Merge "[Dual Camera v2] Implement on camera-pipe" into androidx-main
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
index 70dba7c..e9e6568 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
@@ -174,6 +174,11 @@
 
     override var runningUseCases = useCases.toSet()
 
+    override var isPrimary: Boolean = true
+        set(value) {
+            field = value
+        }
+
     override fun <T> setParameterAsync(
         key: CaptureRequest.Key<T>,
         value: T,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
index ad25703..68435e2 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
@@ -57,7 +57,6 @@
         CameraConfigs.defaultConfig()
     private val debugId = cameraAdapterIds.incrementAndGet()
     private var sessionProcessor: SessionProcessor? = null
-    private var isPrimary = true
 
     init {
         debug { "Created $this for $cameraId" }
@@ -85,7 +84,7 @@
     }
 
     override fun setPrimary(isPrimary: Boolean) {
-        this.isPrimary = isPrimary
+        useCaseManager.setPrimary(isPrimary)
     }
 
     override fun setActiveResumingMode(enabled: Boolean) {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
index 43e1835..6bd2e52 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
@@ -22,6 +22,7 @@
 import androidx.camera.camera2.pipe.OutputStream
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.core.Log.debug
+import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter.Companion.getSessionConfig
 import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
 import androidx.camera.camera2.pipe.integration.impl.STREAM_USE_HINT_OPTION
 import androidx.camera.camera2.pipe.integration.internal.StreamUseCaseUtil
@@ -44,26 +45,27 @@
 class SessionConfigAdapter(
     private val useCases: Collection<UseCase>,
     private val sessionProcessorConfig: SessionConfig? = null,
+    private val isPrimary: Boolean = true,
 ) {
     val isSessionProcessorEnabled = sessionProcessorConfig != null
     val surfaceToStreamUseCaseMap: Map<DeferrableSurface, Long> by lazy {
         val sessionConfigs = mutableListOf<SessionConfig>()
         val useCaseConfigs = mutableListOf<UseCaseConfig<*>>()
         for (useCase in useCases) {
-            sessionConfigs.add(useCase.sessionConfig)
+            sessionConfigs.add(useCase.getSessionConfig(isPrimary))
             useCaseConfigs.add(useCase.currentConfig)
         }
         getSurfaceToStreamUseCaseMapping(sessionConfigs, useCaseConfigs)
     }
     val surfaceToStreamUseHintMap: Map<DeferrableSurface, Long> by lazy {
-        val sessionConfigs = useCases.map { it.sessionConfig }
+        val sessionConfigs = useCases.map { it.getSessionConfig(isPrimary) }
         getSurfaceToStreamUseHintMapping(sessionConfigs)
     }
     private val validatingBuilder: SessionConfig.ValidatingBuilder by lazy {
         val validatingBuilder = SessionConfig.ValidatingBuilder()
 
         for (useCase in useCases) {
-            validatingBuilder.add(useCase.sessionConfig)
+            validatingBuilder.add(useCase.getSessionConfig(isPrimary))
         }
 
         if (sessionProcessorConfig != null) {
@@ -102,7 +104,8 @@
         val sessionConfig =
             useCases
                 .firstOrNull { useCase ->
-                    useCase.sessionConfig.surfaces.contains(deferrableSurface)
+                    val sessionConfig = useCase.getSessionConfig(isPrimary)
+                    sessionConfig.surfaces.contains(deferrableSurface)
                 }
                 ?.sessionConfig
 
@@ -195,5 +198,9 @@
         fun SessionConfig.toCamera2ImplConfig(): Camera2ImplConfig {
             return Camera2ImplConfig(implementationOptions)
         }
+
+        fun UseCase.getSessionConfig(isPrimary: Boolean): SessionConfig {
+            return if (isPrimary) sessionConfig else secondarySessionConfig
+        }
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
index e0cb40c..e60f9ba 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
@@ -51,6 +51,8 @@
     // UseCases
     var runningUseCases: Set<UseCase>
 
+    var isPrimary: Boolean
+
     interface RunningUseCasesChangeListener {
         /** Invoked when value of [UseCaseCamera.runningUseCases] has been changed. */
         fun onRunningUseCasesChanged()
@@ -101,7 +103,7 @@
 
             // Note: This may be called with the same set of values that was previously set. This
             // is used as a signal to indicate the properties of the UseCase may have changed.
-            SessionConfigAdapter(value).getValidSessionConfigOrNull()?.let {
+            SessionConfigAdapter(value, isPrimary = isPrimary).getValidSessionConfigOrNull()?.let {
                 requestControl.setSessionConfigAsync(it)
             }
                 ?: run {
@@ -118,6 +120,11 @@
             }
         }
 
+    override var isPrimary: Boolean = true
+        set(value) {
+            field = value
+        }
+
     init {
         debug { "Configured $this for $useCases" }
         useCaseGraphConfig.apply { cameraStateAdapter.onGraphUpdated(graph) }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index aaefadf..b832f7b 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -153,6 +153,8 @@
 
     @GuardedBy("lock") private var pendingSessionProcessorInitialization = false
 
+    @GuardedBy("lock") private var isPrimary = true
+
     @GuardedBy("lock")
     private val pendingUseCasesToNotifyCameraControlReady = mutableSetOf<UseCase>()
 
@@ -314,6 +316,10 @@
             }
         }
 
+    fun setPrimary(isPrimary: Boolean) {
+        synchronized(lock) { this.isPrimary = isPrimary }
+    }
+
     fun setActiveResumeMode(enabled: Boolean) =
         synchronized(lock) {
             activeResumeEnabled = enabled
@@ -347,7 +353,10 @@
         when {
             shouldAddRepeatingUseCase(runningUseCases) -> addRepeatingUseCase()
             shouldRemoveRepeatingUseCase(runningUseCases) -> removeRepeatingUseCase()
-            else -> camera?.runningUseCases = runningUseCases
+            else -> {
+                camera?.isPrimary = isPrimary
+                camera?.runningUseCases = runningUseCases
+            }
         }
     }
 
@@ -436,7 +445,7 @@
                     }
             return
         } else {
-            val sessionConfigAdapter = SessionConfigAdapter(useCases)
+            val sessionConfigAdapter = SessionConfigAdapter(useCases, isPrimary = isPrimary)
             val streamConfigMap = mutableMapOf<CameraStream.Config, DeferrableSurface>()
             val graphConfig = createCameraGraphConfig(sessionConfigAdapter, streamConfigMap)
 
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index b5bcfe9..fce6cf6 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -1552,6 +1552,11 @@
             override val requestControl: UseCaseCameraRequestControl
                 get() = fakeRequestControl
 
+            override var isPrimary: Boolean = true
+                set(value) {
+                    field = value
+                }
+
             override fun <T> setParameterAsync(
                 key: CaptureRequest.Key<T>,
                 value: T,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index c7eb629..312045f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -237,6 +237,11 @@
     override var requestControl: UseCaseCameraRequestControl = FakeUseCaseCameraRequestControl(),
 ) : UseCaseCamera {
 
+    override var isPrimary: Boolean = true
+        set(value) {
+            field = value
+        }
+
     override fun <T> setParameterAsync(
         key: CaptureRequest.Key<T>,
         value: T,
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/ConcurrentCameraActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/ConcurrentCameraActivity.java
index 9a3ec50..5a005f3 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/ConcurrentCameraActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/ConcurrentCameraActivity.java
@@ -154,7 +154,7 @@
     private boolean mIsFrontPrimary = true;
     private boolean mIsDualSelfieEnabled = false;
     private boolean mIsDualRecordEnabled = false;
-    private boolean mIsCameraPipeEnabled = false;
+    private boolean mIsCameraPipeEnabled = true;
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {