EmulatorController.kt
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.test.espresso.device.controller.emulator
import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope
import androidx.test.espresso.device.action.ScreenOrientation
import androidx.test.espresso.device.controller.DeviceControllerOperationException
import androidx.test.espresso.device.controller.DeviceMode
import androidx.test.platform.device.DeviceController
import androidx.test.platform.device.UnsupportedDeviceOperationException
import com.android.emulator.control.EmulatorControllerGrpc
import com.android.emulator.control.ParameterValue
import com.android.emulator.control.PhysicalModelValue
import com.android.emulator.control.PhysicalModelValue.PhysicalType
import com.android.emulator.control.Posture
import com.android.emulator.control.Posture.PostureValue
import io.grpc.StatusRuntimeException
/**
* Implementation of {@link DeviceController} for tests run on an Emulator.
*
* @hide
*/
@RestrictTo(Scope.LIBRARY)
class EmulatorController
constructor(
private val emulatorControllerStub: EmulatorControllerGrpc.EmulatorControllerBlockingStub
) : DeviceController {
companion object {
private val TAG = EmulatorController::class.java.simpleName
private val DEGREES_TO_ROTATE_LANDSCAPE_TO_PORTRAIT = -45F
private val DEGREES_TO_ROTATE_PORTRAIT_TO_LANDSCAPE = 90F
}
override fun setDeviceMode(deviceMode: Int) {
if (
!(deviceMode == DeviceMode.FLAT.mode ||
deviceMode == DeviceMode.TABLETOP.mode ||
deviceMode == DeviceMode.BOOK.mode ||
deviceMode == DeviceMode.CLOSED.mode)
) {
throw UnsupportedDeviceOperationException(
"The provided device mode is not supported on this device."
)
}
val postureValue: PostureValue =
if (deviceMode == DeviceMode.FLAT.mode) {
PostureValue.POSTURE_OPENED
} else if (deviceMode == DeviceMode.CLOSED.mode) {
PostureValue.POSTURE_CLOSED
} else {
PostureValue.POSTURE_HALF_OPENED
}
val posture: Posture = Posture.newBuilder().setValue(postureValue).build()
try {
emulatorControllerStub.setPosture(posture)
} catch (e: StatusRuntimeException) {
throw DeviceControllerOperationException(
"Failed to set device mode. Please make sure the connected Emulator is foldable.",
e
)
}
}
override fun setScreenOrientation(orientation: Int) {
val degreesToRotate =
if (orientation == ScreenOrientation.LANDSCAPE.orientation) {
DEGREES_TO_ROTATE_PORTRAIT_TO_LANDSCAPE
} else {
DEGREES_TO_ROTATE_LANDSCAPE_TO_PORTRAIT
}
val parameters =
ParameterValue.newBuilder().addData(0F).addData(0F).addData(degreesToRotate).build()
try {
emulatorControllerStub.setPhysicalModel(
PhysicalModelValue.newBuilder()
.setTarget(PhysicalModelValue.PhysicalType.ROTATION)
.setValue(parameters)
.build()
)
} catch (e: StatusRuntimeException) {
throw DeviceControllerOperationException(
"Failed to set screen orientation. Status: ${e.getStatus()}.",
e
)
}
}
}