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.testcases.Camera2AndroidTestCase;
39 import android.hardware.camera2.params.MeteringRectangle;
40 import android.media.ImageReader;
41 import android.os.Handler;
42 import android.os.SystemClock;
43 import android.util.Log;
44 import android.util.Range;
45 import android.view.Surface;
46 
47 import com.android.ex.camera2.blocking.BlockingSessionCallback;
48 import com.android.ex.camera2.blocking.BlockingStateCallback;
49 import com.android.ex.camera2.utils.StateWaiter;
50 
51 import org.mockito.ArgumentMatcher;
52 
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.concurrent.locks.Condition;
56 import java.util.concurrent.locks.Lock;
57 import java.util.concurrent.locks.ReentrantLock;
58 import java.util.HashSet;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.HashMap;
62 import java.util.Set;
63 import android.util.Size;
64 import java.util.concurrent.LinkedBlockingQueue;
65 import java.util.concurrent.TimeUnit;
66 
67 /**
68  * <p>Basic test for CameraDevice APIs.</p>
69  */
70 public class CameraDeviceTest extends Camera2AndroidTestCase {
71     private static final String TAG = "CameraDeviceTest";
72     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
73     private static final int ERROR_LISTENER_WAIT_TIMEOUT_MS = 1000;
74     private static final int REPEATING_CAPTURE_EXPECTED_RESULT_COUNT = 5;
75     private static final int MAX_NUM_IMAGES = 5;
76     private static final int MIN_FPS_REQUIRED_FOR_STREAMING = 20;
77     private static final int DEFAULT_POST_RAW_SENSITIVITY_BOOST = 100;
78 
79     private CameraCaptureSession mSession;
80 
81     private BlockingStateCallback mCameraMockListener;
82     private int mLatestDeviceState = STATE_UNINITIALIZED;
83     private BlockingSessionCallback mSessionMockListener;
84     private StateWaiter mSessionWaiter;
85     private int mLatestSessionState = -1; // uninitialized
86 
87     private static int[] sTemplates = new int[] {
88             CameraDevice.TEMPLATE_PREVIEW,
89             CameraDevice.TEMPLATE_RECORD,
90             CameraDevice.TEMPLATE_STILL_CAPTURE,
91             CameraDevice.TEMPLATE_VIDEO_SNAPSHOT
92     };
93 
94     private static int[] sInvalidTemplates = new int[] {
95             CameraDevice.TEMPLATE_PREVIEW - 1,
96             CameraDevice.TEMPLATE_MANUAL + 1,
97     };
98 
99     // Request templates that are unsupported by LEGACY mode.
100     private static Set<Integer> sLegacySkipTemplates = new HashSet<>();
101     static {
102         sLegacySkipTemplates.add(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
103         sLegacySkipTemplates.add(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
104         sLegacySkipTemplates.add(CameraDevice.TEMPLATE_MANUAL);
105     }
106 
107     @Override
setContext(Context context)108     public void setContext(Context context) {
109         super.setContext(context);
110 
111         /**
112          * Workaround for mockito and JB-MR2 incompatibility
113          *
114          * Avoid java.lang.IllegalArgumentException: dexcache == null
115          * https://code.google.com/p/dexmaker/issues/detail?id=2
116          */
117         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
118 
119         /**
120          * Create error listener in context scope, to catch asynchronous device error.
121          * Use spy object here since we want to use the SimpleDeviceListener callback
122          * implementation (spy doesn't stub the functions unless we ask it to do so).
123          */
124         mCameraMockListener = spy(new BlockingStateCallback());
125     }
126 
127     @Override
setUp()128     protected void setUp() throws Exception {
129         super.setUp();
130         /**
131          * Due to the asynchronous nature of camera device error callback, we
132          * have to make sure device doesn't run into error state before. If so,
133          * fail the rest of the tests. This is especially needed when error
134          * callback is fired too late.
135          */
136         verify(mCameraMockListener, never())
137                 .onError(
138                     any(CameraDevice.class),
139                     anyInt());
140         verify(mCameraMockListener, never())
141                 .onDisconnected(
142                     any(CameraDevice.class));
143 
144         mCameraListener = mCameraMockListener;
145         createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
146                 new ImageDropperListener());
147     }
148 
149     @Override
tearDown()150     protected void tearDown() throws Exception {
151         super.tearDown();
152     }
153 
154     /**
155      * <p>
156      * Test camera capture request preview capture template.
157      * </p>
158      *
159      * <p>
160      * The request template returned by the camera device must include a
161      * necessary set of metadata keys, and their values must be set correctly.
162      * It mainly requires below settings:
163      * </p>
164      * <ul>
165      * <li>All 3A settings are auto.</li>
166      * <li>All sensor settings are not null.</li>
167      * <li>All ISP processing settings should be non-manual, and the camera
168      * device should make sure the stable frame rate is guaranteed for the given
169      * settings.</li>
170      * </ul>
171      */
testCameraDevicePreviewTemplate()172     public void testCameraDevicePreviewTemplate() throws Exception {
173         for (int i = 0; i < mCameraIds.length; i++) {
174             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_PREVIEW);
175         }
176 
177         // TODO: test the frame rate sustainability in preview use case test.
178     }
179 
180     /**
181      * <p>
182      * Test camera capture request still capture template.
183      * </p>
184      *
185      * <p>
186      * The request template returned by the camera device must include a
187      * necessary set of metadata keys, and their values must be set correctly.
188      * It mainly requires below settings:
189      * </p>
190      * <ul>
191      * <li>All 3A settings are auto.</li>
192      * <li>All sensor settings are not null.</li>
193      * <li>All ISP processing settings should be non-manual, and the camera
194      * device should make sure the high quality takes priority to the stable
195      * frame rate for the given settings.</li>
196      * </ul>
197      */
testCameraDeviceStillTemplate()198     public void testCameraDeviceStillTemplate() throws Exception {
199         for (int i = 0; i < mCameraIds.length; i++) {
200             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_STILL_CAPTURE);
201         }
202     }
203 
204     /**
205      * <p>
206      * Test camera capture video recording template.
207      * </p>
208      *
209      * <p>
210      * The request template returned by the camera device must include a
211      * necessary set of metadata keys, and their values must be set correctly.
212      * It has the similar requirement as preview, with one difference:
213      * </p>
214      * <ul>
215      * <li>Frame rate should be stable, for example, wide fps range like [7, 30]
216      * is a bad setting.</li>
217      */
testCameraDeviceRecordingTemplate()218     public void testCameraDeviceRecordingTemplate() throws Exception {
219         for (int i = 0; i < mCameraIds.length; i++) {
220             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_RECORD);
221         }
222 
223         // TODO: test the frame rate sustainability in recording use case test.
224     }
225 
226     /**
227      *<p>Test camera capture video snapshot template.</p>
228      *
229      * <p>The request template returned by the camera device must include a necessary set of
230      * metadata keys, and their values must be set correctly. It has the similar requirement
231      * as recording, with an additional requirement: the settings should maximize image quality
232      * without compromising stable frame rate.</p>
233      */
testCameraDeviceVideoSnapShotTemplate()234     public void testCameraDeviceVideoSnapShotTemplate() throws Exception {
235         for (int i = 0; i < mCameraIds.length; i++) {
236             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
237         }
238 
239         // TODO: test the frame rate sustainability in video snapshot use case test.
240     }
241 
242     /**
243      *<p>Test camera capture request zero shutter lag template.</p>
244      *
245      * <p>The request template returned by the camera device must include a necessary set of
246      * metadata keys, and their values must be set correctly. It has the similar requirement
247      * as preview, with an additional requirement: </p>
248      */
testCameraDeviceZSLTemplate()249     public void testCameraDeviceZSLTemplate() throws Exception {
250         for (int i = 0; i < mCameraIds.length; i++) {
251             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
252         }
253     }
254 
255     /**
256      * <p>
257      * Test camera capture request manual template.
258      * </p>
259      *
260      * <p>
261      * The request template returned by the camera device must include a
262      * necessary set of metadata keys, and their values must be set correctly. It
263      * mainly requires below settings:
264      * </p>
265      * <ul>
266      * <li>All 3A settings are manual.</li>
267      * <li>ISP processing parameters are set to preview quality.</li>
268      * <li>The manual capture parameters (exposure, sensitivity, and so on) are
269      * set to reasonable defaults.</li>
270      * </ul>
271      */
testCameraDeviceManualTemplate()272     public void testCameraDeviceManualTemplate() throws Exception {
273         for (int i = 0; i < mCameraIds.length; i++) {
274             captureTemplateTestByCamera(mCameraIds[i], CameraDevice.TEMPLATE_MANUAL);
275         }
276     }
277 
testCameraDeviceCreateCaptureBuilder()278     public void testCameraDeviceCreateCaptureBuilder() throws Exception {
279         for (int i = 0; i < mCameraIds.length; i++) {
280             try {
281                 openDevice(mCameraIds[i], mCameraMockListener);
282                 /**
283                  * Test: that each template type is supported, and that its required fields are
284                  * present.
285                  */
286                 for (int j = 0; j < sTemplates.length; j++) {
287                     // Skip video snapshots for LEGACY mode
288                     if (mStaticInfo.isHardwareLevelLegacy() &&
289                             sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
290                         continue;
291                     }
292                     // Skip non-PREVIEW templates for non-color output
293                     if (!mStaticInfo.isColorOutputSupported() &&
294                             sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
295                         continue;
296                     }
297                     CaptureRequest.Builder capReq = mCamera.createCaptureRequest(sTemplates[j]);
298                     assertNotNull("Failed to create capture request", capReq);
299                     if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_EXPOSURE_TIME)) {
300                         assertNotNull("Missing field: SENSOR_EXPOSURE_TIME",
301                                 capReq.get(CaptureRequest.SENSOR_EXPOSURE_TIME));
302                     }
303                     if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_SENSITIVITY)) {
304                         assertNotNull("Missing field: SENSOR_SENSITIVITY",
305                                 capReq.get(CaptureRequest.SENSOR_SENSITIVITY));
306                     }
307                 }
308 
309                 /**
310                  * Test: creating capture requests with an invalid template ID should throw
311                  * IllegalArgumentException.
312                  */
313                 for (int j = 0; j < sInvalidTemplates.length; j++) {
314                     try {
315                         CaptureRequest.Builder capReq =
316                                 mCamera.createCaptureRequest(sInvalidTemplates[j]);
317                         fail("Should get IllegalArgumentException due to an invalid template ID.");
318                     } catch (IllegalArgumentException e) {
319                         // Expected exception.
320                     }
321                 }
322             }
323             finally {
324                 try {
325                     closeSession();
326                 } finally {
327                     closeDevice(mCameraIds[i], mCameraMockListener);
328                 }
329             }
330         }
331     }
332 
testCameraDeviceSetErrorListener()333     public void testCameraDeviceSetErrorListener() throws Exception {
334         for (int i = 0; i < mCameraIds.length; i++) {
335             try {
336                 openDevice(mCameraIds[i], mCameraMockListener);
337                 /**
338                  * Test: that the error listener can be set without problems.
339                  * Also, wait some time to check if device doesn't run into error.
340                  */
341                 SystemClock.sleep(ERROR_LISTENER_WAIT_TIMEOUT_MS);
342                 verify(mCameraMockListener, never())
343                         .onError(
344                                 any(CameraDevice.class),
345                                 anyInt());
346             }
347             finally {
348                 try {
349                     closeSession();
350                 } finally {
351                     closeDevice(mCameraIds[i], mCameraMockListener);
352                 }
353             }
354         }
355     }
356 
testCameraDeviceCapture()357     public void testCameraDeviceCapture() throws Exception {
358         runCaptureTest(/*burst*/false, /*repeating*/false, /*abort*/false);
359     }
360 
testCameraDeviceCaptureBurst()361     public void testCameraDeviceCaptureBurst() throws Exception {
362         runCaptureTest(/*burst*/true, /*repeating*/false, /*abort*/false);
363     }
364 
testCameraDeviceRepeatingRequest()365     public void testCameraDeviceRepeatingRequest() throws Exception {
366         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/false);
367     }
368 
testCameraDeviceRepeatingBurst()369     public void testCameraDeviceRepeatingBurst() throws Exception {
370         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/false);
371     }
372 
373     /**
374      * Test {@link android.hardware.camera2.CameraCaptureSession#abortCaptures} API.
375      *
376      * <p>Abort is the fastest way to idle the camera device for reconfiguration with
377      * {@link android.hardware.camera2.CameraCaptureSession#abortCaptures}, at the cost of
378      * discarding in-progress work. Once the abort is complete, the idle callback will be called.
379      * </p>
380      */
testCameraDeviceAbort()381     public void testCameraDeviceAbort() throws Exception {
382         runCaptureTest(/*burst*/false, /*repeating*/true, /*abort*/true);
383         runCaptureTest(/*burst*/true, /*repeating*/true, /*abort*/true);
384         /**
385          * TODO: this is only basic test of abort. we probably should also test below cases:
386          *
387          * 1. Performance. Make sure abort is faster than stopRepeating, we can test each one a
388          * couple of times, then compare the average. Also, for abortCaptures() alone, we should
389          * make sure it doesn't take too long time (e.g. <100ms for full devices, <500ms for limited
390          * devices), after the abort, we should be able to get all results back very quickly.  This
391          * can be done in performance test.
392          *
393          * 2. Make sure all in-flight request comes back after abort, e.g. submit a couple of
394          * long exposure single captures, then abort, then check if we can get the pending
395          * request back quickly.
396          *
397          * 3. Also need check onCaptureSequenceCompleted for repeating burst after abortCaptures().
398          */
399     }
400 
401     /**
402      * Test invalid capture (e.g. null or empty capture request).
403      */
testInvalidCapture()404     public void testInvalidCapture() throws Exception {
405         for (int i = 0; i < mCameraIds.length; i++) {
406             try {
407                 openDevice(mCameraIds[i], mCameraMockListener);
408                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
409 
410                 prepareCapture();
411 
412                 invalidRequestCaptureTestByCamera();
413 
414                 closeSession();
415             }
416             finally {
417                 closeDevice(mCameraIds[i], mCameraMockListener);
418             }
419         }
420     }
421 
422     /**
423      * Test to ensure that we can call camera2 API methods inside callbacks.
424      *
425      * Tests:
426      *  onOpened -> createCaptureSession, createCaptureRequest
427      *  onConfigured -> getDevice, abortCaptures,
428      *     createCaptureRequest, capture, setRepeatingRequest, stopRepeating
429      *  onCaptureCompleted -> createCaptureRequest, getDevice, abortCaptures,
430      *     capture, setRepeatingRequest, stopRepeating, session+device.close
431      */
testChainedOperation()432     public void testChainedOperation() throws Throwable {
433 
434         final ArrayList<Surface> outputs = new ArrayList<>();
435         outputs.add(mReaderSurface);
436 
437         // A queue for the chained listeners to push results to
438         // A success Throwable indicates no errors; other Throwables detail a test failure;
439         // nulls indicate timeouts.
440         final Throwable success = new Throwable("Success");
441         final LinkedBlockingQueue<Throwable> results = new LinkedBlockingQueue<>();
442 
443         // Define listeners
444         // A cascade of Device->Session->Capture listeners, each of which invokes at least one
445         // method on the camera device or session.
446 
447         class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback {
448             @Override
449             public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
450                     TotalCaptureResult result) {
451                 try {
452                     CaptureRequest.Builder request2 =
453                             session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
454                     request2.addTarget(mReaderSurface);
455 
456                     // Some calls to the camera for coverage
457                     session.abortCaptures();
458                     session.capture(request2.build(),
459                             /*listener*/ null, /*handler*/ null);
460                     session.setRepeatingRequest(request2.build(),
461                             /*listener*/ null, /*handler*/ null);
462                     session.stopRepeating();
463 
464                     CameraDevice camera = session.getDevice();
465                     session.close();
466                     camera.close();
467 
468                     results.offer(success);
469                 } catch (Throwable t) {
470                     results.offer(t);
471                 }
472             }
473 
474             @Override
475             public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
476                     CaptureFailure failure) {
477                 try {
478                     CameraDevice camera = session.getDevice();
479                     session.close();
480                     camera.close();
481                     fail("onCaptureFailed invoked with failure reason: " + failure.getReason());
482                 } catch (Throwable t) {
483                     results.offer(t);
484                 }
485             }
486         }
487 
488         class ChainedSessionListener extends CameraCaptureSession.StateCallback {
489             private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback();
490 
491             @Override
492             public void onConfigured(CameraCaptureSession session) {
493                 try {
494                     CaptureRequest.Builder request =
495                             session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
496                     request.addTarget(mReaderSurface);
497                     // Some calls to the camera for coverage
498                     session.getDevice();
499                     session.abortCaptures();
500                     // The important call for the next level of chaining
501                     session.capture(request.build(), mCaptureCallback, mHandler);
502                     // Some more calls
503                     session.setRepeatingRequest(request.build(),
504                             /*listener*/ null, /*handler*/ null);
505                     session.stopRepeating();
506                     results.offer(success);
507                 } catch (Throwable t) {
508                     results.offer(t);
509                 }
510             }
511 
512             @Override
513             public void onConfigureFailed(CameraCaptureSession session) {
514                 try {
515                     CameraDevice camera = session.getDevice();
516                     session.close();
517                     camera.close();
518                     fail("onConfigureFailed was invoked");
519                 } catch (Throwable t) {
520                     results.offer(t);
521                 }
522             }
523         }
524 
525         class ChainedCameraListener extends CameraDevice.StateCallback {
526             private final ChainedSessionListener mSessionListener = new ChainedSessionListener();
527 
528             public CameraDevice cameraDevice;
529 
530             @Override
531             public void onOpened(CameraDevice camera) {
532 
533                 cameraDevice = camera;
534                 try {
535                     // Some calls for coverage
536                     camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
537                     // The important call for next level of chaining
538                     camera.createCaptureSession(outputs, mSessionListener, mHandler);
539                     results.offer(success);
540                 } catch (Throwable t) {
541                     try {
542                         camera.close();
543                         results.offer(t);
544                     } catch (Throwable t2) {
545                         Log.e(TAG,
546                                 "Second failure reached; discarding first exception with trace " +
547                                 Log.getStackTraceString(t));
548                         results.offer(t2);
549                     }
550                 }
551             }
552 
553             @Override
554             public void onDisconnected(CameraDevice camera) {
555                 try {
556                     camera.close();
557                     fail("onDisconnected invoked");
558                 } catch (Throwable t) {
559                     results.offer(t);
560                 }
561             }
562 
563             @Override
564             public void onError(CameraDevice camera, int error) {
565                 try {
566                     camera.close();
567                     fail("onError invoked with error code: " + error);
568                 } catch (Throwable t) {
569                     results.offer(t);
570                 }
571             }
572         }
573 
574         // Actual test code
575 
576         for (int i = 0; i < mCameraIds.length; i++) {
577             Throwable result;
578 
579             if (!(new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraIds[i]))).
580                     isColorOutputSupported()) {
581                 Log.i(TAG, "Camera " + mCameraIds[i] + " does not support color outputs, skipping");
582                 continue;
583             }
584 
585             // Start chained cascade
586             ChainedCameraListener cameraListener = new ChainedCameraListener();
587             mCameraManager.openCamera(mCameraIds[i], cameraListener, mHandler);
588 
589             // Check if open succeeded
590             result = results.poll(CAMERA_OPEN_TIMEOUT_MS, TimeUnit.MILLISECONDS);
591             if (result != success) {
592                 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
593                 if (result == null) {
594                     fail("Timeout waiting for camera open");
595                 } else {
596                     throw result;
597                 }
598             }
599 
600             // Check if configure succeeded
601             result = results.poll(SESSION_CONFIGURE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
602             if (result != success) {
603                 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
604                 if (result == null) {
605                     fail("Timeout waiting for session configure");
606                 } else {
607                     throw result;
608                 }
609             }
610 
611             // Check if capture succeeded
612             result = results.poll(CAPTURE_RESULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
613             if (result != success) {
614                 if (cameraListener.cameraDevice != null) cameraListener.cameraDevice.close();
615                 if (result == null) {
616                     fail("Timeout waiting for capture completion");
617                 } else {
618                     throw result;
619                 }
620             }
621         }
622     }
623 
624     /**
625      * Verify basic semantics and error conditions of the prepare call.
626      *
627      */
testPrepare()628     public void testPrepare() throws Exception {
629         for (int i = 0; i < mCameraIds.length; i++) {
630             try {
631                 openDevice(mCameraIds[i], mCameraMockListener);
632                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
633                 if (!mStaticInfo.isColorOutputSupported()) {
634                     Log.i(TAG, "Camera " + mCameraIds[i] +
635                             " does not support color outputs, skipping");
636                     continue;
637                 }
638 
639                 prepareTestByCamera();
640             }
641             finally {
642                 closeDevice(mCameraIds[i], mCameraMockListener);
643             }
644         }
645     }
646 
647     /**
648      * Verify creating sessions back to back.
649      */
testCreateSessions()650     public void testCreateSessions() throws Exception {
651         for (int i = 0; i < mCameraIds.length; i++) {
652             try {
653                 openDevice(mCameraIds[i], mCameraMockListener);
654                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
655                 if (!mStaticInfo.isColorOutputSupported()) {
656                     Log.i(TAG, "Camera " + mCameraIds[i] +
657                             " does not support color outputs, skipping");
658                     continue;
659                 }
660 
661                 testCreateSessionsByCamera(mCameraIds[i]);
662             }
663             finally {
664                 closeDevice(mCameraIds[i], mCameraMockListener);
665             }
666         }
667     }
668 
669     /**
670      * Verify creating sessions back to back and only the last one is valid for
671      * submitting requests.
672      */
testCreateSessionsByCamera(String cameraId)673     private void testCreateSessionsByCamera(String cameraId) throws Exception {
674         final int NUM_SESSIONS = 3;
675         final int SESSION_TIMEOUT_MS = 1000;
676         final int CAPTURE_TIMEOUT_MS = 3000;
677 
678         if (VERBOSE) {
679             Log.v(TAG, "Testing creating sessions for camera " + cameraId);
680         }
681 
682         Size yuvSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.YUV_420_888,
683                 /*bound*/null).get(0);
684         Size jpegSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.JPEG,
685                 /*bound*/null).get(0);
686 
687         // Create a list of image readers. JPEG for last one and YUV for the rest.
688         List<ImageReader> imageReaders = new ArrayList<>();
689         List<CameraCaptureSession> allSessions = new ArrayList<>();
690 
691         try {
692             for (int i = 0; i < NUM_SESSIONS - 1; i++) {
693                 imageReaders.add(ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(),
694                         ImageFormat.YUV_420_888, /*maxImages*/1));
695             }
696             imageReaders.add(ImageReader.newInstance(jpegSize.getWidth(), jpegSize.getHeight(),
697                     ImageFormat.JPEG, /*maxImages*/1));
698 
699             // Create multiple sessions back to back.
700             MultipleSessionCallback sessionListener =
701                     new MultipleSessionCallback(/*failOnConfigureFailed*/true);
702             for (int i = 0; i < NUM_SESSIONS; i++) {
703                 List<Surface> outputs = new ArrayList<>();
704                 outputs.add(imageReaders.get(i).getSurface());
705                 mCamera.createCaptureSession(outputs, sessionListener, mHandler);
706             }
707 
708             // Verify we get onConfigured() for all sessions.
709             allSessions = sessionListener.getAllSessions(NUM_SESSIONS,
710                     SESSION_TIMEOUT_MS * NUM_SESSIONS);
711             assertEquals(String.format("Got %d sessions but configured %d sessions",
712                     allSessions.size(), NUM_SESSIONS), allSessions.size(), NUM_SESSIONS);
713 
714             // Verify all sessions except the last one are closed.
715             for (int i = 0; i < NUM_SESSIONS - 1; i++) {
716                 sessionListener.waitForSessionClose(allSessions.get(i), SESSION_TIMEOUT_MS);
717             }
718 
719             // Verify we can capture a frame with the last session.
720             CameraCaptureSession session = allSessions.get(allSessions.size() - 1);
721             SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
722             ImageReader reader = imageReaders.get(imageReaders.size() - 1);
723             SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
724             reader.setOnImageAvailableListener(imageListener, mHandler);
725 
726             CaptureRequest.Builder builder =
727                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
728             builder.addTarget(reader.getSurface());
729             CaptureRequest request = builder.build();
730 
731             session.capture(request, captureListener, mHandler);
732             captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS);
733             imageListener.getImage(CAPTURE_TIMEOUT_MS).close();
734         } finally {
735             for (ImageReader reader : imageReaders) {
736                 reader.close();
737             }
738             for (CameraCaptureSession session : allSessions) {
739                 session.close();
740             }
741         }
742     }
743 
prepareTestByCamera()744     private void prepareTestByCamera() throws Exception {
745         final int PREPARE_TIMEOUT_MS = 10000;
746 
747         mSessionMockListener = spy(new BlockingSessionCallback());
748 
749         SurfaceTexture output1 = new SurfaceTexture(1);
750         Surface output1Surface = new Surface(output1);
751         SurfaceTexture output2 = new SurfaceTexture(2);
752         Surface output2Surface = new Surface(output2);
753 
754         List<Surface> outputSurfaces = new ArrayList<>(
755             Arrays.asList(output1Surface, output2Surface));
756         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
757 
758         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
759 
760         // Try basic prepare
761 
762         mSession.prepare(output1Surface);
763 
764         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
765                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
766 
767         // Should not complain if preparing already prepared stream
768 
769         mSession.prepare(output1Surface);
770 
771         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(2))
772                 .onSurfacePrepared(eq(mSession), eq(output1Surface));
773 
774         // Check surface not included in session
775 
776         SurfaceTexture output3 = new SurfaceTexture(3);
777         Surface output3Surface = new Surface(output3);
778         try {
779             mSession.prepare(output3Surface);
780             // Legacy camera prepare always succeed
781             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
782                 fail("Preparing surface not part of session must throw IllegalArgumentException");
783             }
784         } catch (IllegalArgumentException e) {
785             // expected
786         }
787 
788         // Ensure second prepare also works
789 
790         mSession.prepare(output2Surface);
791 
792         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
793                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
794 
795         // Use output1
796 
797         CaptureRequest.Builder r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
798         r.addTarget(output1Surface);
799 
800         mSession.capture(r.build(), null, null);
801 
802         try {
803             mSession.prepare(output1Surface);
804             // Legacy camera prepare always succeed
805             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
806                 fail("Preparing already-used surface must throw IllegalArgumentException");
807             }
808         } catch (IllegalArgumentException e) {
809             // expected
810         }
811 
812         // Create new session with outputs 1 and 3, ensure output1Surface still can't be prepared
813         // again
814 
815         mSessionMockListener = spy(new BlockingSessionCallback());
816 
817         outputSurfaces = new ArrayList<>(
818             Arrays.asList(output1Surface, output3Surface));
819         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
820 
821         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
822 
823         try {
824             mSession.prepare(output1Surface);
825             // Legacy camera prepare always succeed
826             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
827                 fail("Preparing surface used in previous session must throw " +
828                         "IllegalArgumentException");
829             }
830         } catch (IllegalArgumentException e) {
831             // expected
832         }
833 
834         // Use output3, wait for result, then make sure prepare still doesn't work
835 
836         r = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
837         r.addTarget(output3Surface);
838 
839         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
840         mSession.capture(r.build(), resultListener, mHandler);
841 
842         resultListener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
843 
844         try {
845             mSession.prepare(output3Surface);
846             // Legacy camera prepare always succeed
847             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
848                 fail("Preparing already-used surface must throw IllegalArgumentException");
849             }
850         } catch (IllegalArgumentException e) {
851             // expected
852         }
853 
854         // Create new session with outputs 1 and 2, ensure output2Surface can be prepared again
855 
856         mSessionMockListener = spy(new BlockingSessionCallback());
857 
858         outputSurfaces = new ArrayList<>(
859             Arrays.asList(output1Surface, output2Surface));
860         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
861 
862         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
863 
864         mSession.prepare(output2Surface);
865 
866         verify(mSessionMockListener, timeout(PREPARE_TIMEOUT_MS).times(1))
867                 .onSurfacePrepared(eq(mSession), eq(output2Surface));
868 
869         try {
870             mSession.prepare(output1Surface);
871             // Legacy camera prepare always succeed
872             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
873                 fail("Preparing surface used in previous session must throw " +
874                         "IllegalArgumentException");
875             }
876         } catch (IllegalArgumentException e) {
877             // expected
878         }
879 
880     }
881 
882 
invalidRequestCaptureTestByCamera()883     private void invalidRequestCaptureTestByCamera() throws Exception {
884         if (VERBOSE) Log.v(TAG, "invalidRequestCaptureTestByCamera");
885 
886         List<CaptureRequest> emptyRequests = new ArrayList<CaptureRequest>();
887         CaptureRequest.Builder requestBuilder =
888                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
889         CaptureRequest unConfiguredRequest = requestBuilder.build();
890         List<CaptureRequest> unConfiguredRequests = new ArrayList<CaptureRequest>();
891         unConfiguredRequests.add(unConfiguredRequest);
892 
893         try {
894             // Test: CameraCaptureSession capture should throw IAE for null request.
895             mSession.capture(/*request*/null, /*listener*/null, mHandler);
896             mCollector.addMessage(
897                     "Session capture should throw IllegalArgumentException for null request");
898         } catch (IllegalArgumentException e) {
899             // Pass.
900         }
901 
902         try {
903             // Test: CameraCaptureSession capture should throw IAE for request
904             // without surface configured.
905             mSession.capture(unConfiguredRequest, /*listener*/null, mHandler);
906             mCollector.addMessage("Session capture should throw " +
907                     "IllegalArgumentException for request without surface configured");
908         } catch (IllegalArgumentException e) {
909             // Pass.
910         }
911 
912         try {
913             // Test: CameraCaptureSession setRepeatingRequest should throw IAE for null request.
914             mSession.setRepeatingRequest(/*request*/null, /*listener*/null, mHandler);
915             mCollector.addMessage("Session setRepeatingRequest should throw " +
916                     "IllegalArgumentException for null request");
917         } catch (IllegalArgumentException e) {
918             // Pass.
919         }
920 
921         try {
922             // Test: CameraCaptureSession setRepeatingRequest should throw IAE for for request
923             // without surface configured.
924             mSession.setRepeatingRequest(unConfiguredRequest, /*listener*/null, mHandler);
925             mCollector.addMessage("Capture zero burst should throw IllegalArgumentException " +
926                     "for request without surface configured");
927         } catch (IllegalArgumentException e) {
928             // Pass.
929         }
930 
931         try {
932             // Test: CameraCaptureSession captureBurst should throw IAE for null request list.
933             mSession.captureBurst(/*requests*/null, /*listener*/null, mHandler);
934             mCollector.addMessage("Session captureBurst should throw " +
935                     "IllegalArgumentException for null request list");
936         } catch (IllegalArgumentException e) {
937             // Pass.
938         }
939 
940         try {
941             // Test: CameraCaptureSession captureBurst should throw IAE for empty request list.
942             mSession.captureBurst(emptyRequests, /*listener*/null, mHandler);
943             mCollector.addMessage("Session captureBurst should throw " +
944                     " IllegalArgumentException for empty request list");
945         } catch (IllegalArgumentException e) {
946             // Pass.
947         }
948 
949         try {
950             // Test: CameraCaptureSession captureBurst should throw IAE for request
951             // without surface configured.
952             mSession.captureBurst(unConfiguredRequests, /*listener*/null, mHandler);
953             fail("Session captureBurst should throw IllegalArgumentException " +
954                     "for null request list");
955         } catch (IllegalArgumentException e) {
956             // Pass.
957         }
958 
959         try {
960             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for null request list.
961             mSession.setRepeatingBurst(/*requests*/null, /*listener*/null, mHandler);
962             mCollector.addMessage("Session setRepeatingBurst should throw " +
963                     "IllegalArgumentException for null request list");
964         } catch (IllegalArgumentException e) {
965             // Pass.
966         }
967 
968         try {
969             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for empty request list.
970             mSession.setRepeatingBurst(emptyRequests, /*listener*/null, mHandler);
971             mCollector.addMessage("Session setRepeatingBurst should throw " +
972                     "IllegalArgumentException for empty request list");
973         } catch (IllegalArgumentException e) {
974             // Pass.
975         }
976 
977         try {
978             // Test: CameraCaptureSession setRepeatingBurst should throw IAE for request
979             // without surface configured.
980             mSession.setRepeatingBurst(unConfiguredRequests, /*listener*/null, mHandler);
981             mCollector.addMessage("Session setRepeatingBurst should throw " +
982                     "IllegalArgumentException for request without surface configured");
983         } catch (IllegalArgumentException e) {
984             // Pass.
985         }
986     }
987 
988     private class IsCaptureResultNotEmpty
989             extends ArgumentMatcher<TotalCaptureResult> {
990         @Override
matches(Object obj)991         public boolean matches(Object obj) {
992             /**
993              * Do the simple verification here. Only verify the timestamp for now.
994              * TODO: verify more required capture result metadata fields.
995              */
996             TotalCaptureResult result = (TotalCaptureResult) obj;
997             Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
998             if (timeStamp != null && timeStamp.longValue() > 0L) {
999                 return true;
1000             }
1001             return false;
1002         }
1003     }
1004 
1005     /**
1006      * Run capture test with different test configurations.
1007      *
1008      * @param burst If the test uses {@link CameraCaptureSession#captureBurst} or
1009      * {@link CameraCaptureSession#setRepeatingBurst} to capture the burst.
1010      * @param repeating If the test uses {@link CameraCaptureSession#setRepeatingBurst} or
1011      * {@link CameraCaptureSession#setRepeatingRequest} for repeating capture.
1012      * @param abort If the test uses {@link CameraCaptureSession#abortCaptures} to stop the
1013      * repeating capture.  It has no effect if repeating is false.
1014      */
runCaptureTest(boolean burst, boolean repeating, boolean abort)1015     private void runCaptureTest(boolean burst, boolean repeating, boolean abort) throws Exception {
1016         for (int i = 0; i < mCameraIds.length; i++) {
1017             try {
1018                 openDevice(mCameraIds[i], mCameraMockListener);
1019                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
1020 
1021                 prepareCapture();
1022 
1023                 if (!burst) {
1024                     // Test: that a single capture of each template type succeeds.
1025                     for (int j = 0; j < sTemplates.length; j++) {
1026                         // Skip video snapshots for LEGACY mode
1027                         if (mStaticInfo.isHardwareLevelLegacy() &&
1028                                 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1029                             continue;
1030                         }
1031                         // Skip non-PREVIEW templates for non-color output
1032                         if (!mStaticInfo.isColorOutputSupported() &&
1033                                 sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
1034                             continue;
1035                         }
1036                         captureSingleShot(mCameraIds[i], sTemplates[j], repeating, abort);
1037                     }
1038                 }
1039                 else {
1040                     // Test: burst of one shot
1041                     captureBurstShot(mCameraIds[i], sTemplates, 1, repeating, abort);
1042 
1043                     int template = mStaticInfo.isColorOutputSupported() ?
1044                         CameraDevice.TEMPLATE_STILL_CAPTURE :
1045                         CameraDevice.TEMPLATE_PREVIEW;
1046                     int[] templates = new int[] {
1047                         template,
1048                         template,
1049                         template,
1050                         template,
1051                         template
1052                     };
1053 
1054                     // Test: burst of 5 shots of the same template type
1055                     captureBurstShot(mCameraIds[i], templates, templates.length, repeating, abort);
1056 
1057                     // Test: burst of 5 shots of different template types
1058                     captureBurstShot(
1059                             mCameraIds[i], sTemplates, sTemplates.length, repeating, abort);
1060                 }
1061                 verify(mCameraMockListener, never())
1062                         .onError(
1063                                 any(CameraDevice.class),
1064                                 anyInt());
1065             } catch (Exception e) {
1066                 mCollector.addError(e);
1067             } finally {
1068                 try {
1069                     closeSession();
1070                 } catch (Exception e) {
1071                     mCollector.addError(e);
1072                 }finally {
1073                     closeDevice(mCameraIds[i], mCameraMockListener);
1074                 }
1075             }
1076         }
1077     }
1078 
captureSingleShot( String id, int template, boolean repeating, boolean abort)1079     private void captureSingleShot(
1080             String id,
1081             int template,
1082             boolean repeating, boolean abort) throws Exception {
1083 
1084         assertEquals("Bad initial state for preparing to capture",
1085                 mLatestSessionState, SESSION_READY);
1086 
1087         CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(template);
1088         assertNotNull("Failed to create capture request", requestBuilder);
1089         requestBuilder.addTarget(mReaderSurface);
1090         CameraCaptureSession.CaptureCallback mockCaptureCallback =
1091                 mock(CameraCaptureSession.CaptureCallback.class);
1092 
1093         if (VERBOSE) {
1094             Log.v(TAG, String.format("Capturing shot for device %s, template %d",
1095                     id, template));
1096         }
1097 
1098         startCapture(requestBuilder.build(), repeating, mockCaptureCallback, mHandler);
1099         waitForSessionState(SESSION_ACTIVE, SESSION_ACTIVE_TIMEOUT_MS);
1100 
1101         int expectedCaptureResultCount = repeating ? REPEATING_CAPTURE_EXPECTED_RESULT_COUNT : 1;
1102         verifyCaptureResults(mockCaptureCallback, expectedCaptureResultCount);
1103 
1104         if (repeating) {
1105             if (abort) {
1106                 mSession.abortCaptures();
1107                 // Have to make sure abort and new requests aren't interleave together.
1108                 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1109 
1110                 // Capture a single capture, and verify the result.
1111                 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback();
1112                 CaptureRequest singleRequest = requestBuilder.build();
1113                 mSession.capture(singleRequest, resultCallback, mHandler);
1114                 resultCallback.getCaptureResultForRequest(singleRequest, CAPTURE_RESULT_TIMEOUT_MS);
1115 
1116                 // Resume the repeating, and verify that results are returned.
1117                 mSession.setRepeatingRequest(singleRequest, resultCallback, mHandler);
1118                 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) {
1119                     resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
1120                 }
1121             }
1122             mSession.stopRepeating();
1123         }
1124         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1125     }
1126 
captureBurstShot( String id, int[] templates, int len, boolean repeating, boolean abort)1127     private void captureBurstShot(
1128             String id,
1129             int[] templates,
1130             int len,
1131             boolean repeating,
1132             boolean abort) throws Exception {
1133 
1134         assertEquals("Bad initial state for preparing to capture",
1135                 mLatestSessionState, SESSION_READY);
1136 
1137         assertTrue("Invalid args to capture function", len <= templates.length);
1138         List<CaptureRequest> requests = new ArrayList<CaptureRequest>();
1139         List<CaptureRequest> postAbortRequests = new ArrayList<CaptureRequest>();
1140         for (int i = 0; i < len; i++) {
1141             // Skip video snapshots for LEGACY mode
1142             if (mStaticInfo.isHardwareLevelLegacy() &&
1143                     templates[i] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1144                 continue;
1145             }
1146             // Skip non-PREVIEW templates for non-color outpu
1147             if (!mStaticInfo.isColorOutputSupported() &&
1148                     templates[i] != CameraDevice.TEMPLATE_PREVIEW) {
1149                 continue;
1150             }
1151             CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(templates[i]);
1152             assertNotNull("Failed to create capture request", requestBuilder);
1153             requestBuilder.addTarget(mReaderSurface);
1154             requests.add(requestBuilder.build());
1155             if (abort) {
1156                 postAbortRequests.add(requestBuilder.build());
1157             }
1158         }
1159         CameraCaptureSession.CaptureCallback mockCaptureCallback =
1160                 mock(CameraCaptureSession.CaptureCallback.class);
1161 
1162         if (VERBOSE) {
1163             Log.v(TAG, String.format("Capturing burst shot for device %s", id));
1164         }
1165 
1166         if (!repeating) {
1167             mSession.captureBurst(requests, mockCaptureCallback, mHandler);
1168         }
1169         else {
1170             mSession.setRepeatingBurst(requests, mockCaptureCallback, mHandler);
1171         }
1172         waitForSessionState(SESSION_ACTIVE, SESSION_READY_TIMEOUT_MS);
1173 
1174         int expectedResultCount = requests.size();
1175         if (repeating) {
1176             expectedResultCount *= REPEATING_CAPTURE_EXPECTED_RESULT_COUNT;
1177         }
1178 
1179         verifyCaptureResults(mockCaptureCallback, expectedResultCount);
1180 
1181         if (repeating) {
1182             if (abort) {
1183                 mSession.abortCaptures();
1184                 // Have to make sure abort and new requests aren't interleave together.
1185                 waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1186 
1187                 // Capture a burst of captures, and verify the results.
1188                 SimpleCaptureCallback resultCallback = new SimpleCaptureCallback();
1189                 mSession.captureBurst(postAbortRequests, resultCallback, mHandler);
1190                 // Verify that the results are returned.
1191                 for (int i = 0; i < postAbortRequests.size(); i++) {
1192                     resultCallback.getCaptureResultForRequest(
1193                             postAbortRequests.get(i), CAPTURE_RESULT_TIMEOUT_MS);
1194                 }
1195 
1196                 // Resume the repeating, and verify that results are returned.
1197                 mSession.setRepeatingBurst(requests, resultCallback, mHandler);
1198                 for (int i = 0; i < REPEATING_CAPTURE_EXPECTED_RESULT_COUNT; i++) {
1199                     resultCallback.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
1200                 }
1201             }
1202             mSession.stopRepeating();
1203         }
1204         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1205     }
1206 
1207     /**
1208      * Precondition: Device must be in known OPENED state (has been waited for).
1209      *
1210      * <p>Creates a new capture session and waits until it is in the {@code SESSION_READY} state.
1211      * </p>
1212      *
1213      * <p>Any existing capture session will be closed as a result of calling this.</p>
1214      * */
prepareCapture()1215     private void prepareCapture() throws Exception {
1216         if (VERBOSE) Log.v(TAG, "prepareCapture");
1217 
1218         assertTrue("Bad initial state for preparing to capture",
1219                 mLatestDeviceState == STATE_OPENED);
1220 
1221         if (mSession != null) {
1222             if (VERBOSE) Log.v(TAG, "prepareCapture - closing existing session");
1223             closeSession();
1224         }
1225 
1226         // Create a new session listener each time, it's not reusable across cameras
1227         mSessionMockListener = spy(new BlockingSessionCallback());
1228         mSessionWaiter = mSessionMockListener.getStateWaiter();
1229 
1230         if (!mStaticInfo.isColorOutputSupported()) {
1231             createDefaultImageReader(getMaxDepthSize(mCamera.getId(), mCameraManager),
1232                     ImageFormat.DEPTH16, MAX_NUM_IMAGES, new ImageDropperListener());
1233         }
1234 
1235         List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(mReaderSurface));
1236         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
1237 
1238         mSession = mSessionMockListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
1239         waitForSessionState(SESSION_CONFIGURED, SESSION_CONFIGURE_TIMEOUT_MS);
1240         waitForSessionState(SESSION_READY, SESSION_READY_TIMEOUT_MS);
1241     }
1242 
waitForDeviceState(int state, long timeoutMs)1243     private void waitForDeviceState(int state, long timeoutMs) {
1244         mCameraMockListener.waitForState(state, timeoutMs);
1245         mLatestDeviceState = state;
1246     }
1247 
waitForSessionState(int state, long timeoutMs)1248     private void waitForSessionState(int state, long timeoutMs) {
1249         mSessionWaiter.waitForState(state, timeoutMs);
1250         mLatestSessionState = state;
1251     }
1252 
verifyCaptureResults( CameraCaptureSession.CaptureCallback mockListener, int expectResultCount)1253     private void verifyCaptureResults(
1254             CameraCaptureSession.CaptureCallback mockListener,
1255             int expectResultCount) {
1256         final int TIMEOUT_PER_RESULT_MS = 2000;
1257         // Should receive expected number of capture results.
1258         verify(mockListener,
1259                 timeout(TIMEOUT_PER_RESULT_MS * expectResultCount).atLeast(expectResultCount))
1260                         .onCaptureCompleted(
1261                                 eq(mSession),
1262                                 isA(CaptureRequest.class),
1263                                 argThat(new IsCaptureResultNotEmpty()));
1264         // Should not receive any capture failed callbacks.
1265         verify(mockListener, never())
1266                         .onCaptureFailed(
1267                                 eq(mSession),
1268                                 isA(CaptureRequest.class),
1269                                 isA(CaptureFailure.class));
1270         // Should receive expected number of capture shutter calls
1271         verify(mockListener,
1272                 atLeast(expectResultCount))
1273                         .onCaptureStarted(
1274                                eq(mSession),
1275                                isA(CaptureRequest.class),
1276                                anyLong(),
1277                                anyLong());
1278     }
1279 
checkFpsRange(CaptureRequest.Builder request, int template, CameraCharacteristics props)1280     private void checkFpsRange(CaptureRequest.Builder request, int template,
1281             CameraCharacteristics props) {
1282         CaptureRequest.Key<Range<Integer>> fpsRangeKey = CONTROL_AE_TARGET_FPS_RANGE;
1283         Range<Integer> fpsRange;
1284         if ((fpsRange = mCollector.expectKeyValueNotNull(request, fpsRangeKey)) == null) {
1285             return;
1286         }
1287 
1288         int minFps = fpsRange.getLower();
1289         int maxFps = fpsRange.getUpper();
1290         Range<Integer>[] availableFpsRange = props
1291                 .get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
1292         boolean foundRange = false;
1293         for (int i = 0; i < availableFpsRange.length; i += 1) {
1294             if (minFps == availableFpsRange[i].getLower()
1295                     && maxFps == availableFpsRange[i].getUpper()) {
1296                 foundRange = true;
1297                 break;
1298             }
1299         }
1300         if (!foundRange) {
1301             mCollector.addMessage(String.format("Unable to find the fps range (%d, %d)",
1302                     minFps, maxFps));
1303             return;
1304         }
1305 
1306 
1307         if (template != CameraDevice.TEMPLATE_MANUAL &&
1308                 template != CameraDevice.TEMPLATE_STILL_CAPTURE) {
1309             if (maxFps < MIN_FPS_REQUIRED_FOR_STREAMING) {
1310                 mCollector.addMessage("Max fps should be at least "
1311                         + MIN_FPS_REQUIRED_FOR_STREAMING);
1312                 return;
1313             }
1314 
1315             // Relax framerate constraints on legacy mode
1316             if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
1317                 // Need give fixed frame rate for video recording template.
1318                 if (template == CameraDevice.TEMPLATE_RECORD) {
1319                     if (maxFps != minFps) {
1320                         mCollector.addMessage("Video recording frame rate should be fixed");
1321                     }
1322                 }
1323             }
1324         }
1325     }
1326 
checkAfMode(CaptureRequest.Builder request, int template, CameraCharacteristics props)1327     private void checkAfMode(CaptureRequest.Builder request, int template,
1328             CameraCharacteristics props) {
1329         boolean hasFocuser = props.getKeys().contains(CameraCharacteristics.
1330                 LENS_INFO_MINIMUM_FOCUS_DISTANCE) &&
1331                 (props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f);
1332 
1333         if (!hasFocuser) {
1334             return;
1335         }
1336 
1337         int targetAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
1338         int[] availableAfMode = props.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
1339         if (template == CameraDevice.TEMPLATE_PREVIEW ||
1340                 template == CameraDevice.TEMPLATE_STILL_CAPTURE ||
1341                 template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) {
1342             // Default to CONTINUOUS_PICTURE if it is available, otherwise AUTO.
1343             for (int i = 0; i < availableAfMode.length; i++) {
1344                 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) {
1345                     targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
1346                     break;
1347                 }
1348             }
1349         } else if (template == CameraDevice.TEMPLATE_RECORD ||
1350                 template == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1351             // Default to CONTINUOUS_VIDEO if it is available, otherwise AUTO.
1352             for (int i = 0; i < availableAfMode.length; i++) {
1353                 if (availableAfMode[i] == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
1354                     targetAfMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
1355                     break;
1356                 }
1357             }
1358         } else if (template == CameraDevice.TEMPLATE_MANUAL) {
1359             targetAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
1360         }
1361 
1362         mCollector.expectKeyValueEquals(request, CONTROL_AF_MODE, targetAfMode);
1363         if (mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FOCUS_DISTANCE)) {
1364             mCollector.expectKeyValueNotNull(request, LENS_FOCUS_DISTANCE);
1365         }
1366     }
1367 
checkAntiBandingMode(CaptureRequest.Builder request, int template)1368     private void checkAntiBandingMode(CaptureRequest.Builder request, int template) {
1369         if (template == CameraDevice.TEMPLATE_MANUAL) {
1370             return;
1371         }
1372 
1373         if (!mStaticInfo.isColorOutputSupported()) return;
1374 
1375         List<Integer> availableAntiBandingModes =
1376                 Arrays.asList(toObject(mStaticInfo.getAeAvailableAntiBandingModesChecked()));
1377 
1378         if (availableAntiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO)) {
1379             mCollector.expectKeyValueEquals(request, CONTROL_AE_ANTIBANDING_MODE,
1380                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
1381         } else {
1382             mCollector.expectKeyValueIsIn(request, CONTROL_AE_ANTIBANDING_MODE,
1383                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ,
1384                     CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ);
1385         }
1386     }
1387 
1388     /**
1389      * <p>Check if 3A metering settings are "up to HAL" in request template</p>
1390      *
1391      * <p>This function doesn't fail the test immediately, it updates the
1392      * test pass/fail status and appends the failure message to the error collector each key.</p>
1393      *
1394      * @param regions The metering rectangles to be checked
1395      */
checkMeteringRect(MeteringRectangle[] regions)1396     private void checkMeteringRect(MeteringRectangle[] regions) {
1397         if (regions == null) {
1398             return;
1399         }
1400         mCollector.expectNotEquals("Number of metering region should not be 0", 0, regions.length);
1401         for (int i = 0; i < regions.length; i++) {
1402             mCollector.expectEquals("Default metering regions should have all zero weight",
1403                     0, regions[i].getMeteringWeight());
1404         }
1405     }
1406 
1407     /**
1408      * <p>Check if the request settings are suitable for a given request template.</p>
1409      *
1410      * <p>This function doesn't fail the test immediately, it updates the
1411      * test pass/fail status and appends the failure message to the error collector each key.</p>
1412      *
1413      * @param request The request to be checked.
1414      * @param template The capture template targeted by this request.
1415      * @param props The CameraCharacteristics this request is checked against with.
1416      */
checkRequestForTemplate(CaptureRequest.Builder request, int template, CameraCharacteristics props)1417     private void checkRequestForTemplate(CaptureRequest.Builder request, int template,
1418             CameraCharacteristics props) {
1419         // 3A settings--control.mode.
1420         if (template != CameraDevice.TEMPLATE_MANUAL) {
1421             mCollector.expectKeyValueEquals(request, CONTROL_MODE,
1422                     CaptureRequest.CONTROL_MODE_AUTO);
1423         }
1424 
1425         // 3A settings--AE/AWB/AF.
1426         Integer maxRegionsAeVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
1427         int maxRegionsAe = maxRegionsAeVal != null ? maxRegionsAeVal : 0;
1428         Integer maxRegionsAwbVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
1429         int maxRegionsAwb = maxRegionsAwbVal != null ? maxRegionsAwbVal : 0;
1430         Integer maxRegionsAfVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
1431         int maxRegionsAf = maxRegionsAfVal != null ? maxRegionsAfVal : 0;
1432 
1433         checkFpsRange(request, template, props);
1434 
1435         checkAfMode(request, template, props);
1436         checkAntiBandingMode(request, template);
1437 
1438         if (template == CameraDevice.TEMPLATE_MANUAL) {
1439             mCollector.expectKeyValueEquals(request, CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
1440             mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
1441                     CaptureRequest.CONTROL_AE_MODE_OFF);
1442             mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
1443                     CaptureRequest.CONTROL_AWB_MODE_OFF);
1444         } else {
1445             if (mStaticInfo.isColorOutputSupported()) {
1446                 mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
1447                         CaptureRequest.CONTROL_AE_MODE_ON);
1448                 mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
1449                 mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
1450                         CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
1451                 // if AE lock is not supported, expect the control key to be non-exist or false
1452                 if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
1453                     mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
1454                 }
1455 
1456                 mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
1457                         CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
1458 
1459                 mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
1460                         CaptureRequest.CONTROL_AWB_MODE_AUTO);
1461                 // if AWB lock is not supported, expect the control key to be non-exist or false
1462                 if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
1463                     mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
1464                 }
1465 
1466                 // Check 3A regions.
1467                 if (VERBOSE) {
1468                     Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}",
1469                                     maxRegionsAe, maxRegionsAwb, maxRegionsAf));
1470                 }
1471                 if (maxRegionsAe > 0) {
1472                     mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS);
1473                     MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
1474                     checkMeteringRect(aeRegions);
1475                 }
1476                 if (maxRegionsAwb > 0) {
1477                     mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS);
1478                     MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS);
1479                     checkMeteringRect(awbRegions);
1480                 }
1481                 if (maxRegionsAf > 0) {
1482                     mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS);
1483                     MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
1484                     checkMeteringRect(afRegions);
1485                 }
1486             }
1487         }
1488 
1489         // Sensor settings.
1490 
1491         mCollector.expectEquals("Lens aperture must be present in request if available apertures " +
1492                         "are present in metadata, and vice-versa.",
1493                 mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES),
1494                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_APERTURE));
1495         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES)) {
1496             float[] availableApertures =
1497                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES);
1498             if (availableApertures.length > 1) {
1499                 mCollector.expectKeyValueNotNull(request, LENS_APERTURE);
1500             }
1501         }
1502 
1503         mCollector.expectEquals("Lens filter density must be present in request if available " +
1504                         "filter densities are present in metadata, and vice-versa.",
1505                 mStaticInfo.areKeysAvailable(CameraCharacteristics.
1506                         LENS_INFO_AVAILABLE_FILTER_DENSITIES),
1507                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_FILTER_DENSITY));
1508         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.
1509                 LENS_INFO_AVAILABLE_FILTER_DENSITIES)) {
1510             float[] availableFilters =
1511                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES);
1512             if (availableFilters.length > 1) {
1513                 mCollector.expectKeyValueNotNull(request, LENS_FILTER_DENSITY);
1514             }
1515         }
1516 
1517         float[] availableFocalLen =
1518                 props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
1519         if (availableFocalLen.length > 1) {
1520             mCollector.expectKeyValueNotNull(request, LENS_FOCAL_LENGTH);
1521         }
1522 
1523         mCollector.expectEquals("Lens optical stabilization must be present in request if " +
1524                         "available optical stabilizations are present in metadata, and vice-versa.",
1525                 mStaticInfo.areKeysAvailable(CameraCharacteristics.
1526                         LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION),
1527                 mStaticInfo.areKeysAvailable(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE));
1528         if (mStaticInfo.areKeysAvailable(CameraCharacteristics.
1529                 LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) {
1530             int[] availableOIS =
1531                     props.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);
1532             if (availableOIS.length > 1) {
1533                 mCollector.expectKeyValueNotNull(request, LENS_OPTICAL_STABILIZATION_MODE);
1534             }
1535         }
1536 
1537         if (mStaticInfo.areKeysAvailable(BLACK_LEVEL_LOCK)) {
1538             mCollector.expectKeyValueEquals(request, BLACK_LEVEL_LOCK, false);
1539         }
1540 
1541         if (mStaticInfo.areKeysAvailable(SENSOR_FRAME_DURATION)) {
1542             mCollector.expectKeyValueNotNull(request, SENSOR_FRAME_DURATION);
1543         }
1544 
1545         if (mStaticInfo.areKeysAvailable(SENSOR_EXPOSURE_TIME)) {
1546             mCollector.expectKeyValueNotNull(request, SENSOR_EXPOSURE_TIME);
1547         }
1548 
1549         if (mStaticInfo.areKeysAvailable(SENSOR_SENSITIVITY)) {
1550             mCollector.expectKeyValueNotNull(request, SENSOR_SENSITIVITY);
1551         }
1552 
1553         // ISP-processing settings.
1554         if (mStaticInfo.isColorOutputSupported()) {
1555             mCollector.expectKeyValueEquals(
1556                     request, STATISTICS_FACE_DETECT_MODE,
1557                     CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF);
1558             mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
1559         }
1560 
1561         List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
1562         if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) {
1563             // If the device doesn't support RAW, all template should have OFF as default.
1564             if (!availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
1565                 mCollector.expectKeyValueEquals(
1566                         request, STATISTICS_LENS_SHADING_MAP_MODE,
1567                         CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_OFF);
1568             }
1569         }
1570 
1571         boolean supportReprocessing =
1572                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) ||
1573                 availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
1574 
1575         if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) {
1576             // Not enforce high quality here, as some devices may not effectively have high quality
1577             // mode.
1578             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_MODE)) {
1579                 mCollector.expectKeyValueNotEquals(
1580                         request, COLOR_CORRECTION_MODE,
1581                         CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
1582             }
1583 
1584             // Edge enhancement, noise reduction and aberration correction modes.
1585             mCollector.expectEquals("Edge mode must be present in request if " +
1586                             "available edge modes are present in metadata, and vice-versa.",
1587                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
1588                             EDGE_AVAILABLE_EDGE_MODES),
1589                     mStaticInfo.areKeysAvailable(CaptureRequest.EDGE_MODE));
1590             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
1591                 List<Integer> availableEdgeModes =
1592                         Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
1593                 // Don't need check fast as fast or high quality must be both present or both not.
1594                 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) {
1595                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
1596                             CaptureRequest.EDGE_MODE_HIGH_QUALITY);
1597                 } else {
1598                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
1599                             CaptureRequest.EDGE_MODE_OFF);
1600                 }
1601             }
1602 
1603             mCollector.expectEquals("Noise reduction mode must be present in request if " +
1604                             "available noise reductions are present in metadata, and vice-versa.",
1605                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
1606                             NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES),
1607                     mStaticInfo.areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE));
1608             if (mStaticInfo.areKeysAvailable(
1609                     CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) {
1610                 List<Integer> availableNoiseReductionModes =
1611                         Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked()));
1612                 // Don't need check fast as fast or high quality must be both present or both not.
1613                 if (availableNoiseReductionModes
1614                         .contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
1615                     mCollector.expectKeyValueEquals(
1616                             request, NOISE_REDUCTION_MODE,
1617                             CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
1618                 } else {
1619                     mCollector.expectKeyValueEquals(
1620                             request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
1621                 }
1622             }
1623 
1624             boolean supportAvailableAberrationModes = mStaticInfo.areKeysAvailable(
1625                     CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES);
1626             boolean supportAberrationRequestKey = mStaticInfo.areKeysAvailable(
1627                     CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
1628             mCollector.expectEquals("Aberration correction mode must be present in request if " +
1629                     "available aberration correction reductions are present in metadata, and "
1630                     + "vice-versa.", supportAvailableAberrationModes, supportAberrationRequestKey);
1631             if (supportAberrationRequestKey) {
1632                 List<Integer> availableAberrationModes = Arrays.asList(
1633                         toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
1634                 // Don't need check fast as fast or high quality must be both present or both not.
1635                 if (availableAberrationModes
1636                         .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY)) {
1637                     mCollector.expectKeyValueEquals(
1638                             request, COLOR_CORRECTION_ABERRATION_MODE,
1639                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
1640                 } else {
1641                     mCollector.expectKeyValueEquals(
1642                             request, COLOR_CORRECTION_ABERRATION_MODE,
1643                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
1644                 }
1645             }
1646         } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) {
1647             mCollector.expectKeyValueEquals(request, EDGE_MODE,
1648                     CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
1649             mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE,
1650                     CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
1651         } else if (template == CameraDevice.TEMPLATE_PREVIEW ||
1652                 template == CameraDevice.TEMPLATE_RECORD){
1653             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
1654                 List<Integer> availableEdgeModes =
1655                         Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
1656                 if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
1657                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
1658                             CaptureRequest.EDGE_MODE_FAST);
1659                 } else {
1660                     mCollector.expectKeyValueEquals(request, EDGE_MODE,
1661                             CaptureRequest.EDGE_MODE_OFF);
1662                 }
1663             }
1664 
1665             if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
1666                 List<Integer> availableNoiseReductionModes =
1667                         Arrays.asList(toObject(
1668                                 mStaticInfo.getAvailableNoiseReductionModesChecked()));
1669                 if (availableNoiseReductionModes
1670                         .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
1671                     mCollector.expectKeyValueEquals(
1672                             request, NOISE_REDUCTION_MODE,
1673                             CaptureRequest.NOISE_REDUCTION_MODE_FAST);
1674                 } else {
1675                     mCollector.expectKeyValueEquals(
1676                             request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
1677                 }
1678             }
1679 
1680             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
1681                 List<Integer> availableAberrationModes = Arrays.asList(
1682                         toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
1683                 if (availableAberrationModes
1684                         .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST)) {
1685                     mCollector.expectKeyValueEquals(
1686                             request, COLOR_CORRECTION_ABERRATION_MODE,
1687                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST);
1688                 } else {
1689                     mCollector.expectKeyValueEquals(
1690                             request, COLOR_CORRECTION_ABERRATION_MODE,
1691                             CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
1692                 }
1693             }
1694         } else {
1695             if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
1696                 mCollector.expectKeyValueNotNull(request, EDGE_MODE);
1697             }
1698 
1699             if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
1700                 mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE);
1701             }
1702 
1703             if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
1704                 mCollector.expectKeyValueNotNull(request, COLOR_CORRECTION_ABERRATION_MODE);
1705             }
1706         }
1707 
1708         // Tone map and lens shading modes.
1709         if (template == CameraDevice.TEMPLATE_STILL_CAPTURE) {
1710             mCollector.expectEquals("Tonemap mode must be present in request if " +
1711                             "available tonemap modes are present in metadata, and vice-versa.",
1712                     mStaticInfo.areKeysAvailable(CameraCharacteristics.
1713                             TONEMAP_AVAILABLE_TONE_MAP_MODES),
1714                     mStaticInfo.areKeysAvailable(CaptureRequest.TONEMAP_MODE));
1715             if (mStaticInfo.areKeysAvailable(
1716                     CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES)) {
1717                 List<Integer> availableToneMapModes =
1718                         Arrays.asList(toObject(mStaticInfo.getAvailableToneMapModesChecked()));
1719                 if (availableToneMapModes.contains(CaptureRequest.TONEMAP_MODE_HIGH_QUALITY)) {
1720                     mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
1721                             CaptureRequest.TONEMAP_MODE_HIGH_QUALITY);
1722                 } else {
1723                     mCollector.expectKeyValueEquals(request, TONEMAP_MODE,
1724                             CaptureRequest.TONEMAP_MODE_FAST);
1725                 }
1726             }
1727 
1728             // Still capture template should have android.statistics.lensShadingMapMode ON when
1729             // RAW capability is supported.
1730             if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE) &&
1731                     availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
1732                     mCollector.expectKeyValueEquals(request, STATISTICS_LENS_SHADING_MAP_MODE,
1733                             STATISTICS_LENS_SHADING_MAP_MODE_ON);
1734             }
1735         } else {
1736             if (mStaticInfo.areKeysAvailable(TONEMAP_MODE)) {
1737                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
1738                         CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE);
1739                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
1740                         CaptureRequest.TONEMAP_MODE_GAMMA_VALUE);
1741                 mCollector.expectKeyValueNotEquals(request, TONEMAP_MODE,
1742                         CaptureRequest.TONEMAP_MODE_PRESET_CURVE);
1743             }
1744             if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) {
1745                 mCollector.expectKeyValueNotNull(request, STATISTICS_LENS_SHADING_MAP_MODE);
1746             }
1747         }
1748 
1749         int[] outputFormats = mStaticInfo.getAvailableFormats(
1750                 StaticMetadata.StreamDirection.Output);
1751         boolean supportRaw = false;
1752         for (int format : outputFormats) {
1753             if (format == ImageFormat.RAW_SENSOR || format == ImageFormat.RAW10 ||
1754                     format == ImageFormat.RAW12 || format == ImageFormat.RAW_PRIVATE) {
1755                 supportRaw = true;
1756                 break;
1757             }
1758         }
1759         if (supportRaw) {
1760             mCollector.expectKeyValueEquals(request,
1761                     CONTROL_POST_RAW_SENSITIVITY_BOOST,
1762                     DEFAULT_POST_RAW_SENSITIVITY_BOOST);
1763         }
1764 
1765         mCollector.expectKeyValueEquals(request, CONTROL_CAPTURE_INTENT, template);
1766 
1767         // TODO: use the list of keys from CameraCharacteristics to avoid expecting
1768         //       keys which are not available by this CameraDevice.
1769     }
1770 
captureTemplateTestByCamera(String cameraId, int template)1771     private void captureTemplateTestByCamera(String cameraId, int template) throws Exception {
1772         try {
1773             openDevice(cameraId, mCameraMockListener);
1774 
1775             assertTrue("Camera template " + template + " is out of range!",
1776                     template >= CameraDevice.TEMPLATE_PREVIEW
1777                             && template <= CameraDevice.TEMPLATE_MANUAL);
1778 
1779             mCollector.setCameraId(cameraId);
1780 
1781             try {
1782                 CaptureRequest.Builder request = mCamera.createCaptureRequest(template);
1783                 assertNotNull("Failed to create capture request for template " + template, request);
1784 
1785                 CameraCharacteristics props = mStaticInfo.getCharacteristics();
1786                 checkRequestForTemplate(request, template, props);
1787             } catch (IllegalArgumentException e) {
1788                 if (template == CameraDevice.TEMPLATE_MANUAL &&
1789                         !mStaticInfo.isCapabilitySupported(CameraCharacteristics.
1790                                 REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1791                     // OK
1792                 } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG &&
1793                         !mStaticInfo.isCapabilitySupported(CameraCharacteristics.
1794                                 REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)) {
1795                     // OK.
1796                 } else if (sLegacySkipTemplates.contains(template) &&
1797                         mStaticInfo.isHardwareLevelLegacy()) {
1798                     // OK
1799                 } else if (template != CameraDevice.TEMPLATE_PREVIEW &&
1800                         mStaticInfo.isDepthOutputSupported() &&
1801                         !mStaticInfo.isColorOutputSupported()) {
1802                     // OK, depth-only devices need only support PREVIEW template
1803                 } else {
1804                     throw e; // rethrow
1805                 }
1806             }
1807         }
1808         finally {
1809             try {
1810                 closeSession();
1811             } finally {
1812                 closeDevice(cameraId, mCameraMockListener);
1813             }
1814         }
1815     }
1816 
1817     /**
1818      * Start capture with given {@link #CaptureRequest}.
1819      *
1820      * @param request The {@link #CaptureRequest} to be captured.
1821      * @param repeating If the capture is single capture or repeating.
1822      * @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
1823      * @param handler The handler camera device used to post callbacks.
1824      */
1825     @Override
startCapture(CaptureRequest request, boolean repeating, CameraCaptureSession.CaptureCallback listener, Handler handler)1826     protected void startCapture(CaptureRequest request, boolean repeating,
1827             CameraCaptureSession.CaptureCallback listener, Handler handler)
1828                     throws CameraAccessException {
1829         if (VERBOSE) Log.v(TAG, "Starting capture from session");
1830 
1831         if (repeating) {
1832             mSession.setRepeatingRequest(request, listener, handler);
1833         } else {
1834             mSession.capture(request, listener, handler);
1835         }
1836     }
1837 
1838     /**
1839      * Close a {@link #CameraCaptureSession capture session}; blocking until
1840      * the close finishes with a transition to {@link CameraCaptureSession.StateCallback#onClosed}.
1841      */
closeSession()1842     protected void closeSession() {
1843         if (mSession == null) {
1844             return;
1845         }
1846 
1847         mSession.close();
1848         waitForSessionState(SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS);
1849         mSession = null;
1850 
1851         mSessionMockListener = null;
1852         mSessionWaiter = null;
1853     }
1854 
1855     /**
1856      * A camera capture session listener that keeps all the configured and closed sessions.
1857      */
1858     private class MultipleSessionCallback extends CameraCaptureSession.StateCallback {
1859         public static final int SESSION_CONFIGURED = 0;
1860         public static final int SESSION_CLOSED = 1;
1861 
1862         final List<CameraCaptureSession> mSessions = new ArrayList<>();
1863         final Map<CameraCaptureSession, Integer> mSessionStates = new HashMap<>();
1864         CameraCaptureSession mCurrentConfiguredSession = null;
1865 
1866         final ReentrantLock mLock = new ReentrantLock();
1867         final Condition mNewStateCond = mLock.newCondition();
1868 
1869         final boolean mFailOnConfigureFailed;
1870 
1871         /**
1872          * If failOnConfigureFailed is true, it calls fail() when onConfigureFailed() is invoked
1873          * for any session.
1874          */
MultipleSessionCallback(boolean failOnConfigureFailed)1875         public MultipleSessionCallback(boolean failOnConfigureFailed) {
1876             mFailOnConfigureFailed = failOnConfigureFailed;
1877         }
1878 
1879         @Override
onClosed(CameraCaptureSession session)1880         public void onClosed(CameraCaptureSession session) {
1881             mLock.lock();
1882             mSessionStates.put(session, SESSION_CLOSED);
1883             mNewStateCond.signal();
1884             mLock.unlock();
1885         }
1886 
1887         @Override
onConfigured(CameraCaptureSession session)1888         public void onConfigured(CameraCaptureSession session) {
1889             mLock.lock();
1890             mSessions.add(session);
1891             mSessionStates.put(session, SESSION_CONFIGURED);
1892             mNewStateCond.signal();
1893             mLock.unlock();
1894         }
1895 
1896         @Override
onConfigureFailed(CameraCaptureSession session)1897         public void onConfigureFailed(CameraCaptureSession session) {
1898             if (mFailOnConfigureFailed) {
1899                 fail("Configuring a session failed");
1900             }
1901         }
1902 
1903         /**
1904          * Get a number of sessions that have been configured.
1905          */
getAllSessions(int numSessions, int timeoutMs)1906         public List<CameraCaptureSession> getAllSessions(int numSessions, int timeoutMs)
1907                 throws Exception {
1908             long remainingTime = timeoutMs;
1909             mLock.lock();
1910             try {
1911                 while (mSessions.size() < numSessions) {
1912                     long startTime = SystemClock.elapsedRealtime();
1913                     boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
1914                     remainingTime -= (SystemClock.elapsedRealtime() - startTime);
1915                     ret &= remainingTime > 0;
1916 
1917                     assertTrue("Get " + numSessions + " sessions timed out after " + timeoutMs +
1918                             "ms", ret);
1919                 }
1920 
1921                 return mSessions;
1922             } finally {
1923                 mLock.unlock();
1924             }
1925         }
1926 
1927         /**
1928          * Wait until a previously-configured sessoin is closed or it times out.
1929          */
waitForSessionClose(CameraCaptureSession session, int timeoutMs)1930         public void waitForSessionClose(CameraCaptureSession session, int timeoutMs) throws Exception {
1931             long remainingTime = timeoutMs;
1932             mLock.lock();
1933             try {
1934                 while (mSessionStates.get(session).equals(SESSION_CLOSED) == false) {
1935                     long startTime = SystemClock.elapsedRealtime();
1936                     boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
1937                     remainingTime -= (SystemClock.elapsedRealtime() - startTime);
1938                     ret &= remainingTime > 0;
1939 
1940                     assertTrue("Wait for session close timed out after " + timeoutMs + "ms", ret);
1941                 }
1942             } finally {
1943                 mLock.unlock();
1944             }
1945         }
1946     }
1947 }
1948