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