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