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