Fix external camera sensor privacy tests
The following tests fail when an external camera is attached while
running the tests:
- testOpStartsRunningAfterStartedWithSensoryPrivacyEnabled
- testOpGetsRecordedAfterStartedWithSensorPrivacyEnabled
The cause is that CameraService will disconnect clients if sensor privacy
is enabled and camera mute is not supported (external cameras): ag/15371897
Test: atest CtsSensorPrivacyTestCases
Bug: 193550085
Change-Id: Iac5c80fd1607f8d70bd8f9c709b853830a1df90a
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
index fa72f6f..ba673f0 100644
--- a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
@@ -68,6 +68,8 @@
"android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY"
const val DELAYED_ACTIVITY_NEW_TASK_EXTRA =
"android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY_NEW_TASK"
+ const val RETRY_CAM_EXTRA =
+ "android.sensorprivacy.cts.usemiccamera.extra.RETRY_CAM_EXTRA"
const val PKG_NAME = "android.sensorprivacy.cts.usemiccamera"
const val RECORDING_FILE_NAME = "${PKG_NAME}_record.mp4"
const val ACTIVITY_TITLE_SNIP = "CtsUseMic"
@@ -241,7 +243,9 @@
fun testOpStartsRunningAfterStartedWithSensoryPrivacyEnabled() {
checkCameraPresentIfNeeded()
setSensor(true)
- startTestApp()
+ // Retry camera connection because external cameras are disconnected
+ // if sensor privacy is enabled (b/182204067)
+ startTestApp(true)
UiAutomatorUtils.waitFindObject(By.text(
Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click()
assertOpRunning(false)
@@ -256,7 +260,9 @@
fun testOpGetsRecordedAfterStartedWithSensorPrivacyEnabled() {
checkCameraPresentIfNeeded()
setSensor(true)
- startTestApp()
+ // Retry camera connection because external cameras are disconnected
+ // if sensor privacy is enabled (b/182204067)
+ startTestApp(true)
UiAutomatorUtils.waitFindObject(By.text(
Pattern.compile("Cancel", Pattern.CASE_INSENSITIVE))).click()
val before = System.currentTimeMillis()
@@ -332,12 +338,17 @@
}
private fun startTestApp() {
+ startTestApp(false)
+ }
+
+ private fun startTestApp(retryCameraOnError: Boolean) {
val intent = Intent(MIC_CAM_ACTIVITY_ACTION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL)
for (extra in extras) {
intent.putExtra(extra, true)
}
+ intent.putExtra(RETRY_CAM_EXTRA, retryCameraOnError)
context.startActivity(intent)
// Wait for app to open
UiAutomatorUtils.waitFindObject(By.textContains(ACTIVITY_TITLE_SNIP))
diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
index 7281cad..0177c64 100644
--- a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
+++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
@@ -35,6 +35,7 @@
import android.os.Bundle
import android.os.Handler
import android.os.Process
+import android.util.Log
import android.util.Size
private const val MIC = 1 shl 0
@@ -42,10 +43,15 @@
private const val SAMPLING_RATE = 8000
+private const val RETRY_TIMEOUT = 5000L
+private const val TAG = "UseMicCamera"
+
class UseMicCamera : Activity() {
private var audioRecord: AudioRecord? = null
private var cameraDevice: CameraDevice? = null
private lateinit var appOpsManager: AppOpsManager
+ private var cameraOpenRetryCount: Int = 0
+ private var cameraMaxOpenRetry: Int = 0
companion object {
const val MIC_CAM_ACTIVITY_ACTION =
@@ -60,6 +66,8 @@
"android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY"
const val DELAYED_ACTIVITY_NEW_TASK_EXTRA =
"android.sensorprivacy.cts.usemiccamera.extra.DELAYED_ACTIVITY_NEW_TASK"
+ const val RETRY_CAM_EXTRA =
+ "android.sensorprivacy.cts.usemiccamera.extra.RETRY_CAM_EXTRA"
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -125,6 +133,15 @@
val outputSize: Size = config!!.getOutputSizes(outputFormat)[0]
val handler = Handler(mainLooper)
+ // Retry camera connection because external cameras are disconnected
+ // if sensor privacy is enabled (b/182204067)
+ val isExternalCamera = (cameraManager!!.getCameraCharacteristics(cameraId)
+ .get(CameraCharacteristics.LENS_FACING)
+ == CameraCharacteristics.LENS_FACING_EXTERNAL)
+ if (intent.getBooleanExtra(RETRY_CAM_EXTRA, false) && isExternalCamera) {
+ cameraMaxOpenRetry = 1
+ }
+
val cameraDeviceCallback = object : CameraDevice.StateCallback() {
override fun onOpened(cD: CameraDevice) {
val imageReader = ImageReader.newInstance(
@@ -149,14 +166,26 @@
cD.createCaptureSession(sessionConfiguration)
cameraDevice = cD
+ cameraOpenRetryCount = 0
}
override fun onDisconnected(cameraDevice: CameraDevice) {
}
override fun onError(cameraDevice: CameraDevice, i: Int) {
+ // Retry once after timeout if cause is ERROR_CAMERA_DISABLED because it may
+ // be triggered if camera mute is not supported and sensor privacy is enabled
+ if (i == ERROR_CAMERA_DISABLED && cameraOpenRetryCount < cameraMaxOpenRetry) {
+ cameraDevice.close()
+ cameraOpenRetryCount++
+ handler.postDelayed({ openCam() }, RETRY_TIMEOUT)
+ }
}
}
- cameraManager!!.openCamera(cameraId, mainExecutor, cameraDeviceCallback)
+ try {
+ cameraManager!!.openCamera(cameraId, mainExecutor, cameraDeviceCallback)
+ } catch (e: android.hardware.camera2.CameraAccessException) {
+ Log.e(TAG, "openCamera: " + e)
+ }
}
-}
\ No newline at end of file
+}