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
+}