[go: nahoru, domu]

Add/Remove MeteringRepeating in Camera2CameraImpl

The 2nd chain CL is about checking codes to add or remove MeteringRepeating
in Camera2CameraImpl.java and add related tests in ImageCaptureTest and
Camera2ImplCameraXTest.

Bug: 145326998
Test: Test: ./gradlew bOS && ./gradlew camera:camera-*:connectedCheck
Change-Id: I177820832ae13c8f5b0120c5eb02311302f0104b
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index 7021fe5..9fd682d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -303,6 +303,26 @@
     }
 
     @Test
+    public void canCaptureMultipleImagesWithMaxQualityNoRepeating() {
+        ImageCapture useCase = new ImageCapture.Builder()
+                .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
+                .build();
+        mInstrumentation.runOnMainSync(
+                () -> {
+                    CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
+                    mLifecycleOwner.startAndResume();
+                });
+
+        OnImageCapturedCallback callback = createMockOnImageCapturedCallback(null);
+        int numImages = 5;
+        for (int i = 0; i < numImages; ++i) {
+            useCase.takePicture(mMainExecutor, callback);
+        }
+
+        verify(callback, timeout(10000).times(numImages)).onCaptureSuccess(any(ImageProxy.class));
+    }
+
+    @Test
     public void saveCanSucceed() throws IOException {
         ImageCapture useCase = mDefaultBuilder.build();
         mInstrumentation.runOnMainSync(
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
index 2098c32..adf56c7 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
@@ -627,4 +627,39 @@
         assertThat(((CameraInternal) camera).getCameraInfoInternal().getCameraId()).isEqualTo(
                 CameraUtil.getCameraIdWithLensFacing(DEFAULT_LENS_FACING));
     }
+
+    @Test
+    public void sequentialBindUnbindUseCases_closeCamera() throws InterruptedException {
+        ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build();
+
+        ImageCapture.Builder builder1 = new ImageCapture.Builder()
+                .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY);
+        new Camera2Interop.Extender<>(builder1).setDeviceStateCallback(mDeviceStateCallback);
+        ImageCapture imageCapture = builder1.build();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mLifecycle.startAndResume();
+                // Bind ImageCapture only
+                CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, imageCapture);
+
+                // Then bind another ImageAnalysis
+                CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, imageAnalysis);
+            }
+        });
+
+        verify(mDeviceStateCallback, timeout(3000)).onOpened(any(CameraDevice.class));
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                CameraX.unbind(imageCapture);
+                CameraX.unbind(imageAnalysis);
+            }
+        });
+
+        verify(mDeviceStateCallback, timeout(3000)).onClosed(any(CameraDevice.class));
+    }
+
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index d52a5a4..2b4b65b 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -63,6 +63,7 @@
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -160,6 +161,9 @@
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     final Set<CaptureSession> mConfiguringForClose = new HashSet<>();
 
+    // The metering repeating use case for ImageCapture only case.
+    private MeteringRepeating mMeteringRepeating;
+
     /**
      * Constructor for a camera.
      *
@@ -652,6 +656,7 @@
                 //  where an unbound UseCase is silently ignored.
                 try {
                     mUseCaseAttachState.setUseCaseOnline(useCase);
+
                     useCasesChangedToOnline.add(useCase);
                 } catch (NullPointerException e) {
                     debugLog("Failed to set already detached use case online");
@@ -667,6 +672,9 @@
 
         notifyStateOnlineToUseCases(useCasesChangedToOnline);
 
+        // Check if need to add or remove MeetingRepeatingUseCase.
+        addOrRemoveMeteringRepeatingUseCase();
+
         updateCaptureSessionConfig();
         resetCaptureSession(/*abortInFlightCaptures=*/false);
 
@@ -750,6 +758,9 @@
 
         notifyStateOfflineToUseCases(useCasesChangedToOffline);
 
+        // Check if need to add or remove MeetingRepeatingUseCase.
+        addOrRemoveMeteringRepeatingUseCase();
+
         boolean allUseCasesOffline = mUseCaseAttachState.getOnlineUseCases().isEmpty();
         if (allUseCasesOffline) {
             mCameraControlInternal.setActive(false);
@@ -768,6 +779,55 @@
         }
     }
 
+    // Check if it need the repeating surface for ImageCapture only use case.
+    private void addOrRemoveMeteringRepeatingUseCase() {
+        ValidatingBuilder validatingBuilder = mUseCaseAttachState.getOnlineBuilder();
+        SessionConfig sessionConfig = validatingBuilder.build();
+        CaptureConfig captureConfig = sessionConfig.getRepeatingCaptureConfig();
+        int sizeRepeatingSurfaces = captureConfig.getSurfaces().size();
+        int sizeSessionSurfaces = sessionConfig.getSurfaces().size();
+
+        if (!sessionConfig.getSurfaces().isEmpty()) {
+            if (captureConfig.getSurfaces().isEmpty()) {
+                // Create the MeteringRepeating UseCase
+                if (mMeteringRepeating == null) {
+                    mMeteringRepeating = new MeteringRepeating(this);
+                }
+                addMeteringRepeating();
+            } else {
+                // There is mMeteringRepeating and online, check to remove it or not.
+                if (sizeSessionSurfaces == 1 && sizeRepeatingSurfaces == 1) {
+                    // The only online use case is MeteringRepeating, directly remove it.
+                    removeMeteringRepeating();
+                } else if (sizeRepeatingSurfaces >= 2) {
+                    // There are other repeating UseCases, remove the MeteringRepeating.
+                    removeMeteringRepeating();
+                } else {
+                    // Other normal cases, do nothing.
+                    Log.d(TAG, "mMeteringRepeating is online, "
+                            + "SessionConfig Surfaces: " + sizeSessionSurfaces + ", "
+                            + "CaptureConfig Surfaces: " + sizeRepeatingSurfaces);
+                }
+            }
+        }
+    }
+
+    private  void removeMeteringRepeating() {
+        if (mMeteringRepeating != null) {
+            mUseCaseAttachState.setUseCaseOffline(mMeteringRepeating);
+            notifyStateOfflineToUseCases(Arrays.asList(mMeteringRepeating));
+            mMeteringRepeating.clear();
+            mMeteringRepeating = null;
+        }
+    }
+
+    private  void addMeteringRepeating() {
+        if (mMeteringRepeating != null) {
+            mUseCaseAttachState.setUseCaseOnline(mMeteringRepeating);
+            notifyStateOnlineToUseCases(Arrays.asList(mMeteringRepeating));
+        }
+    }
+
     /** Returns an interface to retrieve characteristics of the camera. */
     @NonNull
     @Override