• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.cts;
18 
19 import static android.hardware.camera2.cts.CameraTestUtils.*;
20 import static com.android.ex.camera2.blocking.BlockingCameraManager.*;
21 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
22 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
23 import static org.mockito.Mockito.*;
24 import static android.hardware.camera2.CaptureRequest.*;
25 
26 import android.content.Context;
27 import android.graphics.SurfaceTexture;
28 import android.graphics.ImageFormat;
29 import android.hardware.camera2.CameraAccessException;
30 import android.hardware.camera2.CameraCaptureSession;
31 import android.hardware.camera2.CameraCharacteristics;
32 import android.hardware.camera2.CameraDevice;
33 import android.hardware.camera2.CameraDevice.CameraDeviceSetup;
34 import android.hardware.camera2.CameraMetadata;
35 import android.hardware.camera2.CaptureFailure;
36 import android.hardware.camera2.CaptureRequest;
37 import android.hardware.camera2.CaptureResult;
38 import android.hardware.camera2.TotalCaptureResult;
39 import android.hardware.camera2.cts.helpers.StaticMetadata;
40 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
41 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
42 import android.hardware.camera2.params.MeteringRectangle;
43 import android.hardware.camera2.params.InputConfiguration;
44 import android.hardware.camera2.params.OutputConfiguration;
45 import android.hardware.camera2.params.SessionConfiguration;
46 import android.hardware.camera2.params.StreamConfigurationMap;
47 import android.media.ImageReader;
48 import android.os.ConditionVariable;
49 import android.os.Handler;
50 import android.os.SystemClock;
51 import android.util.Log;
52 import android.util.Range;
53 import android.view.Surface;
54 
55 import com.android.ex.camera2.blocking.BlockingSessionCallback;
56 import com.android.ex.camera2.blocking.BlockingStateCallback;
57 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
58 import com.android.ex.camera2.utils.StateWaiter;
59 import com.android.internal.camera.flags.Flags;
60 
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.concurrent.locks.Condition;
64 import java.util.concurrent.locks.Lock;
65 import java.util.concurrent.locks.ReentrantLock;
66 import java.util.List;
67 import java.util.Map;
68 import java.util.HashMap;
69 import android.util.Size;
70 
71 import org.junit.Test;
72 import org.junit.runners.Parameterized;
73 import org.junit.runner.RunWith;
74 import org.mockito.ArgumentMatcher;
75 
76 import java.util.concurrent.Executor;
77 import java.util.concurrent.LinkedBlockingQueue;
78 import java.util.concurrent.TimeUnit;
79 
80 /**
81  * <p>Basic test for CameraDevice APIs.</p>
82  */
83 
84 @RunWith(Parameterized.class)
85 public class CameraDeviceTest extends Camera2AndroidTestCase {
86     private static final String TAG = "CameraDeviceTest";
87     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
88     private static final int ERROR_LISTENER_WAIT_TIMEOUT_MS = 1000;
89     private static final int REPEATING_CAPTURE_EXPECTED_RESULT_COUNT = 5;
90     private static final int MAX_NUM_IMAGES = 5;
91     private static final int MIN_FPS_REQUIRED_FOR_STREAMING = 20;
92     private static final int DEFAULT_POST_RAW_SENSITIVITY_BOOST = 100;
93 
94     private CameraCaptureSession mSession;
95 
96     private BlockingStateCallback mCameraMockListener;
97     private int mLatestDeviceState = STATE_UNINITIALIZED;
98     private BlockingSessionCallback mSessionMockListener;
99     private StateWaiter mSessionWaiter;
100     private int mLatestSessionState = -1; // uninitialized
101 
102     private static int[] sTemplates = new int[] {
103             CameraDevice.TEMPLATE_PREVIEW,
104             CameraDevice.TEMPLATE_RECORD,
105             CameraDevice.TEMPLATE_STILL_CAPTURE,
106             CameraDevice.TEMPLATE_VIDEO_SNAPSHOT,
107     };
108 
109     private static int[] sInvalidTemplates = new int[] {
110             CameraDevice.TEMPLATE_PREVIEW - 1,
111             CameraDevice.TEMPLATE_MANUAL + 1,
112     };
113 
114     @Override
setUp()115     public void setUp() throws Exception {
116         super.setUp();
117         /**
118          * Workaround for mockito and JB-MR2 incompatibility
119          *
120          * Avoid java.lang.IllegalArgumentException: dexcache == null
121          * https://code.google.com/p/dexmaker/issues/detail?id=2
122          */
123         System.setProperty("dexmaker.dexcache", mContext.getCacheDir().toString());
124 
125         /**
126          * Create error listener in context scope, to catch asynchronous device error.
127          * Use spy object here since we want to use the SimpleDeviceListener callback
128          * implementation (spy doesn't stub the functions unless we ask it to do so).
129          */
130         mCameraMockListener = spy(new BlockingStateCallback());
131         /**
132          * Due to the asynchronous nature of camera device error callback, we
133          * have to make sure device doesn't run into error state before. If so,
134          * fail the rest of the tests. This is especially needed when error
135          * callback is fired too late.
136          */
137         verify(mCameraMockListener, never())
138                 .onError(
139                     any(CameraDevice.class),
140                     anyInt());
141         verify(mCameraMockListener, never())
142                 .onDisconnected(
143                     any(CameraDevice.class));
144 
145         mCameraListener = mCameraMockListener;
146     }
147 
148     @Override
tearDown()149     public void tearDown() throws Exception {
150         super.tearDown();
151     }
152 
153     /**
154      * <p>
155      * Test camera capture request preview capture template.
156      * </p>
157      *
158      * <p>
159      * The request template returned by the camera device must include a
160      * necessary set of metadata keys, and their values must be set correctly.
161      * It mainly requires below settings:
162      * </p>
163      * <ul>
164      * <li>All 3A settings are auto.</li>
165      * <li>All sensor settings are not null.</li>
166      * <li>All ISP processing settings should be non-manual, and the camera
167      * device should make sure the stable frame rate is guaranteed for the given
168      * settings.</li>
169      * </ul>
170      */
171     @Test
testCameraDevicePreviewTemplate()172     public void testCameraDevicePreviewTemplate() throws Exception {
173         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
174         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
175             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_PREVIEW);
176         }
177 
178         // TODO: test the frame rate sustainability in preview use case test.
179     }
180 
181     /**
182      * <p>
183      * Test camera capture request still capture template.
184      * </p>
185      *
186      * <p>
187      * The request template returned by the camera device must include a
188      * necessary set of metadata keys, and their values must be set correctly.
189      * It mainly requires below settings:
190      * </p>
191      * <ul>
192      * <li>All 3A settings are auto.</li>
193      * <li>All sensor settings are not null.</li>
194      * <li>All ISP processing settings should be non-manual, and the camera
195      * device should make sure the high quality takes priority to the stable
196      * frame rate for the given settings.</li>
197      * </ul>
198      */
199     @Test
testCameraDeviceStillTemplate()200     public void testCameraDeviceStillTemplate() throws Exception {
201         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
202         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
203             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_STILL_CAPTURE);
204         }
205     }
206 
207     /**
208      * <p>
209      * Test camera capture video recording template.
210      * </p>
211      *
212      * <p>
213      * The request template returned by the camera device must include a
214      * necessary set of metadata keys, and their values must be set correctly.
215      * It has the similar requirement as preview, with one difference:
216      * </p>
217      * <ul>
218      * <li>Frame rate should be stable, for example, wide fps range like [7, 30]
219      * is a bad setting.</li>
220      */
221     @Test
testCameraDeviceRecordingTemplate()222     public void testCameraDeviceRecordingTemplate() throws Exception {
223         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
224         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
225             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_RECORD);
226         }
227 
228         // TODO: test the frame rate sustainability in recording use case test.
229     }
230 
231     /**
232      *<p>Test camera capture video snapshot template.</p>
233      *
234      * <p>The request template returned by the camera device must include a necessary set of
235      * metadata keys, and their values must be set correctly. It has the similar requirement
236      * as recording, with an additional requirement: the settings should maximize image quality
237      * without compromising stable frame rate.</p>
238      */
239     @Test
testCameraDeviceVideoSnapShotTemplate()240     public void testCameraDeviceVideoSnapShotTemplate() throws Exception {
241         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
242         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
243             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
244         }
245 
246         // TODO: test the frame rate sustainability in video snapshot use case test.
247     }
248 
249     /**
250      *<p>Test camera capture request zero shutter lag template.</p>
251      *
252      * <p>The request template returned by the camera device must include a necessary set of
253      * metadata keys, and their values must be set correctly. It has the similar requirement
254      * as preview, with an additional requirement: </p>
255      */
256     @Test
testCameraDeviceZSLTemplate()257     public void testCameraDeviceZSLTemplate() throws Exception {
258         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
259         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
260             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
261         }
262     }
263 
264     /**
265      * <p>
266      * Test camera capture request manual template.
267      * </p>
268      *
269      * <p>
270      * The request template returned by the camera device must include a
271      * necessary set of metadata keys, and their values must be set correctly. It
272      * mainly requires below settings:
273      * </p>
274      * <ul>
275      * <li>All 3A settings are manual.</li>
276      * <li>ISP processing parameters are set to preview quality.</li>
277      * <li>The manual capture parameters (exposure, sensitivity, and so on) are
278      * set to reasonable defaults.</li>
279      * </ul>
280      */
281     @Test
testCameraDeviceManualTemplate()282     public void testCameraDeviceManualTemplate() throws Exception {
283         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
284         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
285             captureTemplateTestByCamera(cameraIdsUnderTest[i], CameraDevice.TEMPLATE_MANUAL);
286         }
287     }
288 
289     @Test
testCameraDeviceCreateCaptureBuilder()290     public void testCameraDeviceCreateCaptureBuilder() throws Exception {
291         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
292         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
293             try {
294                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
295                 /**
296                  * Test: that each template type is supported, and that its required fields are
297                  * present.
298                  */
299                 for (int j = 0; j < sTemplates.length; j++) {
300                     // Skip video snapshots for LEGACY mode
301                     if (mStaticInfo.isHardwareLevelLegacy() &&
302                             sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
303                         continue;
304                     }
305                     // Skip non-PREVIEW templates for non-color output
306                     if (!mStaticInfo.isColorOutputSupported() &&
307                             sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
308                         continue;
309                     }
310                     CaptureRequest.Builder capReq = mCamera.createCaptureRequest(sTemplates[j]);
311                     assertNotNull("Failed to create capture request", capReq);
312                     if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_EXPOSURE_TIME)) {
313                         assertNotNull("Missing field: SENSOR_EXPOSURE_TIME",
314                                 capReq.get(CaptureRequest.SENSOR_EXPOSURE_TIME));
315                     }
316                     if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_SENSITIVITY)) {
317                         assertNotNull("Missing field: SENSOR_SENSITIVITY",
318                                 capReq.get(CaptureRequest.SENSOR_SENSITIVITY));
319                     }
320                     if (mStaticInfo.areKeysAvailable(CaptureRequest.CONTROL_SETTINGS_OVERRIDE)) {
321                         assertNotNull("Settings override key is not set in capture template",
322                                 capReq.get(CaptureRequest.CONTROL_SETTINGS_OVERRIDE));
323                         assertTrue("CONTROL_SETTINGS_OVERRIDE isn't OFF in capture templates",
324                                 capReq.get(CaptureRequest.CONTROL_SETTINGS_OVERRIDE)
325                                 == CameraMetadata.CONTROL_SETTINGS_OVERRIDE_OFF);
326                     }
327                     if (Flags.zoomMethod()) {
328                         if (mStaticInfo.areKeysAvailable(CaptureRequest.CONTROL_ZOOM_METHOD)) {
329                             assertNotNull("CONTROL_ZOOM_METHOD key is not set in capture template",
330                                     capReq.get(CaptureRequest.CONTROL_ZOOM_METHOD));
331                             assertTrue("CONTROL_ZOOM_METHOD isn't AUTO in capture templates",
332                                     capReq.get(CaptureRequest.CONTROL_ZOOM_METHOD)
333                                     == CameraMetadata.CONTROL_ZOOM_METHOD_AUTO);
334                         }
335                     }
336                 }
337 
338                 /**
339                  * Test: creating capture requests with an invalid template ID should throw
340                  * IllegalArgumentException.
341                  */
342                 for (int j = 0; j < sInvalidTemplates.length; j++) {
343                     try {
344                         CaptureRequest.Builder capReq =
345                                 mCamera.createCaptureRequest(sInvalidTemplates[j]);
346                         fail("Should get IllegalArgumentException due to an invalid template ID.");
347                     } catch (IllegalArgumentException e) {
348                         // Expected exception.
349                     }
350                 }
351             }
352             finally {
353                 try {
354                     closeSession();
355                 } finally {
356                     closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
357                 }
358             }
359         }
360     }
361 
362     @Test
testCameraDeviceSetErrorListener()363     public void testCameraDeviceSetErrorListener() throws Exception {
364         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
365         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
366             try {
367                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
368                 /**
369                  * Test: that the error listener can be set without problems.
370                  * Also, wait some time to check if device doesn't run into error.
371                  */
372                 SystemClock.sleep(ERROR_LISTENER_WAIT_TIMEOUT_MS);
373                 verify(mCameraMockListener, never())
374                         .onError(
375                                 any(CameraDevice.class),
376                                 anyInt());
377             }
378             finally {
379                 try {
380                     closeSession();
381                 } finally {
382                     closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
383                 }
384             }
385         }
386     }
387 
388     @Test
testCameraDeviceCapture()389     public void testCameraDeviceCapture() throws Exception {
390         runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false, /*useExecutor*/false);
391         runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false, /*useExecutor*/true);
392     }
393 
394     @Test
testCameraDeviceCaptureBurst()395     public void testCameraDeviceCaptureBurst() throws Exception {
396         runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false, /*useExecutor*/false);
397         runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false, /*useExecutor*/true);
398     }
399 
400     @Test
testCameraDeviceRepeatingRequest()401     public void testCameraDeviceRepeatingRequest() throws Exception {
402         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false, /*useExecutor*/false);
403         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false, /*useExecutor*/true);
404     }
405 
406     @Test
testCameraDeviceRepeatingBurst()407     public void testCameraDeviceRepeatingBurst() throws Exception {
408         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false, /*useExecutor*/ false);
409         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false, /*useExecutor*/ true);
410     }
411 
412     /**
413      * Test {@link android.hardware.camera2.CameraCaptureSession#abortCaptures} API.
414      *
415      * <p>Abort is the fastest way to idle the camera device for reconfiguration with
416      * {@link android.hardware.camera2.CameraCaptureSession#abortCaptures}, at the cost of
417      * discarding in-progress work. Once the abort is complete, the idle callback will be called.
418      * </p>
419      */
420     @Test
testCameraDeviceAbort()421     public void testCameraDeviceAbort() throws Exception {
422         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true, /*useExecutor*/false);
423         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true, /*useExecutor*/true);
424         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true, /*useExecutor*/false);
425         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true, /*useExecutor*/true);
426         /**
427          * TODO: this is only basic test of abort. we probably should also test below cases:
428          *
429          * 1. Performance. Make sure abort is faster than stopRepeating, we can test each one a
430          * couple of times, then compare the average. Also, for abortCaptures() alone, we should
431          * make sure it doesn't take too long time (e.g. <100ms for full devices, <500ms for limited
432          * devices), after the abort, we should be able to get all results back very quickly.  This
433          * can be done in performance test.
434          *
435          * 2. Make sure all in-flight request comes back after abort, e.g. submit a couple of
436          * long exposure single captures, then abort, then check if we can get the pending
437          * request back quickly.
438          *
439          * 3. Also need check onCaptureSequenceCompleted for repeating burst after abortCaptures().
440          */
441     }
442 
443     /**
444      * Test invalid capture (e.g. null or empty capture request).
445      */
446     @Test
testInvalidCapture()447     public void testInvalidCapture() throws Exception {
448         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
449         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
450             try {
451                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
452                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
453 
454                 prepareCapture();
455 
456                 invalidRequestCaptureTestByCamera();
457 
458                 closeSession();
459             }
460             finally {
461                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
462             }
463         }
464     }
465 
466     /**
467      * Test to ensure that we can call camera2 API methods inside callbacks.
468      *
469      * Tests:
470      *  onOpened -> createCaptureSession, createCaptureRequest
471      *  onConfigured -> getDevice, abortCaptures,
472      *     createCaptureRequest, capture, setRepeatingRequest, stopRepeating
473      *  onCaptureCompleted -> createCaptureRequest, getDevice, abortCaptures,
474      *     capture, setRepeatingRequest, stopRepeating, session+device.close
475      */
476     @Test
testChainedOperation()477     public void testChainedOperation() throws Throwable {
478 
479         final ArrayList<Surface> outputs = new ArrayList<>();
480 
481         // A queue for the chained listeners to push results to
482         // A success Throwable indicates no errors; other Throwables detail a test failure;
483         // nulls indicate timeouts.
484         final Throwable success = new Throwable("Success");
485         final LinkedBlockingQueue<Throwable> results = new LinkedBlockingQueue<>();
486 
487         // Define listeners
488         // A cascade of Device->Session->Capture listeners, each of which invokes at least one
489         // method on the camera device or session.
490 
491         class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback {
492             @Override
493             public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
494                     TotalCaptureResult result) {
495                 try {
496                     CaptureRequest.Builder request2 =
497                             session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
498                     request2.addTarget(mReaderSurface);
499 
500                     // Some calls to the camera for coverage
501                     session.abortCaptures();
502                     session.capture(request2.build(),
503                             /*listener*/ null, /*handler*/ null);
504                     session.setRepeatingRequest(request2.build(),
505                             /*listener*/ null, /*handler*/ null);
506                     session.stopRepeating();
507 
508                     CameraDevice camera = session.getDevice();
509                     session.close();
510                     camera.close();
511 
512                     results.offer(success);
513                 } catch (Throwable t) {
514                     results.offer(t);
515                 }
516             }
517 
518             @Override
519             public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
520                     CaptureFailure failure) {
521                 try {
522                     CameraDevice camera = session.getDevice();
523                     session.close();
524                     camera.close();
525                     fail("onCaptureFailed invoked with failure reason: " + failure.getReason());
526                 } catch (Throwable t) {
527                     results.offer(t);
528                 }
529             }
530         }
531 
532         class ChainedSessionListener extends CameraCaptureSession.StateCallback {
533             private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback();
534 
535             @Override
536             public void onConfigured(CameraCaptureSession session) {
537                 try {
538                     CaptureRequest.Builder request =
539                             session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
540                     request.addTarget(mReaderSurface);
541                     // Some calls to the camera for coverage
542                     session.getDevice();
543                     session.abortCaptures();
544                     // The important call for the next level of chaining
545                     session.capture(request.build(), mCaptureCallback, mHandler);
546                     // Some more calls
547                     session.setRepeatingRequest(request.build(),
548                             /*listener*/ null, /*handler*/ null);
549                     session.stopRepeating();
550                     results.offer(success);
551                 } catch (Throwable t) {
552                     results.offer(t);
553                 }
554             }
555 
556             @Override
557             public void onConfigureFailed(CameraCaptureSession session) {
558                 try {
559                     CameraDevice camera = session.getDevice();
560                     session.close();
561                     camera.close();
562                     fail("onConfigureFailed was invoked");
563                 } catch (Throwable t) {
564                     results.offer(t);
565                 }
566             }
567         }
568 
569         class ChainedCameraListener extends CameraDevice.StateCallback {
570             private final ChainedSessionListener mSessionListener = new ChainedSessionListener();
571 
572             public CameraDevice cameraDevice;
573 
574             @Override
575             public void onOpened(CameraDevice camera) {
576 
577                 cameraDevice = camera;
578                 try {
579                     // Some calls for coverage
580                     camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
581                     // The important call for next level of chaining
582                     camera.createCaptureSession(outputs, mSessionListener, mHandler);
583                     results.offer(success);
584                 } catch (Throwable t) {
585                     try {
586                         camera.close();
587                         results.offer(t);
588                     } catch (Throwable t2) {
589                         Log.e(TAG,
590                                 "Second failure reached; discarding first exception with trace " +
591                                 Log.getStackTraceString(t));
592                         results.offer(t2);
593                     }
594                 }
595             }
596 
597             @Override
598             public void onDisconnected(CameraDevice camera) {
599                 try {
600                     camera.close();
601                     fail("onDisconnected invoked");
602                 } catch (Throwable t) {
603                     results.offer(t);
604                 }
605             }
606 
607             @Override
608             public void onError(CameraDevice camera, int error) {
609                 try {
610                     camera.close();
611                     fail("onError invoked with error code: " + error);
612                 } catch (Throwable t) {
613                     results.offer(t);
614                 }
615             }
616         }
617 
618         // Actual test code
619         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
620         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
621             try {
622                 Throwable result;
623 
624                 if (!(new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraIdsUnderTest[i]))).
625                         isColorOutputSupported()) {
626                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
627                             " does not support color outputs, skipping");
628                     continue;
629                 }
630 
631                 createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888,
632                         MAX_NUM_IMAGES, new ImageDropperListener());
633                 outputs.add(mReaderSurface);
634 
635                 // Start chained cascade
636                 ChainedCameraListener cameraListener = new ChainedCameraListener();
637                 mCameraManager.openCamera(cameraIdsUnderTest[i], cameraListener, mHandler);
638 
639                 // Check if open succeeded
640                 result = results.poll(CAMERA_OPEN_TIMEOUT_MS, TimeUnit.MILLISECONDS);
641                 if (result != success) {
642                     if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
643                     if (result == null) {
644                         fail("Timeout waiting for camera open");
645                     } else {
646                         throw result;
647                     }
648                 }
649 
650                 // Check if configure succeeded
651                 result = results.poll(SESSION_CONFIGURE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
652                 if (result != success) {
653                     if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
654                     if (result == null) {
655                         fail("Timeout waiting for session configure");
656                     } else {
657                         throw result;
658                     }
659                 }
660 
661                 // Check if capture succeeded
662                 result = results.poll(CAPTURE_RESULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
663                 if (result != success) {
664                     if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
665                     if (result == null) {
666                         fail("Timeout waiting for capture completion");
667                     } else {
668                         throw result;
669                     }
670                 }
671 
672             } finally {
673                 closeDefaultImageReader();
674                 outputs.clear();
675             }
676         }
677     }
678 
679     /**
680      * Verify basic semantics and error conditions of the prepare call.
681      *
682      */
683     @Test
testPrepare()684     public void testPrepare() throws Exception {
685         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
686         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
687             try {
688                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
689                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
690                             " does not support color outputs, skipping");
691                     continue;
692                 }
693                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
694                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
695 
696                 prepareTestByCamera();
697             }
698             finally {
699                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
700             }
701         }
702     }
703 
704     /**
705      * Verify prepare call behaves properly when sharing surfaces.
706      *
707      */
708     @Test
testPrepareForSharedSurfaces()709     public void testPrepareForSharedSurfaces() throws Exception {
710         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
711         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
712             try {
713                 StaticMetadata staticInfo = mAllStaticInfo.get(cameraIdsUnderTest[i]);
714                 if (staticInfo.isHardwareLevelLegacy()) {
715                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + " is legacy, skipping");
716                     continue;
717                 }
718                 if (!staticInfo.isColorOutputSupported()) {
719                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
720                             " does not support color outputs, skipping");
721                     continue;
722                 }
723                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
724                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
725 
726                 prepareTestForSharedSurfacesByCamera();
727             }
728             finally {
729                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
730             }
731         }
732     }
733 
734     /**
735      * Verify creating sessions back to back.
736      */
737     @Test
testCreateSessions()738     public void testCreateSessions() throws Exception {
739         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
740         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
741             try {
742                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
743                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
744                             " does not support color outputs, skipping");
745                     continue;
746                 }
747                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
748                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
749 
750                 testCreateSessionsByCamera(cameraIdsUnderTest[i]);
751             }
752             finally {
753                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
754             }
755         }
756     }
757 
758     /**
759      * Verify creating a custom session
760      */
761     @Test
testCreateCustomSession()762     public void testCreateCustomSession() throws Exception {
763         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
764         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
765             try {
766                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
767                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
768                             " does not support color outputs, skipping");
769                     continue;
770                 }
771                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
772                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
773 
774                 testCreateCustomSessionByCamera(cameraIdsUnderTest[i]);
775             }
776             finally {
777                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
778             }
779         }
780     }
781 
782     /**
783      * Verify creating a custom mode session works
784      */
testCreateCustomSessionByCamera(String cameraId)785     private void testCreateCustomSessionByCamera(String cameraId) throws Exception {
786         final int SESSION_TIMEOUT_MS = 1000;
787         final int CAPTURE_TIMEOUT_MS = 3000;
788 
789         if (VERBOSE) {
790             Log.v(TAG, "Testing creating custom session for camera " + cameraId);
791         }
792 
793         Size yuvSize = mOrderedPreviewSizes.get(0);
794 
795         // Create a list of image readers. JPEG for last one and YUV for the rest.
796         ImageReader imageReader = ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(),
797                 ImageFormat.YUV_420_888, /*maxImages*/1);
798 
799         try {
800             // Create a normal-mode session via createCustomCaptureSession
801             mSessionMockListener = spy(new BlockingSessionCallback());
802             mSessionWaiter = mSessionMockListener.getStateWaiter();
803             List<OutputConfiguration> outputs = new ArrayList<>();
804             outputs.add(new OutputConfiguration(imageReader.getSurface()));
805             mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs,
806                     CameraDevice.SESSION_OPERATION_MODE_NORMAL, mSessionMockListener, mHandler);
807             mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
808 
809             // Verify we can capture a frame with the session.
810             SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
811             SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
812             imageReader.setOnImageAvailableListener(imageListener, mHandler);
813 
814             CaptureRequest.Builder builder =
815                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
816             builder.addTarget(imageReader.getSurface());
817             CaptureRequest request = builder.build();
818 
819             mSession.capture(request, captureListener, mHandler);
820             captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS);
821             imageListener.getImage(CAPTURE_TIMEOUT_MS).close();
822 
823             // Create a few invalid custom sessions by using undefined non-vendor mode indices, and
824             // check that they fail to configure
825             mSessionMockListener = spy(new BlockingSessionCallback());
826             mSessionWaiter = mSessionMockListener.getStateWaiter();
827             mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs,
828                     CameraDevice.SESSION_OPERATION_MODE_VENDOR_START - 1, mSessionMockListener, mHandler);
829             mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
830             waitForSessionState(BlockingSessionCallback.SESSION_CONFIGURE_FAILED,
831                     SESSION_CONFIGURE_TIMEOUT_MS);
832 
833             mSessionMockListener = spy(new BlockingSessionCallback());
834             mCamera.createCustomCaptureSession(/*inputConfig*/null, outputs,
835                     CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED + 1, mSessionMockListener,
836                     mHandler);
837             mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
838             mSessionWaiter = mSessionMockListener.getStateWaiter();
839             waitForSessionState(BlockingSessionCallback.SESSION_CONFIGURE_FAILED,
840                     SESSION_CONFIGURE_TIMEOUT_MS);
841 
842         } finally {
843             imageReader.close();
844             mSession.close();
845         }
846     }
847 
848     /**
849      * Test session configuration.
850      */
851     @Test
testSessionConfiguration()852     public void testSessionConfiguration() throws Exception {
853         ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration> ();
854         outConfigs.add(new OutputConfiguration(new Size(1, 1), SurfaceTexture.class));
855         outConfigs.add(new OutputConfiguration(new Size(2, 2), SurfaceTexture.class));
856         mSessionMockListener = spy(new BlockingSessionCallback());
857         HandlerExecutor executor = new HandlerExecutor(mHandler);
858         InputConfiguration inputConfig = new InputConfiguration(1, 1, ImageFormat.PRIVATE);
859 
860         SessionConfiguration regularSessionConfig = new SessionConfiguration(
861                 SessionConfiguration.SESSION_REGULAR, outConfigs, executor, mSessionMockListener);
862 
863         SessionConfiguration highspeedSessionConfig = new SessionConfiguration(
864                 SessionConfiguration.SESSION_HIGH_SPEED, outConfigs, executor, mSessionMockListener);
865 
866         assertEquals("Session configuration output doesn't match",
867                 regularSessionConfig.getOutputConfigurations(), outConfigs);
868 
869         assertEquals("Session configuration output doesn't match",
870                 regularSessionConfig.getOutputConfigurations(),
871                 highspeedSessionConfig.getOutputConfigurations());
872 
873         assertEquals("Session configuration callback doesn't match",
874                 regularSessionConfig.getStateCallback(), mSessionMockListener);
875 
876         assertEquals("Session configuration callback doesn't match",
877                 regularSessionConfig.getStateCallback(),
878                 highspeedSessionConfig.getStateCallback());
879 
880         assertEquals("Session configuration executor doesn't match",
881                 regularSessionConfig.getExecutor(), executor);
882 
883         assertEquals("Session configuration handler doesn't match",
884                 regularSessionConfig.getExecutor(), highspeedSessionConfig.getExecutor());
885 
886         regularSessionConfig.setInputConfiguration(inputConfig);
887         assertEquals("Session configuration input doesn't match",
888                 regularSessionConfig.getInputConfiguration(), inputConfig);
889 
890         try {
891             highspeedSessionConfig.setInputConfiguration(inputConfig);
892             fail("No exception for valid input configuration in hight speed session configuration");
893         } catch (UnsupportedOperationException e) {
894             //expected
895         }
896 
897         assertEquals("Session configuration input doesn't match",
898                 highspeedSessionConfig.getInputConfiguration(), null);
899 
900         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
901         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
902             try {
903                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
904                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
905                             " does not support color outputs, skipping");
906                     continue;
907                 }
908                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
909                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
910 
911                 CaptureRequest.Builder builder =
912                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
913                 CaptureRequest request = builder.build();
914 
915                 regularSessionConfig.setSessionParameters(request);
916                 highspeedSessionConfig.setSessionParameters(request);
917 
918                 assertEquals("Session configuration parameters doesn't match",
919                         regularSessionConfig.getSessionParameters(), request);
920 
921                 assertEquals("Session configuration parameters doesn't match",
922                         regularSessionConfig.getSessionParameters(),
923                         highspeedSessionConfig.getSessionParameters());
924             }
925             finally {
926                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
927             }
928         }
929     }
930 
931     /**
932      * Check for any state leakage in case of internal re-configure
933      */
934     @Test
testSessionParametersStateLeak()935     public void testSessionParametersStateLeak() throws Exception {
936         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
937         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
938             try {
939                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
940                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
941                             " does not support color outputs, skipping");
942                     continue;
943                 }
944                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
945                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
946 
947                 testSessionParametersStateLeakByCamera(cameraIdsUnderTest[i]);
948             }
949             finally {
950                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
951             }
952         }
953     }
954 
955     /**
956      * Check for any state leakage in case of internal re-configure
957      */
testSessionParametersStateLeakByCamera(String cameraId)958     private void testSessionParametersStateLeakByCamera(String cameraId)
959             throws Exception {
960         int outputFormat = ImageFormat.YUV_420_888;
961         Size outputSize = mOrderedPreviewSizes.get(0);
962 
963         CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
964         StreamConfigurationMap config = characteristics.get(
965                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
966         List <CaptureRequest.Key<?>> sessionKeys = characteristics.getAvailableSessionKeys();
967         if (sessionKeys == null) {
968             return;
969         }
970 
971         if (config.isOutputSupportedFor(outputFormat)) {
972             outputSize = config.getOutputSizes(outputFormat)[0];
973         } else {
974             return;
975         }
976 
977         ImageReader imageReader = ImageReader.newInstance(outputSize.getWidth(),
978                 outputSize.getHeight(), outputFormat, /*maxImages*/3);
979 
980         class OnReadyCaptureStateCallback extends CameraCaptureSession.StateCallback {
981             private ConditionVariable onReadyTriggeredCond = new ConditionVariable();
982             private boolean onReadyTriggered = false;
983 
984             @Override
985             public void onConfigured(CameraCaptureSession session) {
986             }
987 
988             @Override
989             public void onConfigureFailed(CameraCaptureSession session) {
990             }
991 
992             @Override
993             public synchronized void onReady(CameraCaptureSession session) {
994                 onReadyTriggered = true;
995                 onReadyTriggeredCond.open();
996             }
997 
998             public void waitForOnReady(long timeout) {
999                 synchronized (this) {
1000                     if (onReadyTriggered) {
1001                         onReadyTriggered = false;
1002                         onReadyTriggeredCond.close();
1003                         return;
1004                     }
1005                 }
1006 
1007                 if (onReadyTriggeredCond.block(timeout)) {
1008                     synchronized (this) {
1009                         onReadyTriggered = false;
1010                         onReadyTriggeredCond.close();
1011                     }
1012                 } else {
1013                     throw new TimeoutRuntimeException("Unable to receive onReady after "
1014                         + timeout + "ms");
1015                 }
1016             }
1017         }
1018 
1019         OnReadyCaptureStateCallback sessionListener = new OnReadyCaptureStateCallback();
1020 
1021         try {
1022             mSessionMockListener = spy(new BlockingSessionCallback(sessionListener));
1023             mSessionWaiter = mSessionMockListener.getStateWaiter();
1024             List<OutputConfiguration> outputs = new ArrayList<>();
1025             outputs.add(new OutputConfiguration(imageReader.getSurface()));
1026             SessionConfiguration sessionConfig = new SessionConfiguration(
1027                     SessionConfiguration.SESSION_REGULAR, outputs,
1028                     new HandlerExecutor(mHandler), mSessionMockListener);
1029 
1030             CaptureRequest.Builder builder =
1031                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1032             builder.addTarget(imageReader.getSurface());
1033             CaptureRequest request = builder.build();
1034 
1035             sessionConfig.setSessionParameters(request);
1036             mCamera.createCaptureSession(sessionConfig);
1037 
1038             mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1039             sessionListener.waitForOnReady(SESSION_CONFIGURE_TIMEOUT_MS);
1040 
1041             SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
1042             ImageDropperListener imageListener = new ImageDropperListener();
1043             imageReader.setOnImageAvailableListener(imageListener, mHandler);
1044 
1045             // To check the state leak condition, we need a capture request that has
1046             // at least one session parameter value difference from the initial session
1047             // parameters configured above. Scan all available template types for the
1048             // required delta.
1049             CaptureRequest.Builder requestBuilder = null;
1050             ArrayList<CaptureRequest.Builder> builders = new ArrayList<CaptureRequest.Builder> ();
1051             if (mStaticInfo.isCapabilitySupported(
1052                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1053                 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL));
1054             }
1055             if (mStaticInfo.isCapabilitySupported(
1056                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)
1057                     || mStaticInfo.isCapabilitySupported(
1058                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING)) {
1059                 builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG));
1060             }
1061             builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT));
1062             builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW));
1063             builders.add(mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD));
1064             for (CaptureRequest.Key<?> key : sessionKeys) {
1065                 Object sessionValue = builder.get(key);
1066                 for (CaptureRequest.Builder newBuilder : builders) {
1067                     Object currentValue = newBuilder.get(key);
1068                     if ((sessionValue == null) && (currentValue == null)) {
1069                         continue;
1070                     }
1071 
1072                     if (((sessionValue == null) && (currentValue != null)) ||
1073                             ((sessionValue != null) && (currentValue == null)) ||
1074                             (!sessionValue.equals(currentValue))) {
1075                         requestBuilder = newBuilder;
1076                         break;
1077                     }
1078                 }
1079 
1080                 if (requestBuilder != null) {
1081                     break;
1082                 }
1083             }
1084 
1085             if (requestBuilder != null) {
1086                 requestBuilder.addTarget(imageReader.getSurface());
1087                 request = requestBuilder.build();
1088                 mSession.setRepeatingRequest(request, captureListener, mHandler);
1089                 try {
1090                     sessionListener.waitForOnReady(SESSION_CONFIGURE_TIMEOUT_MS);
1091                     fail("Camera shouldn't switch to ready state when session parameters are " +
1092                             "modified");
1093                 } catch (TimeoutRuntimeException e) {
1094                     //expected
1095                 }
1096             }
1097         } finally {
1098             imageReader.close();
1099             mSession.close();
1100         }
1101     }
1102 
1103     /**
1104      * Verify creating a session with additional parameters.
1105      */
1106     @Test
testCreateSessionWithParameters()1107     public void testCreateSessionWithParameters() throws Exception {
1108         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
1109         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
1110             try {
1111                 if (!mAllStaticInfo.get(cameraIdsUnderTest[i]).isColorOutputSupported()) {
1112                     Log.i(TAG, "Camera " + cameraIdsUnderTest[i] +
1113                             " does not support color outputs, skipping");
1114                     continue;
1115                 }
1116                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
1117                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
1118 
1119                 testCreateSessionWithParametersByCamera(cameraIdsUnderTest[i], /*reprocessable*/false);
1120                 testCreateSessionWithParametersByCamera(cameraIdsUnderTest[i], /*reprocessable*/true);
1121             }
1122             finally {
1123                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
1124             }
1125         }
1126     }
1127 
1128     /**
1129      * Verify creating a session with additional parameters works
1130      */
testCreateSessionWithParametersByCamera(String cameraId, boolean reprocessable)1131     private void testCreateSessionWithParametersByCamera(String cameraId, boolean reprocessable)
1132             throws Exception {
1133         final int CAPTURE_TIMEOUT_MS = 3000;
1134         int inputFormat = ImageFormat.YUV_420_888;
1135         int outputFormat = inputFormat;
1136         Size outputSize = mOrderedPreviewSizes.get(0);
1137         Size inputSize = outputSize;
1138         InputConfiguration inputConfig = null;
1139 
1140         boolean reprocessSupported = mStaticInfo.isCapabilitySupported(
1141                 REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
1142         reprocessSupported |= mStaticInfo.isCapabilitySupported(
1143                 REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
1144         if (reprocessable && !reprocessSupported) {
1145             Log.v(TAG, "Reprocessing not supported for " + cameraId);
1146             return;
1147         }
1148 
1149         if (VERBOSE) {
1150             Log.v(TAG, "Testing creating session with parameters for camera " + cameraId);
1151         }
1152 
1153         CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
1154         StreamConfigurationMap config = characteristics.get(
1155                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1156         List<OutputConfiguration> outputs = new ArrayList<>();
1157         ImageReader reprocessInputReader = null;
1158 
1159         if (reprocessable) {
1160             // Setup the mandatory PRIV/YUV(input) + PRIV/YUV(output) + Jpeg(output) stream
1161             // combination.
1162             int inputFormats[] = config.getInputFormats();
1163             assertNotNull(inputFormats);
1164             assertArrayNotEmpty(inputFormats, "No input formats supported");
1165             inputFormat = inputFormats[0];
1166             int outputFormats[] = config.getValidOutputFormatsForInput(inputFormat);
1167             assertNotNull(outputFormats);
1168             assertTrue(contains(outputFormats, ImageFormat.JPEG));
1169             outputFormat = ImageFormat.JPEG;
1170 
1171             Size inputSizes[] = config.getInputSizes(inputFormat);
1172             Size outputSizes[] = config.getOutputSizes(outputFormat);
1173             assertTrue("No valid sizes supported for input format: " + inputFormat,
1174                     (inputSizes.length > 0));
1175             assertTrue("No valid sizes supported for output format: " + outputFormat,
1176                     (outputSizes.length > 0));
1177 
1178             inputSize = inputSizes[0];
1179             outputSize = outputSizes[0];
1180             inputConfig = new InputConfiguration(inputSize.getWidth(),
1181                     inputSize.getHeight(), inputFormat);
1182             reprocessInputReader = ImageReader.newInstance(inputSize.getWidth(),
1183                     inputSize.getHeight(), inputFormat, /*maxImages*/1);
1184         } else {
1185             if (config.isOutputSupportedFor(outputFormat)) {
1186                 outputSize = config.getOutputSizes(outputFormat)[0];
1187             } else {
1188                 return;
1189             }
1190         }
1191 
1192         ImageReader imageReader = ImageReader.newInstance(outputSize.getWidth(),
1193                 outputSize.getHeight(), outputFormat, /*maxImages*/1);
1194 
1195         try {
1196             mSessionMockListener = spy(new BlockingSessionCallback());
1197             mSessionWaiter = mSessionMockListener.getStateWaiter();
1198             outputs.add(new OutputConfiguration(imageReader.getSurface()));
1199             if (reprocessInputReader != null) {
1200                 outputs.add( new OutputConfiguration(reprocessInputReader.getSurface()));
1201             }
1202             SessionConfiguration sessionConfig = new SessionConfiguration(
1203                     SessionConfiguration.SESSION_REGULAR, outputs,
1204                     new HandlerExecutor(mHandler), mSessionMockListener);
1205 
1206             CaptureRequest.Builder builder =
1207                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1208             builder.addTarget(imageReader.getSurface());
1209             CaptureRequest request = builder.build();
1210 
1211             sessionConfig.setInputConfiguration(inputConfig);
1212             sessionConfig.setSessionParameters(request);
1213             mCamera.createCaptureSession(sessionConfig);
1214 
1215             mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1216 
1217             // Verify we can capture a frame with the session.
1218             SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
1219             SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1220             imageReader.setOnImageAvailableListener(imageListener, mHandler);
1221 
1222             mSession.capture(request, captureListener, mHandler);
1223             captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS);
1224             imageListener.getImage(CAPTURE_TIMEOUT_MS).close();
1225         } finally {
1226             imageReader.close();
1227             if (reprocessInputReader != null) {
1228                 reprocessInputReader.close();
1229             }
1230             mSession.close();
1231         }
1232     }
1233 
1234     /**
1235      * Verify creating sessions back to back and only the last one is valid for
1236      * submitting requests.
1237      */
testCreateSessionsByCamera(String cameraId)1238     private void testCreateSessionsByCamera(String cameraId) throws Exception {
1239         final int NUM_SESSIONS = 3;
1240         final int SESSION_TIMEOUT_MS = 1000;
1241         final int CAPTURE_TIMEOUT_MS = 3000;
1242 
1243         if (VERBOSE) {
1244             Log.v(TAG, "Testing creating sessions for camera " + cameraId);
1245         }
1246 
1247         Size yuvSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.YUV_420_888,
1248                 /*bound*/null).get(0);
1249         Size jpegSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.JPEG,
1250                 /*bound*/null).get(0);
1251 
1252         // Create a list of image readers. JPEG for last one and YUV for the rest.
1253         List<ImageReader> imageReaders = new ArrayList<>();
1254         List<CameraCaptureSession> allSessions = new ArrayList<>();
1255 
1256         try {
1257             for (int i = 0; i < NUM_SESSIONS - 1; i++) {
1258                 imageReaders.add(ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(),
1259                         ImageFormat.YUV_420_888, /*maxImages*/1));
1260             }
1261             imageReaders.add(ImageReader.newInstance(jpegSize.getWidth(), jpegSize.getHeight(),
1262                     ImageFormat.JPEG, /*maxImages*/1));
1263 
1264             // Create multiple sessions back to back.
1265             MultipleSessionCallback sessionListener =
1266                     new MultipleSessionCallback(/*failOnConfigureFailed*/true);
1267             for (int i = 0; i < NUM_SESSIONS; i++) {
1268                 List<Surface> outputs = new ArrayList<>();
1269                 outputs.add(imageReaders.get(i).getSurface());
1270                 mCamera.createCaptureSession(outputs, sessionListener, mHandler);
1271             }
1272 
1273             // Verify we get onConfigured() for all sessions.
1274             allSessions = sessionListener.getAllSessions(NUM_SESSIONS,
1275                     SESSION_TIMEOUT_MS * NUM_SESSIONS);
1276             assertEquals(String.format("Got %d sessions but configured %d sessions",
1277                     allSessions.size(), NUM_SESSIONS), allSessions.size(), NUM_SESSIONS);
1278 
1279             // Verify all sessions except the last one are closed.
1280             for (int i = 0; i < NUM_SESSIONS - 1; i++) {
1281                 sessionListener.waitForSessionClose(allSessions.get(i), SESSION_TIMEOUT_MS);
1282             }
1283 
1284             // Verify we can capture a frame with the last session.
1285             CameraCaptureSession session = allSessions.get(allSessions.size() - 1);
1286             SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
1287             ImageReader reader = imageReaders.get(imageReaders.size() - 1);
1288             SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1289             reader.setOnImageAvailableListener(imageListener, mHandler);
1290 
1291             CaptureRequest.Builder builder =
1292                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1293             builder.addTarget(reader.getSurface());
1294             CaptureRequest request = builder.build();
1295 
1296             session.capture(request, captureListener, mHandler);
1297             captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS);
1298             imageListener.getImage(CAPTURE_TIMEOUT_MS).close();
1299         } finally {
1300             for (ImageReader reader : imageReaders) {
1301                 reader.close();
1302             }
1303             for (CameraCaptureSession session : allSessions) {
1304                 session.close();
1305             }
1306         }
1307     }
1308 
prepareTestByCamera()1309     private void prepareTestByCamera() throws Exception {
1310         final int PREPARE_TIMEOUT_MS = 10000;
1311 
1312         mSessionMockListener = spy(new BlockingSessionCallback());
1313 
1314         SurfaceTexture output1 = new SurfaceTexture(1);
1315         Surface output1Surface = new Surface(output1);
1316         SurfaceTexture output2 = new SurfaceTexture(2);
1317         Surface output2Surface = new Surface(output2);
1318 
1319         ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration> ();
1320         outConfigs.add(new OutputConfiguration(output1Surface));
1321         outConfigs.add(new OutputConfiguration(output2Surface));
1322         SessionConfiguration sessionConfig = new SessionConfiguration(
1323                 SessionConfiguration.SESSION_REGULAR, outConfigs,
1324                 new HandlerExecutor(mHandler), mSessionMockListener);
1325         CaptureRequest.Builder r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1326         sessionConfig.setSessionParameters(r.build());
1327         mCamera.createCaptureSession(sessionConfig);
1328 
1329         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1330 
1331         // Try basic prepare
1332 
1333         mSession.prepare(output1Surface);
1334 
1335         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
1336                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
1337 
1338         // Should not complain if preparing already prepared stream
1339 
1340         mSession.prepare(output1Surface);
1341 
1342         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2))
1343                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
1344 
1345         // Check surface not included in session
1346 
1347         SurfaceTexture output3 = new SurfaceTexture(3);
1348         Surface output3Surface = new Surface(output3);
1349         try {
1350             mSession.prepare(output3Surface);
1351             // Legacy camera prepare always succeed
1352             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1353                 fail("Preparing surface not part of session must throw IllegalArgumentException");
1354             }
1355         } catch (IllegalArgumentException e) {
1356             // expected
1357         }
1358 
1359         // Ensure second prepare also works
1360 
1361         mSession.prepare(output2Surface);
1362 
1363         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
1364                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
1365 
1366         // Use output1
1367 
1368         r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1369         r.addTarget(output1Surface);
1370 
1371         mSession.capture(r.build(), null, null);
1372 
1373         try {
1374             mSession.prepare(output1Surface);
1375             // Legacy camera prepare always succeed
1376             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1377                 fail("Preparing already-used surface must throw IllegalArgumentException");
1378             }
1379         } catch (IllegalArgumentException e) {
1380             // expected
1381         }
1382 
1383         // Create new session with outputs 1 and 3, ensure output1Surface still can't be prepared
1384         // again
1385 
1386         mSessionMockListener = spy(new BlockingSessionCallback());
1387 
1388         ArrayList<Surface> outputSurfaces = new ArrayList<Surface>(
1389             Arrays.asList(output1Surface, output3Surface));
1390         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
1391 
1392         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1393 
1394         try {
1395             mSession.prepare(output1Surface);
1396             // Legacy camera prepare always succeed
1397             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1398                 fail("Preparing surface used in previous session must throw " +
1399                         "IllegalArgumentException");
1400             }
1401         } catch (IllegalArgumentException e) {
1402             // expected
1403         }
1404 
1405         // Use output3, wait for result, then make sure prepare still doesn't work
1406 
1407         r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1408         r.addTarget(output3Surface);
1409 
1410         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1411         mSession.capture(r.build(), resultListener, mHandler);
1412 
1413         resultListener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
1414 
1415         try {
1416             mSession.prepare(output3Surface);
1417             // Legacy camera prepare always succeed
1418             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1419                 fail("Preparing already-used surface must throw IllegalArgumentException");
1420             }
1421         } catch (IllegalArgumentException e) {
1422             // expected
1423         }
1424 
1425         // Create new session with outputs 1 and 2, ensure output2Surface can be prepared again
1426 
1427         mSessionMockListener = spy(new BlockingSessionCallback());
1428 
1429         outputSurfaces = new ArrayList<>(
1430             Arrays.asList(output1Surface, output2Surface));
1431         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
1432 
1433         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1434 
1435         mSession.prepare(output2Surface);
1436 
1437         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
1438                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
1439 
1440         try {
1441             mSession.prepare(output1Surface);
1442             // Legacy camera prepare always succeed
1443             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1444                 fail("Preparing surface used in previous session must throw " +
1445                         "IllegalArgumentException");
1446             }
1447         } catch (IllegalArgumentException e) {
1448             // expected
1449         }
1450 
1451         output1.release();
1452         output2.release();
1453         output3.release();
1454     }
1455 
prepareTestForSharedSurfacesByCamera()1456     private void prepareTestForSharedSurfacesByCamera() throws Exception {
1457         final int PREPARE_TIMEOUT_MS = 10000;
1458 
1459         mSessionMockListener = spy(new BlockingSessionCallback());
1460 
1461         SurfaceTexture output1 = new SurfaceTexture(1);
1462         Surface output1Surface = new Surface(output1);
1463         SurfaceTexture output2 = new SurfaceTexture(2);
1464         Surface output2Surface = new Surface(output2);
1465 
1466         List<Surface> outputSurfaces = new ArrayList<>(
1467             Arrays.asList(output1Surface, output2Surface));
1468         OutputConfiguration surfaceSharedConfig = new OutputConfiguration(
1469             OutputConfiguration.SURFACE_GROUP_ID_NONE, output1Surface);
1470         surfaceSharedConfig.enableSurfaceSharing();
1471         surfaceSharedConfig.addSurface(output2Surface);
1472 
1473         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
1474         outputConfigurations.add(surfaceSharedConfig);
1475         mCamera.createCaptureSessionByOutputConfigurations(
1476                 outputConfigurations, mSessionMockListener, mHandler);
1477 
1478         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1479 
1480         // Try prepare on output1Surface
1481         mSession.prepare(output1Surface);
1482 
1483         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
1484                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
1485         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
1486                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
1487 
1488         // Try prepare on output2Surface
1489         mSession.prepare(output2Surface);
1490 
1491         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2))
1492                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
1493         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2))
1494                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
1495 
1496         // Try prepare on output1Surface again
1497         mSession.prepare(output1Surface);
1498 
1499         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(3))
1500                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
1501         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(3))
1502                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
1503     }
1504 
invalidRequestCaptureTestByCamera()1505     private void invalidRequestCaptureTestByCamera() throws Exception {
1506         if (VERBOSE) Log.v(TAG, "invalidRequestCaptureTestByCamera");
1507 
1508         List<CaptureRequest> emptyRequests = new ArrayList<CaptureRequest>();
1509         CaptureRequest.Builder requestBuilder =
1510                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1511         CaptureRequest unConfiguredRequest = requestBuilder.build();
1512         List<CaptureRequest> unConfiguredRequests = new ArrayList<CaptureRequest>();
1513         unConfiguredRequests.add(unConfiguredRequest);
1514 
1515         try {
1516             // Test: CameraCaptureSession capture should throw IAE for null request.
1517             mSession.capture(/*request*/null, /*listener*/null, mHandler);
1518             mCollector.addMessage(
1519                     "Session capture should throw IllegalArgumentException for null request");
1520         } catch (IllegalArgumentException e) {
1521             // Pass.
1522         }
1523 
1524         try {
1525             // Test: CameraCaptureSession capture should throw IAE for request
1526             // without surface configured.
1527             mSession.capture(unConfiguredRequest, /*listener*/null, mHandler);
1528             mCollector.addMessage("Session capture should throw " +
1529                     "IllegalArgumentException for request without surface configured");
1530         } catch (IllegalArgumentException e) {
1531             // Pass.
1532         }
1533 
1534         try {
1535             // Test: CameraCaptureSession setRepeatingRequest should throw IAE for null request.
1536             mSession.setRepeatingRequest(/*request*/null, /*listener*/null, mHandler);
1537             mCollector.addMessage("Session setRepeatingRequest should throw " +
1538                     "IllegalArgumentException for null request");
1539         } catch (IllegalArgumentException e) {
1540             // Pass.
1541         }
1542 
1543         try {
1544             // Test: CameraCaptureSession setRepeatingRequest should throw IAE for for request
1545             // without surface configured.
1546             mSession.setRepeatingRequest(unConfiguredRequest, /*listener*/null, mHandler);
1547             mCollector.addMessage("Capture zero burst should throw IllegalArgumentException " +
1548                     "for request without surface configured");
1549         } catch (IllegalArgumentException e) {
1550             // Pass.
1551         }
1552 
1553         try {
1554             // Test: CameraCaptureSession captureBurst should throw IAE for null request list.
1555             mSession.captureBurst(/*requests*/null, /*listener*/null, mHandler);
1556             mCollector.addMessage("Session captureBurst should throw " +
1557                     "IllegalArgumentException for null request list");
1558         } catch (IllegalArgumentException e) {
1559             // Pass.
1560         }
1561 
1562         try {
1563             // Test: CameraCaptureSession captureBurst should throw IAE for empty request list.
1564             mSession.captureBurst(emptyRequests, /*listener*/null, mHandler);
1565             mCollector.addMessage("Session captureBurst should throw " +
1566                     " IllegalArgumentException for empty request list");
1567         } catch (IllegalArgumentException e) {
1568             // Pass.
1569         }
1570 
1571         try {
1572             // Test: CameraCaptureSession captureBurst should throw IAE for request
1573             // without surface configured.
1574             mSession.captureBurst(unConfiguredRequests, /*listener*/null, mHandler);
1575             fail("Session captureBurst should throw IllegalArgumentException " +
1576                     "for null request list");
1577         } catch (IllegalArgumentException e) {
1578             // Pass.
1579         }
1580 
1581         try {
1582             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for null request list.
1583             mSession.setRepeatingBurst(/*requests*/null, /*listener*/null, mHandler);
1584             mCollector.addMessage("Session setRepeatingBurst should throw " +
1585                     "IllegalArgumentException for null request list");
1586         } catch (IllegalArgumentException e) {
1587             // Pass.
1588         }
1589 
1590         try {
1591             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for empty request list.
1592             mSession.setRepeatingBurst(emptyRequests, /*listener*/null, mHandler);
1593             mCollector.addMessage("Session setRepeatingBurst should throw " +
1594                     "IllegalArgumentException for empty request list");
1595         } catch (IllegalArgumentException e) {
1596             // Pass.
1597         }
1598 
1599         try {
1600             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for request
1601             // without surface configured.
1602             mSession.setRepeatingBurst(unConfiguredRequests, /*listener*/null, mHandler);
1603             mCollector.addMessage("Session setRepeatingBurst should throw " +
1604                     "IllegalArgumentException for request without surface configured");
1605         } catch (IllegalArgumentException e) {
1606             // Pass.
1607         }
1608     }
1609 
1610     private class IsCaptureResultNotEmpty
1611             implements ArgumentMatcher<TotalCaptureResult> {
1612         @Override
matches(TotalCaptureResult result)1613         public boolean matches(TotalCaptureResult result) {
1614             /**
1615              * Do the simple verification here. Only verify the timestamp for now.
1616              * TODO: verify more required capture result metadata fields.
1617              */
1618             Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
1619             if (timeStamp != null && timeStamp.longValue() > 0L) {
1620                 return true;
1621             }
1622             return false;
1623         }
1624     }
1625 
1626     /**
1627      * Run capture test with different test configurations.
1628      *
1629      * @param burst If the test uses {@link CameraCaptureSession#captureBurst} or
1630      * {@link CameraCaptureSession#setRepeatingBurst} to capture the burst.
1631      * @param repeating If the test uses {@link CameraCaptureSession#setRepeatingBurst} or
1632      * {@link CameraCaptureSession#setRepeatingRequest} for repeating capture.
1633      * @param abort If the test uses {@link CameraCaptureSession#abortCaptures} to stop the
1634      * repeating capture.  It has no effect if repeating is false.
1635      * @param useExecutor If the test uses {@link java.util.concurrent.Executor} instead of
1636      * {@link android.os.Handler} for callback invocation.
1637      */
runCaptureTest(boolean burst, boolean repeating, boolean abort, boolean useExecutor)1638     private void runCaptureTest(boolean burst, boolean repeating, boolean abort,
1639             boolean useExecutor) throws Exception {
1640         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
1641         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
1642             try {
1643                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
1644                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
1645 
1646                 prepareCapture();
1647 
1648                 if (!burst) {
1649                     // Test: that a single capture of each template type succeeds.
1650                     for (int j = 0; j < sTemplates.length; j++) {
1651                         // Skip video snapshots for LEGACY mode
1652                         if (mStaticInfo.isHardwareLevelLegacy() &&
1653                                 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1654                             continue;
1655                         }
1656                         // Skip non-PREVIEW templates for non-color output
1657                         if (!mStaticInfo.isColorOutputSupported() &&
1658                                 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
1659                             continue;
1660                         }
1661 
1662                         captureSingleShot(cameraIdsUnderTest[i], sTemplates[j], repeating, abort,
1663                                 useExecutor);
1664                     }
1665                 }
1666                 else {
1667                     // Test: burst of one shot
1668                     captureBurstShot(cameraIdsUnderTest[i], sTemplates, 1, repeating, abort, useExecutor);
1669 
1670                     int template = mStaticInfo.isColorOutputSupported() ?
1671                         CameraDevice.TEMPLATE_STILL_CAPTURE :
1672                         CameraDevice.TEMPLATE_PREVIEW;
1673                     int[] templates = new int[] {
1674                         template,
1675                         template,
1676                         template,
1677                         template,
1678                         template
1679                     };
1680 
1681                     // Test: burst of 5 shots of the same template type
1682                     captureBurstShot(cameraIdsUnderTest[i], templates, templates.length, repeating, abort,
1683                             useExecutor);
1684 
1685                     if (mStaticInfo.isColorOutputSupported()) {
1686                         // Test: burst of 6 shots of different template types
1687                         captureBurstShot(cameraIdsUnderTest[i], sTemplates, sTemplates.length, repeating,
1688                                 abort, useExecutor);
1689                     }
1690                 }
1691                 verify(mCameraMockListener, never())
1692                         .onError(
1693                                 any(CameraDevice.class),
1694                                 anyInt());
1695             } catch (Exception e) {
1696                 mCollector.addError(e);
1697             } finally {
1698                 try {
1699                     closeSession();
1700                 } catch (Exception e) {
1701                     mCollector.addError(e);
1702                 }finally {
1703                     closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
1704                 }
1705             }
1706         }
1707     }
1708 
captureSingleShot( String id, int template, boolean repeating, boolean abort, boolean useExecutor)1709     private void captureSingleShot(
1710             String id,
1711             int template,
1712             boolean repeating, boolean abort, boolean useExecutor) throws Exception {
1713 
1714         assertEquals("Bad initial state for preparing to capture",
1715                 mLatestSessionState, SESSION_READY);
1716 
1717         final Executor executor = useExecutor ? new HandlerExecutor(mHandler) : null;
1718         CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(template);
1719         assertNotNull("Failed to create capture request", requestBuilder);
1720         requestBuilder.addTarget(mReaderSurface);
1721         CameraCaptureSession.CaptureCallback mockCaptureCallback =
1722                 mock(CameraCaptureSession.CaptureCallback.class);
1723 
1724         if (VERBOSE) {
1725             Log.v(TAG, String.format("Capturing shot for device %s, template %d",
1726                     id, template));
1727         }
1728 
1729         if (executor != null) {
1730             startCapture(requestBuilder.build(), repeating, mockCaptureCallback, executor);
1731         } else {
1732             startCapture(requestBuilder.build(), repeating, mockCaptureCallback, mHandler);
1733         }
1734         waitForSessionState(SESSION_ACTIVE, SESSION_ACTIVE_TIMEOUT_MS);
1735 
1736         int expectedCaptureResultCount = repeating ? REPEATING_CAPTURE_EXPECTED_RESULT_COUNT : 1;
1737         verifyCaptureResults(mockCaptureCallback, expectedCaptureResultCount);
1738 
1739         if (repeating) {
1740             if (abort) {
1741                 mSession.abortCaptures();
1742                 // Have to make sure abort and new requests aren't interleave together.
1743                 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1744 
1745                 // Capture a single capture, and verify the result.
1746                 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback();
1747                 CaptureRequest singleRequest = requestBuilder.build();
1748                 if (executor != null) {
1749                     mSession.captureSingleRequest(singleRequest, executor, resultCallback);
1750                 } else {
1751                     mSession.capture(singleRequest, resultCallback, mHandler);
1752                 }
1753                 resultCallback.getCaptureResultForRequest(singleRequest, CAPTURE_RESULT_TIMEOUT_MS);
1754 
1755                 // Resume the repeating, and verify that results are returned.
1756                 if (executor != null) {
1757                     mSession.setSingleRepeatingRequest(singleRequest, executor, resultCallback);
1758                 } else {
1759                     mSession.setRepeatingRequest(singleRequest, resultCallback, mHandler);
1760                 }
1761                 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) {
1762                     resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
1763                 }
1764             }
1765             mSession.stopRepeating();
1766         }
1767         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1768     }
1769 
captureBurstShot( String id, int[] templates, int len, boolean repeating, boolean abort, boolean useExecutor)1770     private void captureBurstShot(
1771             String id,
1772             int[] templates,
1773             int len,
1774             boolean repeating,
1775             boolean abort, boolean useExecutor) throws Exception {
1776 
1777         assertEquals("Bad initial state for preparing to capture",
1778                 mLatestSessionState, SESSION_READY);
1779 
1780         assertTrue("Invalid args to capture function", len <= templates.length);
1781         List<CaptureRequest> requests = new ArrayList<CaptureRequest>();
1782         List<CaptureRequest> postAbortRequests = new ArrayList<CaptureRequest>();
1783         final Executor executor = useExecutor ? new HandlerExecutor(mHandler) : null;
1784         for (int i = 0; i < len; i++) {
1785             // Skip video snapshots for LEGACY mode
1786             if (mStaticInfo.isHardwareLevelLegacy() &&
1787                     templates[i] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1788                 continue;
1789             }
1790             // Skip non-PREVIEW templates for non-color outpu
1791             if (!mStaticInfo.isColorOutputSupported() &&
1792                     templates[i] != CameraDevice.TEMPLATE_PREVIEW) {
1793                 continue;
1794             }
1795 
1796             CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(templates[i]);
1797             assertNotNull("Failed to create capture request", requestBuilder);
1798             requestBuilder.addTarget(mReaderSurface);
1799             requests.add(requestBuilder.build());
1800             if (abort) {
1801                 postAbortRequests.add(requestBuilder.build());
1802             }
1803         }
1804         CameraCaptureSession.CaptureCallback mockCaptureCallback =
1805                 mock(CameraCaptureSession.CaptureCallback.class);
1806 
1807         if (VERBOSE) {
1808             Log.v(TAG, String.format("Capturing burst shot for device %s", id));
1809         }
1810 
1811         if (!repeating) {
1812             if (executor != null) {
1813                 mSession.captureBurstRequests(requests, executor, mockCaptureCallback);
1814             } else {
1815                 mSession.captureBurst(requests, mockCaptureCallback, mHandler);
1816             }
1817         }
1818         else {
1819             if (executor != null) {
1820                 mSession.setRepeatingBurstRequests(requests, executor, mockCaptureCallback);
1821             } else {
1822                 mSession.setRepeatingBurst(requests, mockCaptureCallback, mHandler);
1823             }
1824         }
1825         waitForSessionState(SESSION_ACTIVE, SESSION_READY_TIMEOUT_MS);
1826 
1827         int expectedResultCount = requests.size();
1828         if (repeating) {
1829             expectedResultCount *= REPEATING_CAPTURE_EXPECTED_RESULT_COUNT;
1830         }
1831 
1832         verifyCaptureResults(mockCaptureCallback, expectedResultCount);
1833 
1834         if (repeating) {
1835             if (abort) {
1836                 mSession.abortCaptures();
1837                 // Have to make sure abort and new requests aren't interleave together.
1838                 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1839 
1840                 // Capture a burst of captures, and verify the results.
1841                 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback();
1842                 if (executor != null) {
1843                     mSession.captureBurstRequests(postAbortRequests, executor, resultCallback);
1844                 } else {
1845                     mSession.captureBurst(postAbortRequests, resultCallback, mHandler);
1846                 }
1847                 // Verify that the results are returned.
1848                 for (int i = 0; i < postAbortRequests.size(); i++) {
1849                     resultCallback.getCaptureResultForRequest(
1850                             postAbortRequests.get(i), CAPTURE_RESULT_TIMEOUT_MS);
1851                 }
1852 
1853                 // Resume the repeating, and verify that results are returned.
1854                 if (executor != null) {
1855                     mSession.setRepeatingBurstRequests(requests, executor, resultCallback);
1856                 } else {
1857                     mSession.setRepeatingBurst(requests, resultCallback, mHandler);
1858                 }
1859                 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) {
1860                     resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
1861                 }
1862             }
1863             mSession.stopRepeating();
1864         }
1865         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1866     }
1867 
1868     /**
1869      * Precondition: Device must be in known OPENED state (has been waited for).
1870      *
1871      * <p>Creates a new capture session and waits until it is in the {@code SESSION_READY} state.
1872      * </p>
1873      *
1874      * <p>Any existing capture session will be closed as a result of calling this.</p>
1875      * */
prepareCapture()1876     private void prepareCapture() throws Exception {
1877         if (VERBOSE) Log.v(TAG, "prepareCapture");
1878 
1879         assertTrue("Bad initial state for preparing to capture",
1880                 mLatestDeviceState == STATE_OPENED);
1881 
1882         if (mSession != null) {
1883             if (VERBOSE) Log.v(TAG, "prepareCapture - closing existing session");
1884             closeSession();
1885         }
1886 
1887         // Create a new session listener each time, it's not reusable across cameras
1888         mSessionMockListener = spy(new BlockingSessionCallback());
1889         mSessionWaiter = mSessionMockListener.getStateWaiter();
1890 
1891         if (!mStaticInfo.isColorOutputSupported()) {
1892             createDefaultImageReader(getMaxDepthSize(mCamera.getId(), mCameraManager),
1893                     ImageFormat.DEPTH16, MAX_NUM_IMAGES, new ImageDropperListener());
1894         } else {
1895             createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
1896                     new ImageDropperListener());
1897         }
1898 
1899         List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(mReaderSurface));
1900         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
1901 
1902         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1903         waitForSessionState(SESSION_CONFIGURED, SESSION_CONFIGURE_TIMEOUT_MS);
1904         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1905     }
1906 
waitForDeviceState(int state, long timeoutMs)1907     private void waitForDeviceState(int state, long timeoutMs) {
1908         mCameraMockListener.waitForState(state, timeoutMs);
1909         mLatestDeviceState = state;
1910     }
1911 
waitForSessionState(int state, long timeoutMs)1912     private void waitForSessionState(int state, long timeoutMs) {
1913         mSessionWaiter.waitForState(state, timeoutMs);
1914         mLatestSessionState = state;
1915     }
1916 
verifyCaptureResults( CameraCaptureSession.CaptureCallback mockListener, int expectResultCount)1917     private void verifyCaptureResults(
1918             CameraCaptureSession.CaptureCallback mockListener,
1919             int expectResultCount) {
1920         final int TIMEOUT_PER_RESULT_MS = 2000;
1921         // Should receive expected number of capture results.
1922         verify(mockListener,
1923                 timeout(TIMEOUT_PER_RESULT_MS * expectResultCount).atLeast(expectResultCount))
1924                         .onCaptureCompleted(
1925                                 eq(mSession),
1926                                 isA(CaptureRequest.class),
1927                                 argThat(new IsCaptureResultNotEmpty()));
1928         // Should not receive any capture failed callbacks.
1929         verify(mockListener, never())
1930                         .onCaptureFailed(
1931                                 eq(mSession),
1932                                 isA(CaptureRequest.class),
1933                                 isA(CaptureFailure.class));
1934         // Should receive expected number of capture shutter calls
1935         verify(mockListener,
1936                 atLeast(expectResultCount))
1937                         .onCaptureStarted(
1938                                eq(mSession),
1939                                isA(CaptureRequest.class),
1940                                anyLong(),
1941                                anyLong());
1942     }
1943 
checkFpsRange(CaptureRequest.Builder request, int template, CameraCharacteristics props)1944     private void checkFpsRange(CaptureRequest.Builder request, int template,
1945             CameraCharacteristics props) {
1946         CaptureRequest.Key<Range<Integer>> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE;
1947         Range<Integer> fpsRange;
1948         if ((fpsRange = mCollector.expectKeyValueNotNull(request, fpsRangeKey)) == null) {
1949             return;
1950         }
1951 
1952         int minFps = fpsRange.getLower();
1953         int maxFps = fpsRange.getUpper();
1954         Range<Integer>[] availableFpsRange = props
1955                 .get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
1956         boolean foundRange = false;
1957         for (int i = 0; i < availableFpsRange.length; i += 1) {
1958             if (minFps == availableFpsRange[i].getLower()
1959                     && maxFps == availableFpsRange[i].getUpper()) {
1960                 foundRange = true;
1961                 break;
1962             }
1963         }
1964         if (!foundRange) {
1965             mCollector.addMessage(String.format("Unable to find the fps range (%d, %d)",
1966                     minFps, maxFps));
1967             return;
1968         }
1969 
1970 
1971         if (template != CameraDevice.TEMPLATE_MANUAL &&
1972                 template != CameraDevice.TEMPLATE_STILL_CAPTURE) {
1973             if (maxFps < MIN_FPS_REQUIRED_FOR_STREAMING) {
1974                 mCollector.addMessage("Max fps should be at least "
1975                         + MIN_FPS_REQUIRED_FOR_STREAMING);
1976                 return;
1977             }
1978 
1979             // Relax framerate constraints on legacy mode
1980             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1981                 // Need give fixed frame rate for video recording template.
1982                 if (template == CameraDevice.TEMPLATE_RECORD) {
1983                     if (maxFps != minFps) {
1984                         mCollector.addMessage("Video recording frame rate should be fixed");
1985                     }
1986                 }
1987             }
1988         }
1989     }
1990 
checkAfMode(CaptureRequest.Builder request, int template, CameraCharacteristics props)1991     private void checkAfMode(CaptureRequest.Builder request, int template,
1992             CameraCharacteristics props) {
1993         boolean hasFocuser = props.getKeys().contains(CameraCharacteristics.
1994                 LENS_INFO_MINIMUM_FOCUS_DISTANCE) &&
1995                 (props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f);
1996 
1997         if (!hasFocuser) {
1998             return;
1999         }
2000 
2001         int targetAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
2002         int[] availableAfMode = props.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
2003         if (template == CameraDevice.TEMPLATE_PREVIEW ||
2004                 template == CameraDevice.TEMPLATE_STILL_CAPTURE ||
2005                 template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) {
2006             // Default to CONTINUOUS_PICTURE if it is available, otherwise AUTO.
2007             for (int i = 0; i < availableAfMode.length; i++) {
2008                 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) {
2009                     targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
2010                     break;
2011                 }
2012             }
2013         } else if (template == CameraDevice.TEMPLATE_RECORD ||
2014                 template == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
2015             // Default to CONTINUOUS_VIDEO if it is available, otherwise AUTO.
2016             for (int i = 0; i < availableAfMode.length; i++) {
2017                 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
2018                     targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
2019                     break;
2020                 }
2021             }
2022         } else if (template == CameraDevice.TEMPLATE_MANUAL) {
2023             targetAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
2024         }
2025 
2026         mCollector.expectKeyValueEquals(request, CONTROL_AF_MODE, targetAfMode);
2027         if (mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FOCUS_DISTANCE)) {
2028             mCollector.expectKeyValueNotNull(request, LENS_FOCUS_DISTANCE);
2029         }
2030     }
2031 
checkAntiBandingMode(CaptureRequest.Builder request, int template)2032     private void checkAntiBandingMode(CaptureRequest.Builder request, int template) {
2033         if (template == CameraDevice.TEMPLATE_MANUAL) {
2034             return;
2035         }
2036 
2037         if (!mStaticInfo.isColorOutputSupported()) return;
2038 
2039         List<Integer> availableAntiBandingModes =
2040                 Arrays.asList(toObject(mStaticInfo.getAeAvailableAntiBandingModesChecked()));
2041 
2042         if (availableAntiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO)) {
2043             mCollector.expectKeyValueEquals(request, CONTROL_AE_ANTIBANDING_MODE,
2044                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
2045         } else {
2046             mCollector.expectKeyValueIsIn(request, CONTROL_AE_ANTIBANDING_MODE,
2047                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ,
2048                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ);
2049         }
2050     }
2051 
2052     /**
2053      * <p>Check if 3A metering settings are "up to HAL" in request template</p>
2054      *
2055      * <p>This function doesn't fail the test immediately, it updates the
2056      * test pass/fail status and appends the failure message to the error collector each key.</p>
2057      *
2058      * @param regions The metering rectangles to be checked
2059      */
checkMeteringRect(MeteringRectangle[] regions)2060     private void checkMeteringRect(MeteringRectangle[] regions) {
2061         if (regions == null) {
2062             return;
2063         }
2064         mCollector.expectNotEquals("Number of metering region should not be 0", 0, regions.length);
2065         for (int i = 0; i < regions.length; i++) {
2066             mCollector.expectEquals("Default metering regions should have all zero weight",
2067                     0, regions[i].getMeteringWeight());
2068         }
2069     }
2070 
2071     /**
2072      * <p>Check if the request settings are suitable for a given request template.</p>
2073      *
2074      * <p>This function doesn't fail the test immediately, it updates the
2075      * test pass/fail status and appends the failure message to the error collector each key.</p>
2076      *
2077      * @param request The request to be checked.
2078      * @param template The capture template targeted by this request.
2079      * @param props The CameraCharacteristics this request is checked against with.
2080      */
checkRequestForTemplate(CaptureRequest.Builder request, int template, CameraCharacteristics props)2081     private void checkRequestForTemplate(CaptureRequest.Builder request, int template,
2082             CameraCharacteristics props) {
2083         Integer hwLevel = props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
2084         boolean isExternalCamera = (hwLevel ==
2085                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
2086 
2087         // 3A settings--AE/AWB/AF.
2088         Integer maxRegionsAeVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
2089         int maxRegionsAe = maxRegionsAeVal != null ? maxRegionsAeVal : 0;
2090         Integer maxRegionsAwbVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
2091         int maxRegionsAwb = maxRegionsAwbVal != null ? maxRegionsAwbVal : 0;
2092         Integer maxRegionsAfVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
2093         int maxRegionsAf = maxRegionsAfVal != null ? maxRegionsAfVal : 0;
2094 
2095         checkFpsRange(request, template, props);
2096 
2097         checkAfMode(request, template, props);
2098         checkAntiBandingMode(request, template);
2099 
2100         if (template == CameraDevice.TEMPLATE_MANUAL) {
2101             mCollector.expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
2102             mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
2103                     CaptureRequest.CONTROL_AE_MODE_OFF);
2104             mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
2105                     CaptureRequest.CONTROL_AWB_MODE_OFF);
2106         } else {
2107             mCollector.expectKeyValueEquals(request, CONTROL_MODE,
2108                     CaptureRequest.CONTROL_MODE_AUTO);
2109             if (mStaticInfo.isColorOutputSupported()) {
2110                 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
2111                         CaptureRequest.CONTROL_AE_MODE_ON);
2112                 mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
2113                 mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
2114                         CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
2115                 // if AE lock is not supported, expect the control key to be non-exist or false
2116                 if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
2117                     mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
2118                 }
2119 
2120                 mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
2121                         CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
2122 
2123                 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
2124                         CaptureRequest.CONTROL_AWB_MODE_AUTO);
2125                 // if AWB lock is not supported, expect the control key to be non-exist or false
2126                 if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
2127                     mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
2128                 }
2129 
2130                 // Check 3A regions.
2131                 if (VERBOSE) {
2132                     Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}",
2133                                     maxRegionsAe, maxRegionsAwb, maxRegionsAf));
2134                 }
2135                 if (maxRegionsAe > 0) {
2136                     mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS);
2137                     MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
2138                     checkMeteringRect(aeRegions);
2139                 }
2140                 if (maxRegionsAwb > 0) {
2141                     mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS);
2142                     MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS);
2143                     checkMeteringRect(awbRegions);
2144                 }
2145                 if (maxRegionsAf > 0) {
2146                     mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS);
2147                     MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
2148                     checkMeteringRect(afRegions);
2149                 }
2150             }
2151         }
2152 
2153         // Sensor settings.
2154 
2155         mCollector.expectEquals("Lens aperture must be present in request if available apertures " +
2156                         "are present in metadata, and vice-versa.",
2157                 mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES),
2158                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_APERTURE));
2159         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES)) {
2160             float[] availableApertures =
2161                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES);
2162             if (availableApertures.length > 1) {
2163                 mCollector.expectKeyValueNotNull(request, LENS_APERTURE);
2164             }
2165         }
2166 
2167         mCollector.expectEquals("Lens filter density must be present in request if available " +
2168                         "filter densities are present in metadata, and vice-versa.",
2169                 mStaticInfo.areKeysAvailable(CameraCharacteristics.
2170                         LENS_INFO_AVAILABLE_FILTER_DENSITIES),
2171                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FILTER_DENSITY));
2172         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.
2173                 LENS_INFO_AVAILABLE_FILTER_DENSITIES)) {
2174             float[] availableFilters =
2175                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES);
2176             if (availableFilters.length > 1) {
2177                 mCollector.expectKeyValueNotNull(request, LENS_FILTER_DENSITY);
2178             }
2179         }
2180 
2181 
2182         if (!isExternalCamera) {
2183             float[] availableFocalLen =
2184                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
2185             if (availableFocalLen.length > 1) {
2186                 mCollector.expectKeyValueNotNull(request, LENS_FOCAL_LENGTH);
2187             }
2188         }
2189 
2190 
2191         mCollector.expectEquals("Lens optical stabilization must be present in request if " +
2192                         "available optical stabilizations are present in metadata, and vice-versa.",
2193                 mStaticInfo.areKeysAvailable(CameraCharacteristics.
2194                         LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION),
2195                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE));
2196         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.
2197                 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) {
2198             int[] availableOIS =
2199                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);
2200             if (availableOIS.length > 1) {
2201                 mCollector.expectKeyValueNotNull(request, LENS_OPTICAL_STABILIZATION_MODE);
2202             }
2203         }
2204 
2205         if (mStaticInfo.areKeysAvailable(SENSOR_TEST_PATTERN_MODE)) {
2206             mCollector.expectKeyValueEquals(request, SENSOR_TEST_PATTERN_MODE,
2207                     CaptureRequest.SENSOR_TEST_PATTERN_MODE_OFF);
2208         }
2209 
2210         if (mStaticInfo.areKeysAvailable(BLACK_LEVEL_LOCK)) {
2211             mCollector.expectKeyValueEquals(request, BLACK_LEVEL_LOCK, false);
2212         }
2213 
2214         if (mStaticInfo.areKeysAvailable(SENSOR_FRAME_DURATION)) {
2215             mCollector.expectKeyValueNotNull(request, SENSOR_FRAME_DURATION);
2216         }
2217 
2218         if (mStaticInfo.areKeysAvailable(SENSOR_EXPOSURE_TIME)) {
2219             mCollector.expectKeyValueNotNull(request, SENSOR_EXPOSURE_TIME);
2220         }
2221 
2222         if (mStaticInfo.areKeysAvailable(SENSOR_SENSITIVITY)) {
2223             mCollector.expectKeyValueNotNull(request, SENSOR_SENSITIVITY);
2224         }
2225 
2226         // ISP-processing settings.
2227         if (mStaticInfo.isColorOutputSupported()) {
2228             mCollector.expectKeyValueEquals(
2229                     request, STATISTICS_FACE_DETECT_MODE,
2230                     CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF);
2231             mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
2232         }
2233 
2234         List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
2235         if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) {
2236             // If the device doesn't support RAW, all template should have OFF as default.
2237             if (!availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
2238                 mCollector.expectKeyValueEquals(
2239                         request, STATISTICS_LENS_SHADING_MAP_MODE,
2240                         CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF);
2241             }
2242         }
2243 
2244         boolean supportReprocessing =
2245                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) ||
2246                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
2247 
2248 
2249         if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) {
2250 
2251             // Ok with either FAST or HIGH_QUALITY
2252             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) {
2253                 mCollector.expectKeyValueNotEquals(
2254                         request, COLOR_CORRECTION_MODE,
2255                         CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
2256             }
2257 
2258             // Edge enhancement, noise reduction and aberration correction modes.
2259             mCollector.expectEquals("Edge mode must be present in request if " +
2260                             "available edge modes are present in metadata, and vice-versa.",
2261                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
2262                             EDGE_AVAILABLE_EDGE_MODES),
2263                     mStaticInfo.areKeysAvailable(CaptureRequest.EDGE_MODE));
2264             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
2265                 List<Integer> availableEdgeModes =
2266                         Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
2267                 // Don't need check fast as fast or high quality must be both present or both not.
2268                 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) {
2269                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
2270                             CaptureRequest.EDGE_MODE_HIGH_QUALITY);
2271                 } else {
2272                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
2273                             CaptureRequest.EDGE_MODE_OFF);
2274                 }
2275             }
2276             if (mStaticInfo.areKeysAvailable(SHADING_MODE)) {
2277                 List<Integer> availableShadingModes =
2278                         Arrays.asList(toObject(mStaticInfo.getAvailableShadingModesChecked()));
2279                 mCollector.expectKeyValueEquals(request, SHADING_MODE,
2280                         CaptureRequest.SHADING_MODE_HIGH_QUALITY);
2281             }
2282 
2283             mCollector.expectEquals("Noise reduction mode must be present in request if " +
2284                             "available noise reductions are present in metadata, and vice-versa.",
2285                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
2286                             NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES),
2287                     mStaticInfo.areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE));
2288             if (mStaticInfo.areKeysAvailable(
2289                     CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) {
2290                 List<Integer> availableNoiseReductionModes =
2291                         Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked()));
2292                 // Don't need check fast as fast or high quality must be both present or both not.
2293                 if (availableNoiseReductionModes
2294                         .contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
2295                     mCollector.expectKeyValueEquals(
2296                             request, NOISE_REDUCTION_MODE,
2297                             CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
2298                 } else {
2299                     mCollector.expectKeyValueEquals(
2300                             request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
2301                 }
2302             }
2303 
2304             mCollector.expectEquals("Hot pixel mode must be present in request if " +
2305                             "available hot pixel modes are present in metadata, and vice-versa.",
2306                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
2307                             HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES),
2308                     mStaticInfo.areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE));
2309 
2310             if (mStaticInfo.areKeysAvailable(HOT_PIXEL_MODE)) {
2311                 List<Integer> availableHotPixelModes =
2312                         Arrays.asList(toObject(
2313                                 mStaticInfo.getAvailableHotPixelModesChecked()));
2314                 if (availableHotPixelModes
2315                         .contains(CaptureRequest.HOT_PIXEL_MODE_HIGH_QUALITY)) {
2316                     mCollector.expectKeyValueEquals(
2317                             request, HOT_PIXEL_MODE,
2318                             CaptureRequest.HOT_PIXEL_MODE_HIGH_QUALITY);
2319                 } else {
2320                     mCollector.expectKeyValueEquals(
2321                             request, HOT_PIXEL_MODE, CaptureRequest.HOT_PIXEL_MODE_OFF);
2322                 }
2323             }
2324 
2325             boolean supportAvailableAberrationModes = mStaticInfo.areKeysAvailable(
2326                     CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES);
2327             boolean supportAberrationRequestKey = mStaticInfo.areKeysAvailable(
2328                     CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
2329             mCollector.expectEquals("Aberration correction mode must be present in request if " +
2330                     "available aberration correction reductions are present in metadata, and "
2331                     + "vice-versa.", supportAvailableAberrationModes, supportAberrationRequestKey);
2332             if (supportAberrationRequestKey) {
2333                 List<Integer> availableAberrationModes = Arrays.asList(
2334                         toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
2335                 // Don't need check fast as fast or high quality must be both present or both not.
2336                 if (availableAberrationModes
2337                         .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY)) {
2338                     mCollector.expectKeyValueEquals(
2339                             request, COLOR_CORRECTION_ABERRATION_MODE,
2340                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
2341                 } else {
2342                     mCollector.expectKeyValueEquals(
2343                             request, COLOR_CORRECTION_ABERRATION_MODE,
2344                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
2345                 }
2346             }
2347         } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) {
2348             mCollector.expectKeyValueEquals(request, EDGE_MODE,
2349                     CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
2350             mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE,
2351                     CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
2352         } else if (template == CameraDevice.TEMPLATE_PREVIEW ||
2353                 template == CameraDevice.TEMPLATE_RECORD) {
2354 
2355             // Ok with either FAST or HIGH_QUALITY
2356             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) {
2357                 mCollector.expectKeyValueNotEquals(
2358                         request, COLOR_CORRECTION_MODE,
2359                         CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
2360             }
2361 
2362             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
2363                 List<Integer> availableEdgeModes =
2364                         Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
2365                 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
2366                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
2367                             CaptureRequest.EDGE_MODE_FAST);
2368                 } else {
2369                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
2370                             CaptureRequest.EDGE_MODE_OFF);
2371                 }
2372             }
2373 
2374             if (mStaticInfo.areKeysAvailable(SHADING_MODE)) {
2375                 List<Integer> availableShadingModes =
2376                         Arrays.asList(toObject(mStaticInfo.getAvailableShadingModesChecked()));
2377                 mCollector.expectKeyValueEquals(request, SHADING_MODE,
2378                         CaptureRequest.SHADING_MODE_FAST);
2379             }
2380 
2381             if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
2382                 List<Integer> availableNoiseReductionModes =
2383                         Arrays.asList(toObject(
2384                                 mStaticInfo.getAvailableNoiseReductionModesChecked()));
2385                 if (availableNoiseReductionModes
2386                         .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
2387                     mCollector.expectKeyValueEquals(
2388                             request, NOISE_REDUCTION_MODE,
2389                             CaptureRequest.NOISE_REDUCTION_MODE_FAST);
2390                 } else {
2391                     mCollector.expectKeyValueEquals(
2392                             request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
2393                 }
2394             }
2395 
2396             if (mStaticInfo.areKeysAvailable(HOT_PIXEL_MODE)) {
2397                 List<Integer> availableHotPixelModes =
2398                         Arrays.asList(toObject(
2399                                 mStaticInfo.getAvailableHotPixelModesChecked()));
2400                 if (availableHotPixelModes
2401                         .contains(CaptureRequest.HOT_PIXEL_MODE_FAST)) {
2402                     mCollector.expectKeyValueEquals(
2403                             request, HOT_PIXEL_MODE,
2404                             CaptureRequest.HOT_PIXEL_MODE_FAST);
2405                 } else {
2406                     mCollector.expectKeyValueEquals(
2407                             request, HOT_PIXEL_MODE, CaptureRequest.HOT_PIXEL_MODE_OFF);
2408                 }
2409             }
2410 
2411             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
2412                 List<Integer> availableAberrationModes = Arrays.asList(
2413                         toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
2414                 if (availableAberrationModes
2415                         .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST)) {
2416                     mCollector.expectKeyValueEquals(
2417                             request, COLOR_CORRECTION_ABERRATION_MODE,
2418                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST);
2419                 } else {
2420                     mCollector.expectKeyValueEquals(
2421                             request, COLOR_CORRECTION_ABERRATION_MODE,
2422                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
2423                 }
2424             }
2425         } else {
2426             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
2427                 mCollector.expectKeyValueNotNull(request, EDGE_MODE);
2428             }
2429 
2430             if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
2431                 mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE);
2432             }
2433 
2434             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
2435                 mCollector.expectKeyValueNotNull(request, COLOR_CORRECTION_ABERRATION_MODE);
2436             }
2437         }
2438 
2439         // Tone map and lens shading modes.
2440         if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) {
2441             mCollector.expectEquals("Tonemap mode must be present in request if " +
2442                             "available tonemap modes are present in metadata, and vice-versa.",
2443                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
2444                             TONEMAP_AVAILABLE_TONE_MAP_MODES),
2445                     mStaticInfo.areKeysAvailable(CaptureRequest.TONEMAP_MODE));
2446             if (mStaticInfo.areKeysAvailable(
2447                     CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES)) {
2448                 List<Integer> availableToneMapModes =
2449                         Arrays.asList(toObject(mStaticInfo.getAvailableToneMapModesChecked()));
2450                 if (availableToneMapModes.contains(CaptureRequest.TONEMAP_MODE_HIGH_QUALITY)) {
2451                     mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
2452                             CaptureRequest.TONEMAP_MODE_HIGH_QUALITY);
2453                 } else {
2454                     mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
2455                             CaptureRequest.TONEMAP_MODE_FAST);
2456                 }
2457             }
2458 
2459             // Still capture template should have android.statistics.lensShadingMapMode ON when
2460             // RAW capability is supported.
2461             if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE) &&
2462                     availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
2463                     mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE,
2464                             STATISTICS_LENS_SHADING_MAP_MODE_ON);
2465             }
2466         } else {
2467             if (mStaticInfo.areKeysAvailable(TONEMAP_MODE)) {
2468                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
2469                         CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE);
2470                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
2471                         CaptureRequest.TONEMAP_MODE_GAMMA_VALUE);
2472                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
2473                         CaptureRequest.TONEMAP_MODE_PRESET_CURVE);
2474             }
2475             if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) {
2476                 mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE,
2477                         CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF);
2478             }
2479             if (mStaticInfo.areKeysAvailable(STATISTICS_HOT_PIXEL_MAP_MODE)) {
2480                 mCollector.expectKeyValueEquals(request, STATISTICS_HOT_PIXEL_MAP_MODE,
2481                         false);
2482             }
2483         }
2484 
2485         // Enable ZSL
2486         if (template != CameraDevice.TEMPLATE_STILL_CAPTURE) {
2487             if (mStaticInfo.areKeysAvailable(CONTROL_ENABLE_ZSL)) {
2488                     mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false);
2489             }
2490         }
2491 
2492         int[] outputFormats = mStaticInfo.getAvailableFormats(
2493                 StaticMetadata.StreamDirection.Output);
2494         boolean supportRaw = false;
2495         for (int format : outputFormats) {
2496             if (format == ImageFormat.RAW_SENSOR || format == ImageFormat.RAW10 ||
2497                     format == ImageFormat.RAW12 || format == ImageFormat.RAW_PRIVATE) {
2498                 supportRaw = true;
2499                 break;
2500             }
2501         }
2502         if (supportRaw) {
2503             mCollector.expectKeyValueEquals(request,
2504                     CONTROL_POST_RAW_SENSITIVITY_BOOST,
2505                     DEFAULT_POST_RAW_SENSITIVITY_BOOST);
2506         }
2507 
2508         switch(template) {
2509             case CameraDevice.TEMPLATE_PREVIEW:
2510                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2511                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_PREVIEW);
2512                 break;
2513             case CameraDevice.TEMPLATE_STILL_CAPTURE:
2514                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2515                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
2516                 break;
2517             case CameraDevice.TEMPLATE_RECORD:
2518                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2519                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
2520                 break;
2521             case CameraDevice.TEMPLATE_VIDEO_SNAPSHOT:
2522                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2523                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
2524                 break;
2525             case CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG:
2526                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2527                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG);
2528                 break;
2529             case CameraDevice.TEMPLATE_MANUAL:
2530                 mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT,
2531                         CameraCharacteristics.CONTROL_CAPTURE_INTENT_MANUAL);
2532                 break;
2533             default:
2534                 // Skip unknown templates here
2535         }
2536 
2537         // Check distortion correction mode
2538         if (mStaticInfo.isDistortionCorrectionSupported()) {
2539             mCollector.expectKeyValueNotEquals(request, DISTORTION_CORRECTION_MODE,
2540                     CaptureRequest.DISTORTION_CORRECTION_MODE_OFF);
2541         }
2542 
2543         // Scaler settings
2544         if (mStaticInfo.areKeysAvailable(
2545                 CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)) {
2546             List<Integer> rotateAndCropModes = Arrays.asList(toObject(
2547                 props.get(CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)));
2548             if (rotateAndCropModes.contains(SCALER_ROTATE_AND_CROP_AUTO)) {
2549                 mCollector.expectKeyValueEquals(request, SCALER_ROTATE_AND_CROP,
2550                         CaptureRequest.SCALER_ROTATE_AND_CROP_AUTO);
2551             }
2552         }
2553 
2554         // Check JPEG quality
2555         if (mStaticInfo.isColorOutputSupported()) {
2556             mCollector.expectKeyValueNotNull(request, JPEG_QUALITY);
2557         }
2558 
2559         // TODO: use the list of keys from CameraCharacteristics to avoid expecting
2560         //       keys which are not available by this CameraDevice.
2561     }
2562 
captureTemplateTestByCamera(String cameraId, int template)2563     private void captureTemplateTestByCamera(String cameraId, int template) throws Exception {
2564         try {
2565             openDevice(cameraId, mCameraMockListener);
2566 
2567             assertTrue("Camera template " + template + " is out of range!",
2568                     template >= CameraDevice.TEMPLATE_PREVIEW
2569                             && template <= CameraDevice.TEMPLATE_MANUAL);
2570 
2571             mCollector.setCameraId(cameraId);
2572 
2573             try {
2574                 CaptureRequest.Builder request = mCamera.createCaptureRequest(template);
2575                 assertNotNull("Failed to create capture request for template " + template, request);
2576 
2577                 CameraCharacteristics props = mStaticInfo.getCharacteristics();
2578                 checkRequestForTemplate(request, template, props);
2579             } catch (IllegalArgumentException e) {
2580                 if (template == CameraDevice.TEMPLATE_MANUAL &&
2581                         !mStaticInfo.isCapabilitySupported(CameraCharacteristics.
2582                                 REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
2583                     // OK
2584                 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG &&
2585                         !mStaticInfo.isCapabilitySupported(CameraCharacteristics.
2586                                 REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)) {
2587                     // OK.
2588                 } else if (sLegacySkipTemplates.contains(template) &&
2589                         mStaticInfo.isHardwareLevelLegacy()) {
2590                     // OK
2591                 } else if (template != CameraDevice.TEMPLATE_PREVIEW &&
2592                         mStaticInfo.isDepthOutputSupported() &&
2593                         !mStaticInfo.isColorOutputSupported()) {
2594                     // OK, depth-only devices need only support PREVIEW template
2595                 } else {
2596                     throw e; // rethrow
2597                 }
2598             }
2599         }
2600         finally {
2601             try {
2602                 closeSession();
2603             } finally {
2604                 closeDevice(cameraId, mCameraMockListener);
2605             }
2606         }
2607     }
2608 
2609     /**
2610      * Start capture with given {@link #CaptureRequest}.
2611      *
2612      * @param request The {@link #CaptureRequest} to be captured.
2613      * @param repeating If the capture is single capture or repeating.
2614      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
2615      * @param handler The handler camera device used to post callbacks.
2616      */
2617     @Override
startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Handler handler)2618     protected void startCapture(CaptureRequest request, boolean repeating,
2619             CameraCaptureSession.CaptureCallback listener, Handler handler)
2620                     throws CameraAccessException {
2621         if (VERBOSE) Log.v(TAG, "Starting capture from session");
2622 
2623         if (repeating) {
2624             mSession.setRepeatingRequest(request, listener, handler);
2625         } else {
2626             mSession.capture(request, listener, handler);
2627         }
2628     }
2629 
2630     /**
2631      * Start capture with given {@link #CaptureRequest}.
2632      *
2633      * @param request The {@link #CaptureRequest} to be captured.
2634      * @param repeating If the capture is single capture or repeating.
2635      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
2636      * @param executor The executor used to invoke callbacks.
2637      */
startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Executor executor)2638     protected void startCapture(CaptureRequest request, boolean repeating,
2639             CameraCaptureSession.CaptureCallback listener, Executor executor)
2640                     throws CameraAccessException {
2641         if (VERBOSE) Log.v(TAG, "Starting capture from session");
2642 
2643         if (repeating) {
2644             mSession.setSingleRepeatingRequest(request, executor, listener);
2645         } else {
2646             mSession.captureSingleRequest(request, executor, listener);
2647         }
2648     }
2649 
2650     /**
2651      * Close a {@link #CameraCaptureSession capture session}; blocking until
2652      * the close finishes with a transition to {@link CameraCaptureSession.StateCallback#onClosed}.
2653      */
closeSession()2654     protected void closeSession() {
2655         if (mSession == null) {
2656             return;
2657         }
2658 
2659         mSession.close();
2660         waitForSessionState(SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS);
2661         mSession = null;
2662 
2663         mSessionMockListener = null;
2664         mSessionWaiter = null;
2665     }
2666 
2667     /**
2668      * A camera capture session listener that keeps all the configured and closed sessions.
2669      */
2670     private class MultipleSessionCallback extends CameraCaptureSession.StateCallback {
2671         public static final int SESSION_CONFIGURED = 0;
2672         public static final int SESSION_CLOSED = 1;
2673 
2674         final List<CameraCaptureSession> mSessions = new ArrayList<>();
2675         final Map<CameraCaptureSession, Integer> mSessionStates = new HashMap<>();
2676         CameraCaptureSession mCurrentConfiguredSession = null;
2677 
2678         final ReentrantLock mLock = new ReentrantLock();
2679         final Condition mNewStateCond = mLock.newCondition();
2680 
2681         final boolean mFailOnConfigureFailed;
2682 
2683         /**
2684          * If failOnConfigureFailed is true, it calls fail() when onConfigureFailed() is invoked
2685          * for any session.
2686          */
MultipleSessionCallback(boolean failOnConfigureFailed)2687         public MultipleSessionCallback(boolean failOnConfigureFailed) {
2688             mFailOnConfigureFailed = failOnConfigureFailed;
2689         }
2690 
2691         @Override
onClosed(CameraCaptureSession session)2692         public void onClosed(CameraCaptureSession session) {
2693             mLock.lock();
2694             mSessionStates.put(session, SESSION_CLOSED);
2695             mNewStateCond.signal();
2696             mLock.unlock();
2697         }
2698 
2699         @Override
onConfigured(CameraCaptureSession session)2700         public void onConfigured(CameraCaptureSession session) {
2701             mLock.lock();
2702             mSessions.add(session);
2703             mSessionStates.put(session, SESSION_CONFIGURED);
2704             mNewStateCond.signal();
2705             mLock.unlock();
2706         }
2707 
2708         @Override
onConfigureFailed(CameraCaptureSession session)2709         public void onConfigureFailed(CameraCaptureSession session) {
2710             if (mFailOnConfigureFailed) {
2711                 fail("Configuring a session failed");
2712             }
2713         }
2714 
2715         /**
2716          * Get a number of sessions that have been configured.
2717          */
getAllSessions(int numSessions, int timeoutMs)2718         public List<CameraCaptureSession> getAllSessions(int numSessions, int timeoutMs)
2719                 throws Exception {
2720             long remainingTime = timeoutMs;
2721             mLock.lock();
2722             try {
2723                 while (mSessions.size() < numSessions) {
2724                     long startTime = SystemClock.elapsedRealtime();
2725                     boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
2726                     remainingTime -= (SystemClock.elapsedRealtime() - startTime);
2727                     ret &= remainingTime > 0;
2728 
2729                     assertTrue("Get " + numSessions + " sessions timed out after " + timeoutMs +
2730                             "ms", ret);
2731                 }
2732 
2733                 return mSessions;
2734             } finally {
2735                 mLock.unlock();
2736             }
2737         }
2738 
2739         /**
2740          * Wait until a previously-configured sessoin is closed or it times out.
2741          */
waitForSessionClose(CameraCaptureSession session, int timeoutMs)2742         public void waitForSessionClose(CameraCaptureSession session, int timeoutMs) throws Exception {
2743             long remainingTime = timeoutMs;
2744             mLock.lock();
2745             try {
2746                 while (mSessionStates.get(session).equals(SESSION_CLOSED) == false) {
2747                     long startTime = SystemClock.elapsedRealtime();
2748                     boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
2749                     remainingTime -= (SystemClock.elapsedRealtime() - startTime);
2750                     ret &= remainingTime > 0;
2751 
2752                     assertTrue("Wait for session close timed out after " + timeoutMs + "ms", ret);
2753                 }
2754             } finally {
2755                 mLock.unlock();
2756             }
2757         }
2758     }
2759 
2760     /**
2761      * Verify audio restrictions are set properly for single CameraDevice usage
2762      */
2763     @Test
testAudioRestrictionSingleDevice()2764     public void testAudioRestrictionSingleDevice() throws Exception {
2765         int[] testModes = {
2766             CameraDevice.AUDIO_RESTRICTION_VIBRATION_SOUND,
2767             CameraDevice.AUDIO_RESTRICTION_NONE,
2768             CameraDevice.AUDIO_RESTRICTION_VIBRATION,
2769         };
2770 
2771         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
2772         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
2773             try {
2774                 openDevice(cameraIdsUnderTest[i], mCameraMockListener);
2775                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
2776 
2777                 for (int mode : testModes) {
2778                     mCamera.setCameraAudioRestriction(mode);
2779                     int retMode = mCamera.getCameraAudioRestriction();
2780                     assertTrue("Audio restriction mode mismatch: input: " + mode +
2781                             ", output:" + retMode, mode == retMode);
2782                 }
2783 
2784                 try {
2785                     // Test invalid mode
2786                     mCamera.setCameraAudioRestriction(42);
2787                     fail("Should get IllegalArgumentException for invalid mode");
2788                 } catch (IllegalArgumentException e) {
2789                     // expected
2790                 }
2791             }
2792             finally {
2793                 closeDevice(cameraIdsUnderTest[i], mCameraMockListener);
2794             }
2795         }
2796     }
2797 
testTwoCameraDevicesAudioRestriction(String id0, String id1)2798     private void testTwoCameraDevicesAudioRestriction(String id0, String id1) throws Exception {
2799         BlockingStateCallback cam0Cb = new BlockingStateCallback();
2800         BlockingStateCallback cam1Cb = new BlockingStateCallback();
2801         CameraDevice cam0 = null;
2802         CameraDevice cam1 = null;
2803         try {
2804             cam0 = CameraTestUtils.openCamera(mCameraManager, id0, cam0Cb, mHandler);
2805             cam0Cb.waitForState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
2806 
2807             int mode0 = CameraDevice.AUDIO_RESTRICTION_VIBRATION_SOUND;
2808             cam0.setCameraAudioRestriction(mode0);
2809             int retMode = cam0.getCameraAudioRestriction();
2810             assertTrue("Audio restriction mode mismatch: input: " + mode0 + ", output:" + retMode,
2811                     retMode == mode0);
2812 
2813             try {
2814                 cam1 = CameraTestUtils.openCamera(mCameraManager, id1, cam1Cb, mHandler);
2815             } catch (CameraAccessException | BlockingOpenException e) {
2816                 Log.i(TAG, "Camera " + id1 + "cannot be opened along with camera " + id0 +
2817                         ", skipping the test");
2818                 return;
2819             }
2820             cam1Cb.waitForState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
2821 
2822             // See if cam0 is evicted.
2823             try {
2824                 final int cameraEvictedTimeoutMs = 1000;
2825                 cam0Cb.waitForState(STATE_DISCONNECTED, cameraEvictedTimeoutMs);
2826                 fail("Opened camera " + id0 + " is evicted by a later open call for camera " +
2827                         id1 + " from the same process");
2828             } catch (TimeoutRuntimeException e) {
2829                 // camera 0 is not evicted
2830             }
2831 
2832             // The output mode should be union of all CameraDevices
2833             int mode1 = CameraDevice.AUDIO_RESTRICTION_VIBRATION;
2834             int expectMode = mode0 | mode1;
2835             cam1.setCameraAudioRestriction(mode1);
2836             retMode = cam1.getCameraAudioRestriction();
2837             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2838                     ", output:" + retMode, retMode == expectMode);
2839 
2840             // test turning off mute settings also
2841             mode0 = CameraDevice.AUDIO_RESTRICTION_NONE;
2842             expectMode = mode0 | mode1;
2843             cam0.setCameraAudioRestriction(mode0);
2844             retMode = cam0.getCameraAudioRestriction();
2845             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2846                     ", output:" + retMode, retMode == expectMode);
2847 
2848             // mode should be NONE when both device set to NONE
2849             mode1 = CameraDevice.AUDIO_RESTRICTION_NONE;
2850             expectMode = mode0 | mode1;
2851             cam1.setCameraAudioRestriction(mode1);
2852             retMode = cam1.getCameraAudioRestriction();
2853             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2854                     ", output:" + retMode, retMode == expectMode);
2855 
2856             // test removal of VIBRATE won't affect existing VIBRATE_SOUND state
2857             mode0 = CameraDevice.AUDIO_RESTRICTION_VIBRATION_SOUND;
2858             expectMode = mode0 | mode1;
2859             cam0.setCameraAudioRestriction(mode0);
2860             retMode = cam0.getCameraAudioRestriction();
2861             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2862                     ", output:" + retMode, retMode == expectMode);
2863 
2864             mode1 = CameraDevice.AUDIO_RESTRICTION_VIBRATION;
2865             expectMode = mode0 | mode1;
2866             cam1.setCameraAudioRestriction(mode1);
2867             retMode = cam1.getCameraAudioRestriction();
2868             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2869                     ", output:" + retMode, retMode == expectMode);
2870 
2871             mode1 = CameraDevice.AUDIO_RESTRICTION_NONE;
2872             expectMode = mode0 | mode1;
2873             cam1.setCameraAudioRestriction(mode1);
2874             retMode = cam1.getCameraAudioRestriction();
2875             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2876                     ", output:" + retMode, retMode == expectMode);
2877 
2878             // Now test CameraDevice.close will remove setting and exception is thrown for closed
2879             // camera.
2880             cam0.close();
2881             cam0Cb.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
2882             try {
2883                 cam0.setCameraAudioRestriction(mode0);
2884                 fail("Should get IllegalStateException for closed camera.");
2885             } catch (IllegalStateException e) {
2886                 // expected;
2887             }
2888 
2889             cam0 = null;
2890             cam0Cb = null;
2891             expectMode = mode1;
2892             cam1.setCameraAudioRestriction(mode1);
2893             retMode = cam1.getCameraAudioRestriction();
2894             assertTrue("Audio restriction mode mismatch: expect: " + expectMode +
2895                     ", output:" + retMode, retMode == expectMode);
2896         } finally {
2897             if (cam0 != null) {
2898                 cam0.close();
2899                 cam0Cb.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
2900                 cam0Cb = null;
2901             }
2902             if (cam1 != null) {
2903                 cam1.close();
2904                 cam1Cb.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
2905                 cam1Cb = null;
2906             }
2907         }
2908     }
2909 
2910     @Test
testAudioRestrictionMultipleDevices()2911     public void testAudioRestrictionMultipleDevices() throws Exception {
2912         String[] cameraIdsUnderTest = getCameraIdsUnderTest();
2913         if (cameraIdsUnderTest.length < 2) {
2914             Log.i(TAG, "device doesn't have multiple cameras, skipping");
2915             return;
2916         }
2917 
2918         for (int i = 0; i < cameraIdsUnderTest.length; i++) {
2919             for (int j = i+1; j < cameraIdsUnderTest.length; j++) {
2920                 testTwoCameraDevicesAudioRestriction(cameraIdsUnderTest[i], cameraIdsUnderTest[j]);
2921             }
2922         }
2923     }
2924 }
2925