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