Merge "Refactor Camera2CameraImplTest" into snap-temp-L73200000960618118
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
index 00153de..e1e750d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
@@ -16,6 +16,9 @@
 
 package androidx.camera.camera2.internal;
 
+import static androidx.camera.core.CameraSelector.DEFAULT_BACK_CAMERA;
+
+import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.TestCase.assertTrue;
@@ -28,6 +31,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.internal.verification.VerificationModeFactory.times;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraDevice;
@@ -51,7 +57,6 @@
 import androidx.camera.core.CameraControl;
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.ImageCapture;
-import androidx.camera.core.InitializationException;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.impl.CameraCaptureCallback;
 import androidx.camera.core.impl.CameraCaptureResult;
@@ -90,10 +95,10 @@
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -114,7 +119,16 @@
     private static final int DEFAULT_LENS_FACING = CameraSelector.LENS_FACING_BACK;
     // For the purpose of this test, always say we have 1 camera available.
     private static final int DEFAULT_AVAILABLE_CAMERA_COUNT = 1;
-    private static final Set<CameraInternal.State> STABLE_STATES = new HashSet<>(Arrays.asList(
+    private static final int DEFAULT_TEMPLATE_TYPE = CameraDevice.TEMPLATE_PREVIEW;
+    private static final Map<Integer, Boolean> DEFAULT_TEMPLATE_TO_ZSL_DISABLED = new HashMap<>();
+
+    static {
+        DEFAULT_TEMPLATE_TO_ZSL_DISABLED.put(CameraDevice.TEMPLATE_PREVIEW, false);
+        DEFAULT_TEMPLATE_TO_ZSL_DISABLED.put(CameraDevice.TEMPLATE_RECORD, true);
+        DEFAULT_TEMPLATE_TO_ZSL_DISABLED.put(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG, false);
+    }
+
+    private static final Set<CameraInternal.State> STABLE_STATES = new HashSet<>(asList(
             CameraInternal.State.CLOSED,
             CameraInternal.State.OPEN,
             CameraInternal.State.RELEASED));
@@ -126,7 +140,7 @@
             new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
     );
 
-    private ArrayList<FakeUseCase> mFakeUseCases = new ArrayList<>();
+    private final ArrayList<FakeUseCase> mFakeUseCases = new ArrayList<>();
     private Camera2CameraImpl mCamera2CameraImpl;
     private static HandlerThread sCameraHandlerThread;
     private static Handler sCameraHandler;
@@ -138,7 +152,7 @@
     SemaphoreReleasingCamera2Callbacks.SessionStateCallback mSessionStateCallback;
 
     @BeforeClass
-    public static void classSetup() throws InitializationException {
+    public static void classSetup() {
         sCameraHandlerThread = new HandlerThread("cameraThread");
         sCameraHandlerThread.start();
         sCameraHandler = HandlerCompat.createAsync(sCameraHandlerThread.getLooper());
@@ -194,11 +208,11 @@
         mCamera2CameraImpl.open();
 
         UseCase useCase = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase));
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase));
         mCamera2CameraImpl.release();
     }
 
@@ -215,21 +229,21 @@
     @Test
     public void attachAndActiveUseCase() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         mCamera2CameraImpl.onUseCaseActive(useCase1);
 
         verify(mMockOnImageAvailableListener, timeout(4000).atLeastOnce())
                 .onImageAvailable(any(ImageReader.class));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
     public void detachUseCase() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
         mCamera2CameraImpl.onUseCaseActive(useCase1);
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
@@ -241,8 +255,8 @@
     @Test
     public void unopenedCamera() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
     }
@@ -250,8 +264,8 @@
     @Test
     public void closedCamera() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
     }
@@ -263,12 +277,12 @@
         mCamera2CameraImpl.release();
         mCamera2CameraImpl.open();
 
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         mCamera2CameraImpl.onUseCaseActive(useCase1);
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
@@ -277,54 +291,54 @@
         mCamera2CameraImpl.open();
         mCamera2CameraImpl.release();
 
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         mCamera2CameraImpl.onUseCaseActive(useCase1);
 
         verify(mMockOnImageAvailableListener, never()).onImageAvailable(any(ImageReader.class));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
     public void attach_oneUseCase_isAttached() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
 
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
     public void attach_sameUseCases_staysAttached() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         boolean attachedAfterFirstAdd = mCamera2CameraImpl.isUseCaseAttached(useCase1);
 
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
 
         assertThat(attachedAfterFirstAdd).isTrue();
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
     public void attach_twoUseCases_bothBecomeAttached() {
         UseCase useCase1 = createUseCase();
         UseCase useCase2 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isTrue();
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase2)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.detachUseCases(asList(useCase1, useCase2));
     }
 
     @Test
     public void detach_detachedUseCase_staysDetached() {
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isFalse();
     }
@@ -333,34 +347,34 @@
     public void detachOneAttachedUseCase_fromAttachedUseCases_onlyDetachedSingleUseCase() {
         UseCase useCase1 = createUseCase();
         UseCase useCase2 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
         boolean useCase1isAttachedAfterFirstAdd = mCamera2CameraImpl.isUseCaseAttached(useCase1);
         boolean useCase2isAttachedAfterFirstAdd = mCamera2CameraImpl.isUseCaseAttached(useCase2);
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         assertThat(useCase1isAttachedAfterFirstAdd).isTrue();
         assertThat(useCase2isAttachedAfterFirstAdd).isTrue();
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isFalse();
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase2)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase2));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase2));
     }
 
     @Test
     public void detachSameAttachedUseCaseTwice_onlyDetachesSameUseCase() {
         UseCase useCase1 = createUseCase();
         UseCase useCase2 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase1)).isFalse();
         assertThat(mCamera2CameraImpl.isUseCaseAttached(useCase2)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase2));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase2));
     }
 
     @Test
@@ -369,7 +383,7 @@
         blockHandler();
 
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         DeferrableSurface surface1 = useCase1.getSessionConfig().getSurfaces().get(0);
 
         unblockHandler();
@@ -385,13 +399,13 @@
 
         assertThat(surface1).isNotEqualTo(surface2);
 
-        // Old surface is decremented when CameraCaptueSession is closed by new
+        // Old surface is decremented when CameraCaptureSession is closed by new
         // CameraCaptureSession.
         assertThat(surface1.getUseCount()).isEqualTo(0);
-        // New surface is decremented when CameraCaptueSession is closed by
+        // New surface is decremented when CameraCaptureSession is closed by
         // mCamera2CameraImpl.release()
         assertThat(surface2.getUseCount()).isEqualTo(0);
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
@@ -402,7 +416,7 @@
         blockHandler();
 
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
 
         CameraCaptureCallback captureCallback = mock(CameraCaptureCallback.class);
         CaptureConfig.Builder captureConfigBuilder = new CaptureConfig.Builder();
@@ -411,12 +425,12 @@
         captureConfigBuilder.addCameraCaptureCallback(captureCallback);
 
         mCamera2CameraImpl.getCameraControlInternal().submitStillCaptureRequests(
-                Arrays.asList(captureConfigBuilder.build()),
+                singletonList(captureConfigBuilder.build()),
                 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY,
                 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH);
 
         UseCase useCase2 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase2));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase2));
 
         // Unblock camera handler to make camera operation run quickly .
         // To make the single request not able to run in 1st capture session.  and verify if it can
@@ -428,7 +442,7 @@
         verify(captureCallback, timeout(3000).times(1))
                 .onCaptureCompleted(any(CameraCaptureResult.class));
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.detachUseCases(asList(useCase1, useCase2));
     }
 
     @Test
@@ -441,19 +455,19 @@
         UseCase useCase1 = createUseCase();
         UseCase useCase2 = createUseCase();
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
         CameraCaptureCallback captureCallback = mock(CameraCaptureCallback.class);
         CaptureConfig.Builder captureConfigBuilder = new CaptureConfig.Builder();
-        captureConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
+        captureConfigBuilder.setTemplateType(DEFAULT_TEMPLATE_TYPE);
         captureConfigBuilder.addSurface(useCase1.getSessionConfig().getSurfaces().get(0));
         captureConfigBuilder.addCameraCaptureCallback(captureCallback);
 
         mCamera2CameraImpl.getCameraControlInternal().submitStillCaptureRequests(
-                Arrays.asList(captureConfigBuilder.build()),
+                singletonList(captureConfigBuilder.build()),
                 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY,
                 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH);
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         // Unblock camera handle to make camera operation run quickly .
         // To make the single request not able to run in 1st capture session.  and verify if it can
@@ -468,7 +482,7 @@
         verify(captureCallback, times(0))
                 .onCaptureCompleted(any(CameraCaptureResult.class));
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase2));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase2));
     }
 
     @Test
@@ -580,18 +594,18 @@
             throws InterruptedException {
         mCamera2CameraImpl.open();
         UseCase useCase1 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         mCamera2CameraImpl.onUseCaseActive(useCase1);
 
         // Wait a little bit for the camera to open.
         assertTrue(mSessionStateCallback.waitForOnConfigured(1));
 
         // Remove the useCase1 and trigger the CaptureSession#close().
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
 
         // Create the secondary use case immediately and open it before the first use case closed.
         UseCase useCase2 = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase2));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase2));
         mCamera2CameraImpl.onUseCaseActive(useCase2);
         // Wait for the secondary capture session is configured.
         assertTrue(mSessionStateCallback.waitForOnConfigured(1));
@@ -599,7 +613,7 @@
         Observable.Observer<CameraInternal.State> mockObserver = mock(Observable.Observer.class);
         mCamera2CameraImpl.getCameraState().addObserver(CameraXExecutors.directExecutor(),
                 mockObserver);
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase2));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase2));
         mCamera2CameraImpl.close();
 
         // Wait for the CLOSED state. If the test fail, the CameraX might in wrong internal state,
@@ -614,27 +628,24 @@
         // Create another use case to keep the camera open.
         UseCase useCaseDummy = createUseCase();
         UseCase useCase = createUseCase();
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase, useCaseDummy));
+        mCamera2CameraImpl.attachUseCases(asList(useCase, useCaseDummy));
         mCamera2CameraImpl.onUseCaseActive(useCase);
 
         // Wait a little bit for the camera to open.
         assertTrue(mSessionStateCallback.waitForOnConfigured(2));
 
         // Remove the useCase and trigger the CaptureSession#close().
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase));
         assertTrue(mSessionStateCallback.waitForOnClosed(2));
     }
 
     // Blocks the camera thread handler.
     private void blockHandler() {
-        sCameraHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mSemaphore.acquire();
-                } catch (InterruptedException e) {
-
-                }
+        sCameraHandler.post(() -> {
+            try {
+                mSemaphore.acquire();
+            } catch (InterruptedException e) {
+                // Do nothing.
             }
         });
     }
@@ -644,21 +655,27 @@
         mSemaphore.release();
     }
 
+    @NonNull
     private UseCase createUseCase() {
-        return createUseCase(CameraDevice.TEMPLATE_PREVIEW, /* isZslDisabled = */false);
+        return createUseCase(DEFAULT_TEMPLATE_TYPE);
     }
 
-    private UseCase createUseCase(int template, boolean isZslDisabled) {
+    @NonNull
+    private UseCase createUseCase(int template) {
+        boolean isZslDisabled = getDefaultZslDisabled(template);
         FakeUseCaseConfig.Builder configBuilder =
                 new FakeUseCaseConfig.Builder().setSessionOptionUnpacker(
                         new Camera2SessionOptionUnpacker()).setTargetName("UseCase")
                         .setZslDisabled(isZslDisabled);
         new Camera2Interop.Extender<>(configBuilder).setSessionStateCallback(mSessionStateCallback);
-        CameraSelector selector =
-                new CameraSelector.Builder().requireLensFacing(
-                        CameraSelector.LENS_FACING_BACK).build();
-        TestUseCase testUseCase = new TestUseCase(template, configBuilder.getUseCaseConfig(),
-                selector, mMockOnImageAvailableListener, mMockRepeatingCaptureCallback);
+        return createUseCase(configBuilder.getUseCaseConfig(), template);
+    }
+
+    @NonNull
+    private UseCase createUseCase(@NonNull FakeUseCaseConfig config, int template) {
+        TestUseCase testUseCase = new TestUseCase(template, config, DEFAULT_BACK_CAMERA,
+                mMockOnImageAvailableListener, mMockRepeatingCaptureCallback);
+
         testUseCase.updateSuggestedResolution(new Size(640, 480));
         mFakeUseCases.add(testUseCase);
         return testUseCase;
@@ -669,8 +686,8 @@
         TestUseCase useCase1 = spy((TestUseCase) createUseCase());
         TestUseCase useCase2 = spy((TestUseCase) createUseCase());
 
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
@@ -680,7 +697,7 @@
         verify(useCase1, times(1)).onStateAttached();
         verify(useCase2, times(1)).onStateAttached();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.detachUseCases(asList(useCase1, useCase2));
     }
 
     @Test
@@ -689,9 +706,9 @@
         TestUseCase useCase2 = spy((TestUseCase) createUseCase());
         TestUseCase useCase3 = spy((TestUseCase) createUseCase());
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1, useCase2));
+        mCamera2CameraImpl.attachUseCases(asList(useCase1, useCase2));
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1, useCase2, useCase3));
+        mCamera2CameraImpl.detachUseCases(asList(useCase1, useCase2, useCase3));
 
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
@@ -706,13 +723,14 @@
     private boolean isCameraControlActive(Camera2CameraControlImpl camera2CameraControlImpl) {
         ListenableFuture<Void> listenableFuture = camera2CameraControlImpl.setZoomRatio(2.0f);
         try {
-            // setZoom() will fail immediately when Cameracontrol is not active.
+            // setZoom() will fail immediately when CameraControl is not active.
             listenableFuture.get(50, TimeUnit.MILLISECONDS);
         } catch (ExecutionException e) {
             if (e.getCause() instanceof CameraControl.OperationCanceledException) {
                 return false;
             }
         } catch (InterruptedException | TimeoutException e) {
+            // Do nothing.
         }
         return true;
     }
@@ -726,12 +744,12 @@
 
         UseCase useCase1 = createUseCase();
 
-        mCamera2CameraImpl.attachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
         assertThat(isCameraControlActive(camera2CameraControlImpl)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Collections.singletonList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
     }
 
     @Test
@@ -740,11 +758,11 @@
                 (Camera2CameraControlImpl) mCamera2CameraImpl.getCameraControlInternal();
         UseCase useCase1 = createUseCase();
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.attachUseCases(singletonList(useCase1));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(isCameraControlActive(camera2CameraControlImpl)).isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(useCase1));
+        mCamera2CameraImpl.detachUseCases(singletonList(useCase1));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
         assertThat(isCameraControlActive(camera2CameraControlImpl)).isFalse();
@@ -752,9 +770,9 @@
 
     @Test
     public void attachUseCaseWithTemplatePreview() throws InterruptedException {
-        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW, /* isZslDisabled = */false);
+        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW);
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(preview));
+        mCamera2CameraImpl.attachUseCases(singletonList(preview));
         mCamera2CameraImpl.onUseCaseActive(preview);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
@@ -769,15 +787,15 @@
         assertThat(captureResult.get(CaptureResult.CONTROL_CAPTURE_INTENT))
                 .isEqualTo(CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(preview));
+        mCamera2CameraImpl.detachUseCases(singletonList(preview));
     }
 
     @Test
     public void attachUseCaseWithTemplateRecord() throws InterruptedException {
-        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW, /* isZslDisabled = */false);
-        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD, /* isZslDisabled = */true);
+        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW);
+        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD);
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(preview, record));
+        mCamera2CameraImpl.attachUseCases(asList(preview, record));
         mCamera2CameraImpl.onUseCaseActive(preview);
         mCamera2CameraImpl.onUseCaseActive(record);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
@@ -793,7 +811,7 @@
         assertThat(captureResult.get(CaptureResult.CONTROL_CAPTURE_INTENT))
                 .isEqualTo(CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(preview, record));
+        mCamera2CameraImpl.detachUseCases(asList(preview, record));
     }
 
     @SdkSuppress(minSdkVersion = 23)
@@ -802,14 +820,10 @@
         if (!mCamera2CameraImpl.getCameraInfo().isZslSupported()) {
             return;
         }
-        UseCase preview = createUseCase(
-                CameraDevice.TEMPLATE_PREVIEW,
-                /* isZslDisabled = */false);
-        UseCase zsl = createUseCase(
-                CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
-                /* isZslDisabled = */false);
+        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW);
+        UseCase zsl = createUseCase(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(preview, zsl));
+        mCamera2CameraImpl.attachUseCases(asList(preview, zsl));
         mCamera2CameraImpl.onUseCaseActive(preview);
         mCamera2CameraImpl.onUseCaseActive(zsl);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
@@ -828,7 +842,7 @@
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isFalse();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(preview, zsl));
+        mCamera2CameraImpl.detachUseCases(asList(preview, zsl));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(mCamera2CameraImpl.getCameraControlInternal()
                 .isZslDisabledByByUserCaseConfig()).isFalse();
@@ -840,13 +854,11 @@
         if (!mCamera2CameraImpl.getCameraInfo().isZslSupported()) {
             return;
         }
-        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW, /* isZslDisabled = */
-                false);
-        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD, /* isZslDisabled = */true);
-        UseCase zsl = createUseCase(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
-                /* isZslDisabled = */false);
+        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW);
+        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD);
+        UseCase zsl = createUseCase(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(preview, record, zsl));
+        mCamera2CameraImpl.attachUseCases(asList(preview, record, zsl));
         mCamera2CameraImpl.onUseCaseActive(preview);
         mCamera2CameraImpl.onUseCaseActive(record);
         mCamera2CameraImpl.onUseCaseActive(zsl);
@@ -866,7 +878,7 @@
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(preview, record, zsl));
+        mCamera2CameraImpl.detachUseCases(asList(preview, record, zsl));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
@@ -879,13 +891,11 @@
         if (!mCamera2CameraImpl.getCameraInfo().isZslSupported()) {
             return;
         }
-        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW, /* isZslDisabled = */
-                false);
-        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD, /* isZslDisabled = */true);
-        UseCase zsl = createUseCase(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
-                /* isZslDisabled = */false);
+        UseCase preview = createUseCase(CameraDevice.TEMPLATE_PREVIEW);
+        UseCase record = createUseCase(CameraDevice.TEMPLATE_RECORD);
+        UseCase zsl = createUseCase(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(preview, zsl));
+        mCamera2CameraImpl.attachUseCases(asList(preview, zsl));
         mCamera2CameraImpl.onUseCaseActive(preview);
         mCamera2CameraImpl.onUseCaseActive(zsl);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
@@ -894,7 +904,7 @@
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isFalse();
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(record));
+        mCamera2CameraImpl.attachUseCases(singletonList(record));
         mCamera2CameraImpl.onUseCaseActive(record);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
 
@@ -902,68 +912,46 @@
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(record));
+        mCamera2CameraImpl.detachUseCases(singletonList(record));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isFalse();
 
-        mCamera2CameraImpl.attachUseCases(Arrays.asList(record));
+        mCamera2CameraImpl.attachUseCases(singletonList(record));
         mCamera2CameraImpl.onUseCaseActive(record);
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(zsl));
+        mCamera2CameraImpl.detachUseCases(singletonList(zsl));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(preview));
+        mCamera2CameraImpl.detachUseCases(singletonList(preview));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isTrue();
 
-        mCamera2CameraImpl.detachUseCases(Arrays.asList(record));
+        mCamera2CameraImpl.detachUseCases(singletonList(record));
         HandlerUtil.waitForLooperToIdle(sCameraHandler);
         assertThat(
                 mCamera2CameraImpl.getCameraControlInternal().isZslDisabledByByUserCaseConfig())
                 .isFalse();
     }
 
-    private DeferrableSurface getUseCaseSurface(UseCase useCase) {
-        return useCase.getSessionConfig().getSurfaces().get(0);
-    }
-
     private void changeUseCaseSurface(UseCase useCase) {
         useCase.updateSuggestedResolution(new Size(640, 480));
     }
 
-    private void waitForCameraClose(Camera2CameraImpl camera2CameraImpl)
-            throws InterruptedException {
-        Semaphore semaphore = new Semaphore(0);
-
-        Observable.Observer<CameraInternal.State> observer =
-                new Observable.Observer<CameraInternal.State>() {
-                    @Override
-                    public void onNewData(@Nullable CameraInternal.State value) {
-                        // Ignore any transient states.
-                        if (value == CameraInternal.State.CLOSED) {
-                            semaphore.release();
-                        }
-                    }
-
-                    @Override
-                    public void onError(@NonNull Throwable t) { /* Ignore any transient errors. */ }
-                };
-
-        camera2CameraImpl.getCameraState().addObserver(CameraXExecutors.directExecutor(), observer);
-
-        // Wait until camera reaches closed state
-        semaphore.acquire();
+    private static boolean getDefaultZslDisabled(int templateType) {
+        Boolean isZslDisabled = DEFAULT_TEMPLATE_TO_ZSL_DISABLED.get(templateType);
+        checkState(isZslDisabled != null, "No default mapping from template to zsl disabled");
+        return isZslDisabled;
     }
 
     public static class TestUseCase extends FakeUseCase {
@@ -971,7 +959,6 @@
         HandlerThread mHandlerThread = new HandlerThread("HandlerThread");
         Handler mHandler;
         FakeUseCaseConfig mConfig;
-        private String mCameraId;
         private DeferrableSurface mDeferrableSurface;
         private final CameraCaptureCallback mRepeatingCaptureCallback;
         private final int mTemplate;
@@ -991,12 +978,15 @@
             mRepeatingCaptureCallback = repeatingCaptureCallback;
             mHandlerThread.start();
             mHandler = new Handler(mHandlerThread.getLooper());
-            Integer lensFacing =
+            int lensFacing =
                     cameraSelector.getLensFacing() == null ? CameraSelector.LENS_FACING_BACK :
                             cameraSelector.getLensFacing();
-            mCameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing);
-            onAttach(new FakeCamera(mCameraId, null,
-                            new FakeCameraInfoInternal(mCameraId, 0, lensFacing)),
+            String cameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing);
+            if (cameraId == null) {
+                cameraId = "FakeId";
+            }
+            onAttach(new FakeCamera(cameraId, null,
+                            new FakeCameraInfoInternal(cameraId, 0, lensFacing)),
                     null, null);
             updateSuggestedResolution(new Size(640, 480));
         }