• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.*;
21 
22 import android.content.Context;
23 import android.graphics.ImageFormat;
24 import android.graphics.SurfaceTexture;
25 import android.hardware.camera2.CameraCaptureSession;
26 import android.hardware.camera2.CameraCharacteristics;
27 import android.hardware.camera2.CameraDevice;
28 import android.hardware.camera2.CameraManager;
29 import android.hardware.camera2.CaptureRequest;
30 import android.hardware.camera2.CaptureResult;
31 import android.hardware.camera2.TotalCaptureResult;
32 import android.hardware.camera2.CaptureFailure;
33 import android.hardware.camera2.params.InputConfiguration;
34 import android.hardware.camera2.params.StreamConfigurationMap;
35 import android.hardware.camera2.cts.helpers.StaticMetadata;
36 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
37 import android.media.CamcorderProfile;
38 import android.media.Image;
39 import android.media.ImageReader;
40 import android.media.ImageWriter;
41 import android.util.Log;
42 import android.util.Size;
43 import android.view.Display;
44 import android.view.Surface;
45 import android.view.WindowManager;
46 
47 import com.android.ex.camera2.blocking.BlockingSessionCallback;
48 
49 import java.util.Arrays;
50 import java.util.ArrayList;
51 import java.util.List;
52 
53 import static junit.framework.Assert.assertTrue;
54 import static org.mockito.Mockito.*;
55 
56 /**
57  * Tests exercising edge cases in camera setup, configuration, and usage.
58  */
59 public class RobustnessTest extends Camera2AndroidTestCase {
60     private static final String TAG = "RobustnessTest";
61     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
62 
63     private static final int CONFIGURE_TIMEOUT = 5000; //ms
64     private static final int CAPTURE_TIMEOUT = 1000; //ms
65 
66     // For testTriggerInteractions
67     private static final int PREVIEW_WARMUP_FRAMES = 60;
68     private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100;
69     private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps
70     private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10;
71 
72     /**
73      * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing
74      * a dimension other than one of the supported output dimensions.  The buffers produced into
75      * this surface are expected have the dimensions of the closest possible buffer size in the
76      * available stream configurations for a surface with this format.
77      */
testBadSurfaceDimensions()78     public void testBadSurfaceDimensions() throws Exception {
79         for (String id : mCameraIds) {
80             try {
81                 Log.i(TAG, "Testing Camera " + id);
82                 openDevice(id);
83 
84                 List<Size> testSizes = null;
85                 int format = mStaticInfo.isColorOutputSupported() ?
86                     ImageFormat.YUV_420_888 : ImageFormat.DEPTH16;
87 
88                 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager,
89                         format, null);
90 
91                 // Find some size not supported by the camera
92                 Size weirdSize = new Size(643, 577);
93                 int count = 0;
94                 while(testSizes.contains(weirdSize)) {
95                     // Really, they can't all be supported...
96                     weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
97                     count++;
98                     assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100);
99                 }
100 
101                 // Setup imageReader with invalid dimension
102                 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
103                         weirdSize.getHeight(), format, 3);
104 
105                 // Setup ImageReaderListener
106                 SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
107                 imageReader.setOnImageAvailableListener(imageListener, mHandler);
108 
109                 Surface surface = imageReader.getSurface();
110                 List<Surface> surfaces = new ArrayList<>();
111                 surfaces.add(surface);
112 
113                 // Setup a capture request and listener
114                 CaptureRequest.Builder request =
115                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
116                 request.addTarget(surface);
117 
118                 // Check that correct session callback is hit.
119                 CameraCaptureSession.StateCallback sessionListener =
120                         mock(CameraCaptureSession.StateCallback.class);
121                 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera,
122                         surfaces, sessionListener, mHandler);
123 
124                 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
125                         onConfigured(any(CameraCaptureSession.class));
126                 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
127                         onReady(any(CameraCaptureSession.class));
128                 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
129                 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
130                 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
131 
132                 CameraCaptureSession.CaptureCallback captureListener =
133                         mock(CameraCaptureSession.CaptureCallback.class);
134                 session.capture(request.build(), captureListener, mHandler);
135 
136                 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
137                         onCaptureCompleted(any(CameraCaptureSession.class),
138                                 any(CaptureRequest.class), any(TotalCaptureResult.class));
139                 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
140                         any(CaptureRequest.class), any(CaptureFailure.class));
141 
142                 Image image = imageListener.getImage(CAPTURE_TIMEOUT);
143                 int imageWidth = image.getWidth();
144                 int imageHeight = image.getHeight();
145                 Size actualSize = new Size(imageWidth, imageHeight);
146 
147                 assertTrue("Camera does not contain outputted image resolution " + actualSize,
148                         testSizes.contains(actualSize));
149             } finally {
150                 closeDevice(id);
151             }
152         }
153     }
154 
155     /**
156      * Test for making sure the required output combinations for each hardware level and capability
157      * work as expected.
158      */
testMandatoryOutputCombinations()159     public void testMandatoryOutputCombinations() throws Exception {
160         /**
161          * Tables for maximum sizes to try for each hardware level and capability.
162          *
163          * Keep in sync with the tables in
164          * frameworks/base/core/java/android/hardware/camera2/CameraDevice.java#createCaptureSession
165          *
166          * Each row of the table is a set of (format, max resolution) pairs, using the below consts
167          */
168 
169         // Enum values are defined in MaxStreamSizes
170         final int[][] LEGACY_COMBINATIONS = {
171             // Simple preview, GPU video processing, or no-preview video recording
172             {PRIV, MAXIMUM},
173             // No-viewfinder still image capture
174             {JPEG, MAXIMUM},
175             // In-application video/image processing
176             {YUV,  MAXIMUM},
177             // Standard still imaging.
178             {PRIV, PREVIEW,  JPEG, MAXIMUM},
179             // In-app processing plus still capture.
180             {YUV,  PREVIEW,  JPEG, MAXIMUM},
181             // Standard recording.
182             {PRIV, PREVIEW,  PRIV, PREVIEW},
183             // Preview plus in-app processing.
184             {PRIV, PREVIEW,  YUV,  PREVIEW},
185             // Still capture plus in-app processing.
186             {PRIV, PREVIEW,  YUV,  PREVIEW,  JPEG, MAXIMUM}
187         };
188 
189         final int[][] LIMITED_COMBINATIONS = {
190             // High-resolution video recording with preview.
191             {PRIV, PREVIEW,  PRIV, RECORD },
192             // High-resolution in-app video processing with preview.
193             {PRIV, PREVIEW,  YUV , RECORD },
194             // Two-input in-app video processing.
195             {YUV , PREVIEW,  YUV , RECORD },
196             // High-resolution recording with video snapshot.
197             {PRIV, PREVIEW,  PRIV, RECORD,   JPEG, RECORD  },
198             // High-resolution in-app processing with video snapshot.
199             {PRIV, PREVIEW,  YUV,  RECORD,   JPEG, RECORD  },
200             // Two-input in-app processing with still capture.
201             {YUV , PREVIEW,  YUV,  PREVIEW,  JPEG, MAXIMUM }
202         };
203 
204         final int[][] BURST_COMBINATIONS = {
205             // Maximum-resolution GPU processing with preview.
206             {PRIV, PREVIEW,  PRIV, MAXIMUM },
207             // Maximum-resolution in-app processing with preview.
208             {PRIV, PREVIEW,  YUV,  MAXIMUM },
209             // Maximum-resolution two-input in-app processsing.
210             {YUV,  PREVIEW,  YUV,  MAXIMUM },
211         };
212 
213         final int[][] FULL_COMBINATIONS = {
214             // Video recording with maximum-size video snapshot.
215             {PRIV, PREVIEW,  PRIV, PREVIEW,  JPEG, MAXIMUM },
216             // Standard video recording plus maximum-resolution in-app processing.
217             {YUV,  VGA,      PRIV, PREVIEW,  YUV,  MAXIMUM },
218             // Preview plus two-input maximum-resolution in-app processing.
219             {YUV,  VGA,      YUV,  PREVIEW,  YUV,  MAXIMUM }
220         };
221 
222         final int[][] RAW_COMBINATIONS = {
223             // No-preview DNG capture.
224             {RAW,  MAXIMUM },
225             // Standard DNG capture.
226             {PRIV, PREVIEW,  RAW,  MAXIMUM },
227             // In-app processing plus DNG capture.
228             {YUV,  PREVIEW,  RAW,  MAXIMUM },
229             // Video recording with DNG capture.
230             {PRIV, PREVIEW,  PRIV, PREVIEW,  RAW, MAXIMUM},
231             // Preview with in-app processing and DNG capture.
232             {PRIV, PREVIEW,  YUV,  PREVIEW,  RAW, MAXIMUM},
233             // Two-input in-app processing plus DNG capture.
234             {YUV,  PREVIEW,  YUV,  PREVIEW,  RAW, MAXIMUM},
235             // Still capture with simultaneous JPEG and DNG.
236             {PRIV, PREVIEW,  JPEG, MAXIMUM,  RAW, MAXIMUM},
237             // In-app processing with simultaneous JPEG and DNG.
238             {YUV,  PREVIEW,  JPEG, MAXIMUM,  RAW, MAXIMUM}
239         };
240 
241         final int[][] LEVEL_3_COMBINATIONS = {
242             // In-app viewfinder analysis with dynamic selection of output format
243             {PRIV, PREVIEW, PRIV, VGA, YUV, MAXIMUM, RAW, MAXIMUM},
244             // In-app viewfinder analysis with dynamic selection of output format
245             {PRIV, PREVIEW, PRIV, VGA, JPEG, MAXIMUM, RAW, MAXIMUM}
246         };
247 
248         final int[][][] TABLES =
249                 { LEGACY_COMBINATIONS, LIMITED_COMBINATIONS, BURST_COMBINATIONS, FULL_COMBINATIONS,
250                   RAW_COMBINATIONS, LEVEL_3_COMBINATIONS };
251 
252         sanityCheckConfigurationTables(TABLES);
253 
254         for (String id : mCameraIds) {
255             openDevice(id);
256 
257             // Find the concrete max sizes for each format/resolution combination
258             MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, getContext());
259 
260             String streamConfigurationMapString =
261                     mStaticInfo.getCharacteristics().get(
262                             CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).toString();
263             if (VERBOSE) {
264                 Log.v(TAG, "StreamConfigurationMap: " + streamConfigurationMapString);
265             }
266 
267             // Always run legacy-level tests for color-supporting devices
268 
269             if (mStaticInfo.isColorOutputSupported()) {
270                 for (int[] config : LEGACY_COMBINATIONS) {
271                     testOutputCombination(id, config, maxSizes);
272                 }
273             }
274 
275             // Then run higher-level tests if applicable
276 
277             if (!mStaticInfo.isHardwareLevelLegacy()) {
278 
279                 // If not legacy, at least limited, so run limited-level tests
280 
281                 if (mStaticInfo.isColorOutputSupported()) {
282                     for (int[] config : LIMITED_COMBINATIONS) {
283                         testOutputCombination(id, config, maxSizes);
284                     }
285                 }
286 
287                 // Check for BURST_CAPTURE, FULL and RAW and run those if appropriate
288 
289                 if (mStaticInfo.isCapabilitySupported(
290                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
291                     for (int[] config : BURST_COMBINATIONS) {
292                         testOutputCombination(id, config, maxSizes);
293                     }
294                 }
295 
296                 if (mStaticInfo.isHardwareLevelAtLeastFull()) {
297                     for (int[] config : FULL_COMBINATIONS) {
298                         testOutputCombination(id, config, maxSizes);
299                     }
300                 }
301 
302                 if (mStaticInfo.isCapabilitySupported(
303                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
304                     for (int[] config : RAW_COMBINATIONS) {
305                         testOutputCombination(id, config, maxSizes);
306                     }
307                 }
308 
309                 if (mStaticInfo.isHardwareLevelAtLeast(
310                         CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
311                     for (int[] config: LEVEL_3_COMBINATIONS) {
312                         testOutputCombination(id, config, maxSizes);
313                     }
314                 }
315             }
316 
317             closeDevice(id);
318         }
319     }
320 
321     /**
322      * Test for making sure the required reprocess input/output combinations for each hardware
323      * level and capability work as expected.
324      */
testMandatoryReprocessConfigurations()325     public void testMandatoryReprocessConfigurations() throws Exception {
326 
327         /**
328          * For each stream combination, verify that
329          *    1. A reprocessable session can be created using the stream combination.
330          *    2. Reprocess capture requests targeting YUV and JPEG outputs are successful.
331          */
332         final int[][] LIMITED_COMBINATIONS = {
333             // Input           Outputs
334             {PRIV, MAXIMUM,    JPEG, MAXIMUM},
335             {YUV , MAXIMUM,    JPEG, MAXIMUM},
336             {PRIV, MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM},
337             {YUV , MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM},
338             {PRIV, MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM},
339             {YUV , MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM},
340             {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
341             {YUV,  MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
342         };
343 
344         final int[][] FULL_COMBINATIONS = {
345             // Input           Outputs
346             {YUV , MAXIMUM,    PRIV, PREVIEW},
347             {YUV , MAXIMUM,    YUV , PREVIEW},
348             {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , RECORD},
349             {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , RECORD},
350             {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , MAXIMUM},
351             {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , MAXIMUM},
352             {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
353             {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
354         };
355 
356         final int[][] RAW_COMBINATIONS = {
357             // Input           Outputs
358             {PRIV, MAXIMUM,    YUV , PREVIEW, RAW , MAXIMUM},
359             {YUV , MAXIMUM,    YUV , PREVIEW, RAW , MAXIMUM},
360             {PRIV, MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
361             {YUV , MAXIMUM,    PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
362             {PRIV, MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
363             {YUV , MAXIMUM,    YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
364             {PRIV, MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
365             {YUV , MAXIMUM,    PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
366             {PRIV, MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
367             {YUV , MAXIMUM,    YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
368         };
369 
370         final int[][] LEVEL_3_COMBINATIONS = {
371             // Input          Outputs
372             // In-app viewfinder analysis with YUV->YUV ZSL and RAW
373             {YUV , MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM},
374             // In-app viewfinder analysis with PRIV->JPEG ZSL and RAW
375             {PRIV, MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM},
376             // In-app viewfinder analysis with YUV->JPEG ZSL and RAW
377             {YUV , MAXIMUM,   PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM},
378         };
379 
380         final int[][][] TABLES =
381                 { LIMITED_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS, LEVEL_3_COMBINATIONS };
382 
383         sanityCheckConfigurationTables(TABLES);
384 
385         for (String id : mCameraIds) {
386             CameraCharacteristics cc = mCameraManager.getCameraCharacteristics(id);
387             StaticMetadata staticInfo = new StaticMetadata(cc);
388             MaxStreamSizes maxSizes = new MaxStreamSizes(staticInfo, id, getContext());
389 
390             // Skip the test for legacy devices.
391             if (staticInfo.isHardwareLevelLegacy()) {
392                 continue;
393             }
394 
395             openDevice(id);
396 
397             try {
398                 for (int[] config : LIMITED_COMBINATIONS) {
399                     testReprocessStreamCombination(id, config, maxSizes, staticInfo);
400                 }
401 
402                 // Check FULL devices
403                 if (staticInfo.isHardwareLevelAtLeastFull()) {
404                     for (int[] config : FULL_COMBINATIONS) {
405                         testReprocessStreamCombination(id, config, maxSizes, staticInfo);
406                     }
407                 }
408 
409                 // Check devices with RAW capability.
410                 if (staticInfo.isCapabilitySupported(
411                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
412                     for (int[] config : RAW_COMBINATIONS) {
413                         testReprocessStreamCombination(id, config, maxSizes, staticInfo);
414                     }
415                 }
416 
417                 if (mStaticInfo.isHardwareLevelAtLeast(
418                         CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
419                     for (int[] config: LEVEL_3_COMBINATIONS) {
420                         testReprocessStreamCombination(id, config, maxSizes, staticInfo);
421                     }
422                 }
423             } finally {
424                 closeDevice(id);
425             }
426         }
427     }
428 
testBasicTriggerSequence()429     public void testBasicTriggerSequence() throws Exception {
430 
431         for (String id : mCameraIds) {
432             Log.i(TAG, String.format("Testing Camera %s", id));
433 
434             openDevice(id);
435             try {
436                 // Legacy devices do not support precapture trigger; don't test devices that
437                 // can't focus
438                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
439                     continue;
440                 }
441                 // Depth-only devices won't support AE
442                 if (!mStaticInfo.isColorOutputSupported()) {
443                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
444                     continue;
445                 }
446 
447                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
448                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
449                 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
450                     CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
451 
452                 for (int afMode : availableAfModes) {
453 
454                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
455                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
456                         // Only test AF modes that have meaningful trigger behavior
457                         continue;
458                     }
459 
460                     for (int aeMode : availableAeModes) {
461                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
462                             // Only test AE modes that have meaningful trigger behavior
463                             continue;
464                         }
465 
466                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
467 
468                         CaptureRequest.Builder previewRequest =
469                                 prepareTriggerTestSession(preview, aeMode, afMode);
470 
471                         SimpleCaptureCallback captureListener =
472                                 new CameraTestUtils.SimpleCaptureCallback();
473 
474                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
475                                 mHandler);
476 
477                         // Cancel triggers
478 
479                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
480 
481                         //
482                         // Standard sequence - AF trigger then AE trigger
483 
484                         if (VERBOSE) {
485                             Log.v(TAG, String.format("Triggering AF"));
486                         }
487 
488                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
489                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
490                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
491                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
492 
493                         CaptureRequest triggerRequest = previewRequest.build();
494                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
495 
496                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
497                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
498                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
499                         boolean focusComplete = false;
500 
501                         for (int i = 0;
502                              i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete;
503                              i++) {
504 
505                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
506 
507                             CaptureResult focusResult = captureListener.getCaptureResult(
508                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
509                             afState = focusResult.get(CaptureResult.CONTROL_AF_STATE);
510                         }
511 
512                         assertTrue("Focusing never completed!", focusComplete);
513 
514                         // Standard sequence - Part 2 AE trigger
515 
516                         if (VERBOSE) {
517                             Log.v(TAG, String.format("Triggering AE"));
518                         }
519 
520                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
521                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
522                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
523                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
524 
525                         triggerRequest = previewRequest.build();
526                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
527 
528                         triggerResult = captureListener.getCaptureResultForRequest(
529                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
530 
531                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
532 
533                         boolean precaptureComplete = false;
534 
535                         for (int i = 0;
536                              i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete;
537                              i++) {
538 
539                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
540 
541                             CaptureResult precaptureResult = captureListener.getCaptureResult(
542                                 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
543                             aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE);
544                         }
545 
546                         assertTrue("Precapture sequence never completed!", precaptureComplete);
547 
548                         for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) {
549                             CaptureResult postPrecaptureResult = captureListener.getCaptureResult(
550                                 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
551                             aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE);
552                             assertTrue("Late transition to PRECAPTURE state seen",
553                                     aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
554                         }
555 
556                         // Done
557 
558                         stopCapture(/*fast*/ false);
559                         preview.release();
560                     }
561 
562                 }
563 
564             } finally {
565                 closeDevice(id);
566             }
567         }
568 
569     }
570 
testSimultaneousTriggers()571     public void testSimultaneousTriggers() throws Exception {
572         for (String id : mCameraIds) {
573             Log.i(TAG, String.format("Testing Camera %s", id));
574 
575             openDevice(id);
576             try {
577                 // Legacy devices do not support precapture trigger; don't test devices that
578                 // can't focus
579                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
580                     continue;
581                 }
582                 // Depth-only devices won't support AE
583                 if (!mStaticInfo.isColorOutputSupported()) {
584                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
585                     continue;
586                 }
587 
588                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
589                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
590                 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
591                     CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
592 
593                 for (int afMode : availableAfModes) {
594 
595                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
596                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
597                         // Only test AF modes that have meaningful trigger behavior
598                         continue;
599                     }
600 
601                     for (int aeMode : availableAeModes) {
602                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
603                             // Only test AE modes that have meaningful trigger behavior
604                             continue;
605                         }
606 
607                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
608 
609                         CaptureRequest.Builder previewRequest =
610                                 prepareTriggerTestSession(preview, aeMode, afMode);
611 
612                         SimpleCaptureCallback captureListener =
613                                 new CameraTestUtils.SimpleCaptureCallback();
614 
615                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
616                                 mHandler);
617 
618                         // Cancel triggers
619 
620                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
621 
622                         //
623                         // Trigger AF and AE together
624 
625                         if (VERBOSE) {
626                             Log.v(TAG, String.format("Triggering AF and AE together"));
627                         }
628 
629                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
630                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
631                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
632                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
633 
634                         CaptureRequest triggerRequest = previewRequest.build();
635                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
636 
637                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
638                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
639                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
640                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
641 
642                         boolean precaptureComplete = false;
643                         boolean focusComplete = false;
644 
645                         for (int i = 0;
646                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
647                                      !(focusComplete && precaptureComplete);
648                              i++) {
649 
650                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
651                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
652 
653                             CaptureResult sequenceResult = captureListener.getCaptureResult(
654                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
655                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
656                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
657                         }
658 
659                         assertTrue("Precapture sequence never completed!", precaptureComplete);
660                         assertTrue("Focus sequence never completed!", focusComplete);
661 
662                         // Done
663 
664                         stopCapture(/*fast*/ false);
665                         preview.release();
666 
667                     }
668                 }
669             } finally {
670                 closeDevice(id);
671             }
672         }
673     }
674 
testAfThenAeTrigger()675     public void testAfThenAeTrigger() throws Exception {
676         for (String id : mCameraIds) {
677             Log.i(TAG, String.format("Testing Camera %s", id));
678 
679             openDevice(id);
680             try {
681                 // Legacy devices do not support precapture trigger; don't test devices that
682                 // can't focus
683                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
684                     continue;
685                 }
686                 // Depth-only devices won't support AE
687                 if (!mStaticInfo.isColorOutputSupported()) {
688                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
689                     continue;
690                 }
691 
692                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
693                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
694                 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
695                     CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
696 
697                 for (int afMode : availableAfModes) {
698 
699                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
700                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
701                         // Only test AF modes that have meaningful trigger behavior
702                         continue;
703                     }
704 
705                     for (int aeMode : availableAeModes) {
706                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
707                             // Only test AE modes that have meaningful trigger behavior
708                             continue;
709                         }
710 
711                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
712 
713                         CaptureRequest.Builder previewRequest =
714                                 prepareTriggerTestSession(preview, aeMode, afMode);
715 
716                         SimpleCaptureCallback captureListener =
717                                 new CameraTestUtils.SimpleCaptureCallback();
718 
719                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
720                                 mHandler);
721 
722                         // Cancel triggers
723 
724                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
725 
726                         //
727                         // AF with AE a request later
728 
729                         if (VERBOSE) {
730                             Log.v(TAG, "Trigger AF, then AE trigger on next request");
731                         }
732 
733                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
734                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
735                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
736                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
737 
738                         CaptureRequest triggerRequest = previewRequest.build();
739                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
740 
741                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
742                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
743                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
744                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
745 
746                         CaptureRequest triggerRequest2 = previewRequest.build();
747                         mCameraSession.capture(triggerRequest2, captureListener, mHandler);
748 
749                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
750                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
751                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
752 
753                         boolean precaptureComplete = false;
754                         boolean focusComplete = false;
755 
756                         focusComplete = verifyAfSequence(afMode, afState, focusComplete);
757 
758                         triggerResult = captureListener.getCaptureResultForRequest(
759                                 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
760                         afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
761                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
762 
763                         for (int i = 0;
764                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
765                                      !(focusComplete && precaptureComplete);
766                              i++) {
767 
768                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
769                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
770 
771                             CaptureResult sequenceResult = captureListener.getCaptureResult(
772                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
773                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
774                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
775                         }
776 
777                         assertTrue("Precapture sequence never completed!", precaptureComplete);
778                         assertTrue("Focus sequence never completed!", focusComplete);
779 
780                         // Done
781 
782                         stopCapture(/*fast*/ false);
783                         preview.release();
784 
785                     }
786                 }
787             } finally {
788                 closeDevice(id);
789             }
790         }
791     }
792 
testAeThenAfTrigger()793     public void testAeThenAfTrigger() throws Exception {
794         for (String id : mCameraIds) {
795             Log.i(TAG, String.format("Testing Camera %s", id));
796 
797             openDevice(id);
798             try {
799                 // Legacy devices do not support precapture trigger; don't test devices that
800                 // can't focus
801                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
802                     continue;
803                 }
804                 // Depth-only devices won't support AE
805                 if (!mStaticInfo.isColorOutputSupported()) {
806                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
807                     continue;
808                 }
809 
810                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
811                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
812                 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
813                     CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
814 
815                 for (int afMode : availableAfModes) {
816 
817                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
818                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
819                         // Only test AF modes that have meaningful trigger behavior
820                         continue;
821                     }
822 
823                     for (int aeMode : availableAeModes) {
824                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
825                             // Only test AE modes that have meaningful trigger behavior
826                             continue;
827                         }
828 
829                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
830 
831                         CaptureRequest.Builder previewRequest =
832                                 prepareTriggerTestSession(preview, aeMode, afMode);
833 
834                         SimpleCaptureCallback captureListener =
835                                 new CameraTestUtils.SimpleCaptureCallback();
836 
837                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
838                                 mHandler);
839 
840                         // Cancel triggers
841 
842                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
843 
844                         //
845                         // AE with AF a request later
846 
847                         if (VERBOSE) {
848                             Log.v(TAG, "Trigger AE, then AF trigger on next request");
849                         }
850 
851                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
852                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
853                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
854                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
855 
856                         CaptureRequest triggerRequest = previewRequest.build();
857                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
858 
859                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
860                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
861                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
862                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
863 
864                         CaptureRequest triggerRequest2 = previewRequest.build();
865                         mCameraSession.capture(triggerRequest2, captureListener, mHandler);
866 
867                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
868                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
869                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
870 
871                         boolean precaptureComplete = false;
872                         boolean focusComplete = false;
873 
874                         precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
875 
876                         triggerResult = captureListener.getCaptureResultForRequest(
877                                 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
878                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
879                         aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
880 
881                         for (int i = 0;
882                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
883                                      !(focusComplete && precaptureComplete);
884                              i++) {
885 
886                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
887                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
888 
889                             CaptureResult sequenceResult = captureListener.getCaptureResult(
890                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
891                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
892                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
893                         }
894 
895                         assertTrue("Precapture sequence never completed!", precaptureComplete);
896                         assertTrue("Focus sequence never completed!", focusComplete);
897 
898                         // Done
899 
900                         stopCapture(/*fast*/ false);
901                         preview.release();
902 
903                     }
904                 }
905             } finally {
906                 closeDevice(id);
907             }
908         }
909     }
910 
testAbandonRepeatingRequestSurface()911     public void testAbandonRepeatingRequestSurface() throws Exception {
912         for (String id : mCameraIds) {
913             Log.i(TAG, String.format(
914                     "Testing Camera %s for abandoning surface of a repeating request", id));
915 
916             openDevice(id);
917             try {
918                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
919                 Surface previewSurface = new Surface(preview);
920 
921                 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
922                 SimpleCaptureCallback captureListener = new CameraTestUtils.SimpleCaptureCallback();
923 
924                 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(),
925                         captureListener, mHandler);
926 
927                 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) {
928                     captureListener.getTotalCaptureResult(CAPTURE_TIMEOUT);
929                 }
930 
931                 // Abandon preview surface.
932                 preview.release();
933 
934                 // Check onCaptureSequenceCompleted is received.
935                 long sequenceLastFrameNumber = captureListener.getCaptureSequenceLastFrameNumber(
936                         sequenceId, CAPTURE_TIMEOUT);
937 
938                 mCameraSession.stopRepeating();
939 
940                 // Find the last frame number received in results and failures.
941                 long lastFrameNumber = -1;
942                 while (captureListener.hasMoreResults()) {
943                     TotalCaptureResult result = captureListener.getTotalCaptureResult(
944                             CAPTURE_TIMEOUT);
945                     if (lastFrameNumber < result.getFrameNumber()) {
946                         lastFrameNumber = result.getFrameNumber();
947                     }
948                 }
949 
950                 while (captureListener.hasMoreFailures()) {
951                     ArrayList<CaptureFailure> failures = captureListener.getCaptureFailures(
952                             /*maxNumFailures*/ 1);
953                     for (CaptureFailure failure : failures) {
954                         if (lastFrameNumber < failure.getFrameNumber()) {
955                             lastFrameNumber = failure.getFrameNumber();
956                         }
957                     }
958                 }
959 
960                 // Verify the last frame number received from capture sequence completed matches the
961                 // the last frame number of the results and failures.
962                 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " +
963                         "(%d) doesn't match the last frame number received from " +
964                         "results/failures (%d)", sequenceLastFrameNumber, lastFrameNumber),
965                         sequenceLastFrameNumber, lastFrameNumber);
966             } finally {
967                 closeDevice(id);
968             }
969         }
970     }
971 
preparePreviewTestSession(SurfaceTexture preview)972     private CaptureRequest.Builder preparePreviewTestSession(SurfaceTexture preview)
973             throws Exception {
974         Surface previewSurface = new Surface(preview);
975 
976         preview.setDefaultBufferSize(640, 480);
977 
978         ArrayList<Surface> sessionOutputs = new ArrayList<>();
979         sessionOutputs.add(previewSurface);
980 
981         createSession(sessionOutputs);
982 
983         CaptureRequest.Builder previewRequest =
984                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
985 
986         previewRequest.addTarget(previewSurface);
987 
988         return previewRequest;
989     }
990 
prepareTriggerTestSession( SurfaceTexture preview, int aeMode, int afMode)991     private CaptureRequest.Builder prepareTriggerTestSession(
992             SurfaceTexture preview, int aeMode, int afMode) throws Exception {
993         Log.i(TAG, String.format("Testing AE mode %s, AF mode %s",
994                         StaticMetadata.AE_MODE_NAMES[aeMode],
995                         StaticMetadata.AF_MODE_NAMES[afMode]));
996 
997         CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
998         previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode);
999         previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode);
1000 
1001         return previewRequest;
1002     }
1003 
cancelTriggersAndWait(CaptureRequest.Builder previewRequest, SimpleCaptureCallback captureListener, int afMode)1004     private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest,
1005             SimpleCaptureCallback captureListener, int afMode) throws Exception {
1006         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
1007                 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
1008         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
1009                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
1010 
1011         CaptureRequest triggerRequest = previewRequest.build();
1012         mCameraSession.capture(triggerRequest, captureListener, mHandler);
1013 
1014         // Wait for a few frames to initialize 3A
1015 
1016         CaptureResult previewResult = null;
1017         int afState;
1018         int aeState;
1019 
1020         for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) {
1021             previewResult = captureListener.getCaptureResult(
1022                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
1023             if (VERBOSE) {
1024                 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
1025                 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
1026                 Log.v(TAG, String.format("AF state: %s, AE state: %s",
1027                                 StaticMetadata.AF_STATE_NAMES[afState],
1028                                 StaticMetadata.AE_STATE_NAMES[aeState]));
1029             }
1030         }
1031 
1032         // Verify starting states
1033 
1034         afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
1035         aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
1036 
1037         switch (afMode) {
1038             case CaptureResult.CONTROL_AF_MODE_AUTO:
1039             case CaptureResult.CONTROL_AF_MODE_MACRO:
1040                 assertTrue(String.format("AF state not INACTIVE, is %s",
1041                                 StaticMetadata.AF_STATE_NAMES[afState]),
1042                         afState == CaptureResult.CONTROL_AF_STATE_INACTIVE);
1043                 break;
1044             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
1045             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
1046                 // After several frames, AF must no longer be in INACTIVE state
1047                 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" +
1048                                 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s",
1049                                 StaticMetadata.AF_MODE_NAMES[afMode],
1050                                 StaticMetadata.AF_STATE_NAMES[afState]),
1051                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
1052                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED ||
1053                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED);
1054                 break;
1055             default:
1056                 fail("unexpected af mode");
1057         }
1058 
1059         // After several frames, AE must no longer be in INACTIVE state
1060         assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " +
1061                         "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]),
1062                 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING ||
1063                 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED ||
1064                 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED);
1065     }
1066 
verifyAfSequence(int afMode, int afState, boolean focusComplete)1067     private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) {
1068         if (focusComplete) {
1069             assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s",
1070                             StaticMetadata.AF_MODE_NAMES[afMode],
1071                             StaticMetadata.AF_STATE_NAMES[afState]),
1072                     afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
1073                     afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
1074             return focusComplete;
1075         }
1076         if (VERBOSE) {
1077             Log.v(TAG, String.format("AF mode: %s, AF state: %s",
1078                             StaticMetadata.AF_MODE_NAMES[afMode],
1079                             StaticMetadata.AF_STATE_NAMES[afState]));
1080         }
1081         switch (afMode) {
1082             case CaptureResult.CONTROL_AF_MODE_AUTO:
1083             case CaptureResult.CONTROL_AF_MODE_MACRO:
1084                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
1085                                 StaticMetadata.AF_MODE_NAMES[afMode],
1086                                 StaticMetadata.AF_STATE_NAMES[afState]),
1087                         afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN ||
1088                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
1089                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
1090                 focusComplete =
1091                         (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN);
1092                 break;
1093             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
1094                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
1095                                 StaticMetadata.AF_MODE_NAMES[afMode],
1096                                 StaticMetadata.AF_STATE_NAMES[afState]),
1097                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
1098                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
1099                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
1100                 focusComplete =
1101                         (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN);
1102                 break;
1103             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
1104                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
1105                                 StaticMetadata.AF_MODE_NAMES[afMode],
1106                                 StaticMetadata.AF_STATE_NAMES[afState]),
1107                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
1108                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
1109                 focusComplete = true;
1110                 break;
1111             default:
1112                 fail("Unexpected AF mode: " + StaticMetadata.AF_MODE_NAMES[afMode]);
1113         }
1114         return focusComplete;
1115     }
1116 
verifyAeSequence(int aeState, boolean precaptureComplete)1117     private boolean verifyAeSequence(int aeState, boolean precaptureComplete) {
1118         if (precaptureComplete) {
1119             assertTrue("Precapture state seen after convergence",
1120                     aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
1121             return precaptureComplete;
1122         }
1123         if (VERBOSE) {
1124             Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState]));
1125         }
1126         switch (aeState) {
1127             case CaptureResult.CONTROL_AE_STATE_PRECAPTURE:
1128                 // scan still continuing
1129                 break;
1130             case CaptureResult.CONTROL_AE_STATE_CONVERGED:
1131             case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
1132                 // completed
1133                 precaptureComplete = true;
1134                 break;
1135             default:
1136                 fail(String.format("Precapture sequence transitioned to "
1137                                 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState]));
1138                 break;
1139         }
1140         return precaptureComplete;
1141     }
1142 
1143     /**
1144      * Sanity check the configuration tables.
1145      */
sanityCheckConfigurationTables(final int[][][] tables)1146     private void sanityCheckConfigurationTables(final int[][][] tables) throws Exception {
1147         int tableIdx = 0;
1148         for (int[][] table : tables) {
1149             int rowIdx = 0;
1150             for (int[] row : table) {
1151                 assertTrue(String.format("Odd number of entries for table %d row %d: %s ",
1152                                 tableIdx, rowIdx, Arrays.toString(row)),
1153                         (row.length % 2) == 0);
1154                 for (int i = 0; i < row.length; i += 2) {
1155                     int format = row[i];
1156                     int maxSize = row[i + 1];
1157                     assertTrue(String.format("table %d row %d index %d format not valid: %d",
1158                                     tableIdx, rowIdx, i, format),
1159                             format == PRIV || format == JPEG || format == YUV || format == RAW);
1160                     assertTrue(String.format("table %d row %d index %d max size not valid: %d",
1161                                     tableIdx, rowIdx, i + 1, maxSize),
1162                             maxSize == PREVIEW || maxSize == RECORD ||
1163                             maxSize == MAXIMUM || maxSize == VGA);
1164                 }
1165                 rowIdx++;
1166             }
1167             tableIdx++;
1168         }
1169     }
1170 
1171     /**
1172      * Simple holder for resolutions to use for different camera outputs and size limits.
1173      */
1174     static class MaxStreamSizes {
1175         // Format shorthands
1176         static final int PRIV = ImageFormat.PRIVATE;
1177         static final int JPEG = ImageFormat.JPEG;
1178         static final int YUV  = ImageFormat.YUV_420_888;
1179         static final int RAW  = ImageFormat.RAW_SENSOR;
1180 
1181         // Max resolution indices
1182         static final int PREVIEW = 0;
1183         static final int RECORD  = 1;
1184         static final int MAXIMUM = 2;
1185         static final int VGA = 3;
1186         static final int RESOLUTION_COUNT = 4;
1187 
MaxStreamSizes(StaticMetadata sm, String cameraId, Context context)1188         public MaxStreamSizes(StaticMetadata sm, String cameraId, Context context) {
1189             Size[] privSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.PRIVATE,
1190                     StaticMetadata.StreamDirection.Output);
1191             Size[] yuvSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
1192                     StaticMetadata.StreamDirection.Output);
1193             Size[] jpegSizes = sm.getJpegOutputSizesChecked();
1194             Size[] rawSizes = sm.getRawOutputSizesChecked();
1195 
1196             Size maxPreviewSize = getMaxPreviewSize(context, cameraId);
1197 
1198             maxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null;
1199 
1200             if (sm.isColorOutputSupported()) {
1201                 maxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize);
1202                 maxYuvSizes[PREVIEW]  = getMaxSize(yuvSizes, maxPreviewSize);
1203                 maxJpegSizes[PREVIEW] = getMaxSize(jpegSizes, maxPreviewSize);
1204 
1205                 maxPrivSizes[RECORD] = getMaxRecordingSize(cameraId);
1206                 maxYuvSizes[RECORD]  = getMaxRecordingSize(cameraId);
1207                 maxJpegSizes[RECORD] = getMaxRecordingSize(cameraId);
1208 
1209                 maxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes);
1210                 maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
1211                 maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
1212 
1213                 // Must always be supported, add unconditionally
1214                 final Size vgaSize = new Size(640, 480);
1215                 maxPrivSizes[VGA] = vgaSize;
1216                 maxYuvSizes[VGA] = vgaSize;
1217                 maxJpegSizes[VGA] = vgaSize;
1218             }
1219 
1220             StreamConfigurationMap configs = sm.getCharacteristics().get(
1221                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1222             Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
1223             maxInputPrivSize = privInputSizes != null ?
1224                     CameraTestUtils.getMaxSize(privInputSizes) : null;
1225             Size[] yuvInputSizes = configs.getInputSizes(ImageFormat.YUV_420_888);
1226             maxInputYuvSize = yuvInputSizes != null ?
1227                     CameraTestUtils.getMaxSize(yuvInputSizes) : null;
1228 
1229         }
1230 
1231         public final Size[] maxPrivSizes = new Size[RESOLUTION_COUNT];
1232         public final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
1233         public final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
1234         public final Size maxRawSize;
1235         // TODO: support non maximum reprocess input.
1236         public final Size maxInputPrivSize;
1237         public final Size maxInputYuvSize;
1238 
configToString(int[] config)1239         static public String configToString(int[] config) {
1240             StringBuilder b = new StringBuilder("{ ");
1241             for (int i = 0; i < config.length; i += 2) {
1242                 int format = config[i];
1243                 int sizeLimit = config[i + 1];
1244 
1245                 appendFormatSize(b, format, sizeLimit);
1246                 b.append(" ");
1247             }
1248             b.append("}");
1249             return b.toString();
1250         }
1251 
reprocessConfigToString(int[] reprocessConfig)1252         static public String reprocessConfigToString(int[] reprocessConfig) {
1253             // reprocessConfig[0..1] is the input configuration
1254             StringBuilder b = new StringBuilder("Input: ");
1255             appendFormatSize(b, reprocessConfig[0], reprocessConfig[1]);
1256 
1257             // reprocessConfig[0..1] is also output configuration to be captured as reprocess input.
1258             b.append(", Outputs: { ");
1259             for (int i = 0; i < reprocessConfig.length; i += 2) {
1260                 int format = reprocessConfig[i];
1261                 int sizeLimit = reprocessConfig[i + 1];
1262 
1263                 appendFormatSize(b, format, sizeLimit);
1264                 b.append(" ");
1265             }
1266             b.append("}");
1267             return b.toString();
1268         }
1269 
appendFormatSize(StringBuilder b, int format, int Size)1270         static private void appendFormatSize(StringBuilder b, int format, int Size) {
1271             switch (format) {
1272                 case PRIV:
1273                     b.append("[PRIV, ");
1274                     break;
1275                 case JPEG:
1276                     b.append("[JPEG, ");
1277                     break;
1278                 case YUV:
1279                     b.append("[YUV, ");
1280                     break;
1281                 case RAW:
1282                     b.append("[RAW, ");
1283                     break;
1284                 default:
1285                     b.append("[UNK, ");
1286                     break;
1287             }
1288 
1289             switch (Size) {
1290                 case PREVIEW:
1291                     b.append("PREVIEW]");
1292                     break;
1293                 case RECORD:
1294                     b.append("RECORD]");
1295                     break;
1296                 case MAXIMUM:
1297                     b.append("MAXIMUM]");
1298                     break;
1299                 case VGA:
1300                     b.append("VGA]");
1301                     break;
1302                 default:
1303                     b.append("UNK]");
1304                     break;
1305             }
1306         }
1307     }
1308 
1309     /**
1310      * Return an InputConfiguration for a given reprocess configuration.
1311      */
getInputConfig(int[] reprocessConfig, MaxStreamSizes maxSizes)1312     private InputConfiguration getInputConfig(int[] reprocessConfig, MaxStreamSizes maxSizes) {
1313         int format;
1314         Size size;
1315 
1316         if (reprocessConfig[1] != MAXIMUM) {
1317             throw new IllegalArgumentException("Test only supports MAXIMUM input");
1318         }
1319 
1320         switch (reprocessConfig[0]) {
1321             case PRIV:
1322                 format = ImageFormat.PRIVATE;
1323                 size = maxSizes.maxInputPrivSize;
1324                 break;
1325             case YUV:
1326                 format = ImageFormat.YUV_420_888;
1327                 size = maxSizes.maxInputYuvSize;
1328                 break;
1329             default:
1330                 throw new IllegalArgumentException("Input format not supported: " +
1331                         reprocessConfig[0]);
1332         }
1333 
1334         return new InputConfiguration(size.getWidth(), size.getHeight(), format);
1335     }
1336 
testReprocessStreamCombination(String cameraId, int[] reprocessConfig, MaxStreamSizes maxSizes, StaticMetadata staticInfo)1337     private void testReprocessStreamCombination(String cameraId, int[] reprocessConfig,
1338             MaxStreamSizes maxSizes, StaticMetadata staticInfo) throws Exception {
1339 
1340         Log.i(TAG, String.format("Testing Camera %s, reprocess config: %s", cameraId,
1341                 MaxStreamSizes.reprocessConfigToString(reprocessConfig)));
1342 
1343         final int TIMEOUT_FOR_RESULT_MS = 3000;
1344         final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3;
1345 
1346         List<SurfaceTexture> privTargets = new ArrayList<>();
1347         List<ImageReader> jpegTargets = new ArrayList<>();
1348         List<ImageReader> yuvTargets = new ArrayList<>();
1349         List<ImageReader> rawTargets = new ArrayList<>();
1350         List<Surface> outputSurfaces = new ArrayList<>();
1351         ImageReader inputReader = null;
1352         ImageWriter inputWriter = null;
1353         SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener();
1354         SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback();
1355         SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback();
1356 
1357         boolean supportYuvReprocess = staticInfo.isCapabilitySupported(
1358                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
1359         boolean supportOpaqueReprocess = staticInfo.isCapabilitySupported(
1360                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
1361 
1362         // Skip the configuration if the format is not supported for reprocessing.
1363         if ((reprocessConfig[0] == YUV && !supportYuvReprocess) ||
1364                 (reprocessConfig[0] == PRIV && !supportOpaqueReprocess)) {
1365             return;
1366         }
1367 
1368         try {
1369             // reprocessConfig[2..] are additional outputs
1370             setupConfigurationTargets(
1371                     Arrays.copyOfRange(reprocessConfig, 2, reprocessConfig.length),
1372                     maxSizes, privTargets, jpegTargets, yuvTargets, rawTargets, outputSurfaces,
1373                     NUM_REPROCESS_CAPTURES_PER_CONFIG);
1374 
1375             // reprocessConfig[0:1] is input
1376             InputConfiguration inputConfig = getInputConfig(
1377                     Arrays.copyOfRange(reprocessConfig, 0, 2), maxSizes);
1378 
1379             // For each config, YUV and JPEG outputs will be tested. (For YUV reprocessing,
1380             // the YUV ImageReader for input is also used for output.)
1381             final int totalNumReprocessCaptures =  NUM_REPROCESS_CAPTURES_PER_CONFIG * (
1382                     (inputConfig.getFormat() == ImageFormat.YUV_420_888 ? 1 : 0) +
1383                     jpegTargets.size() + yuvTargets.size());
1384 
1385             // It needs 1 input buffer for each reprocess capture + the number of buffers
1386             // that will be used as outputs.
1387             inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(),
1388                     inputConfig.getFormat(),
1389                     totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG);
1390             inputReader.setOnImageAvailableListener(inputReaderListener, mHandler);
1391             outputSurfaces.add(inputReader.getSurface());
1392 
1393             // Verify we can create a reprocessable session with the input and all outputs.
1394             BlockingSessionCallback sessionListener = new BlockingSessionCallback();
1395             CameraCaptureSession session = configureReprocessableCameraSession(mCamera,
1396                     inputConfig, outputSurfaces, sessionListener, mHandler);
1397             inputWriter = ImageWriter.newInstance(session.getInputSurface(),
1398                     totalNumReprocessCaptures);
1399 
1400             // Prepare a request for reprocess input
1401             CaptureRequest.Builder builder = mCamera.createCaptureRequest(
1402                     CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
1403             builder.addTarget(inputReader.getSurface());
1404 
1405             for (int i = 0; i < totalNumReprocessCaptures; i++) {
1406                 session.capture(builder.build(), inputCaptureListener, mHandler);
1407             }
1408 
1409             List<CaptureRequest> reprocessRequests = new ArrayList<>();
1410             List<Surface> reprocessOutputs = new ArrayList<>();
1411             if (inputConfig.getFormat() == ImageFormat.YUV_420_888) {
1412                 reprocessOutputs.add(inputReader.getSurface());
1413             }
1414 
1415             for (ImageReader reader : jpegTargets) {
1416                 reprocessOutputs.add(reader.getSurface());
1417             }
1418 
1419             for (ImageReader reader : yuvTargets) {
1420                 reprocessOutputs.add(reader.getSurface());
1421             }
1422 
1423             for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
1424                 for (Surface output : reprocessOutputs) {
1425                     TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult(
1426                             TIMEOUT_FOR_RESULT_MS);
1427                     builder =  mCamera.createReprocessCaptureRequest(result);
1428                     inputWriter.queueInputImage(
1429                             inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS));
1430                     builder.addTarget(output);
1431                     reprocessRequests.add(builder.build());
1432                 }
1433             }
1434 
1435             session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler);
1436 
1437             for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
1438                 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult(
1439                         TIMEOUT_FOR_RESULT_MS);
1440             }
1441         } catch (Throwable e) {
1442             mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s",
1443                     MaxStreamSizes.reprocessConfigToString(reprocessConfig), e.getMessage()));
1444         } finally {
1445             inputReaderListener.drain();
1446             reprocessOutputCaptureListener.drain();
1447 
1448             for (SurfaceTexture target : privTargets) {
1449                 target.release();
1450             }
1451 
1452             for (ImageReader target : jpegTargets) {
1453                 target.close();
1454             }
1455 
1456             for (ImageReader target : yuvTargets) {
1457                 target.close();
1458             }
1459 
1460             for (ImageReader target : rawTargets) {
1461                 target.close();
1462             }
1463 
1464             if (inputReader != null) {
1465                 inputReader.close();
1466             }
1467 
1468             if (inputWriter != null) {
1469                 inputWriter.close();
1470             }
1471         }
1472     }
1473 
testOutputCombination(String cameraId, int[] config, MaxStreamSizes maxSizes)1474     private void testOutputCombination(String cameraId, int[] config, MaxStreamSizes maxSizes)
1475             throws Exception {
1476 
1477         Log.i(TAG, String.format("Testing Camera %s, config %s",
1478                         cameraId, MaxStreamSizes.configToString(config)));
1479 
1480         // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
1481         final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
1482         final int MIN_RESULT_COUNT = 3;
1483 
1484         // Set up outputs
1485         List<Surface> outputSurfaces = new ArrayList<Surface>();
1486         List<SurfaceTexture> privTargets = new ArrayList<SurfaceTexture>();
1487         List<ImageReader> jpegTargets = new ArrayList<ImageReader>();
1488         List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
1489         List<ImageReader> rawTargets = new ArrayList<ImageReader>();
1490 
1491         setupConfigurationTargets(config, maxSizes, privTargets, jpegTargets, yuvTargets,
1492                 rawTargets, outputSurfaces, MIN_RESULT_COUNT);
1493 
1494         boolean haveSession = false;
1495         try {
1496             CaptureRequest.Builder requestBuilder =
1497                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1498 
1499             for (Surface s : outputSurfaces) {
1500                 requestBuilder.addTarget(s);
1501             }
1502 
1503             CameraCaptureSession.CaptureCallback mockCaptureCallback =
1504                     mock(CameraCaptureSession.CaptureCallback.class);
1505 
1506             createSession(outputSurfaces);
1507             haveSession = true;
1508             CaptureRequest request = requestBuilder.build();
1509             mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler);
1510 
1511             verify(mockCaptureCallback,
1512                     timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT))
1513                     .onCaptureCompleted(
1514                         eq(mCameraSession),
1515                         eq(request),
1516                         isA(TotalCaptureResult.class));
1517             verify(mockCaptureCallback, never()).
1518                     onCaptureFailed(
1519                         eq(mCameraSession),
1520                         eq(request),
1521                         isA(CaptureFailure.class));
1522 
1523         } catch (Throwable e) {
1524             mCollector.addMessage(String.format("Output combination %s failed due to: %s",
1525                     MaxStreamSizes.configToString(config), e.getMessage()));
1526         }
1527         if (haveSession) {
1528             try {
1529                 Log.i(TAG, String.format("Done with camera %s, config %s, closing session",
1530                                 cameraId, MaxStreamSizes.configToString(config)));
1531                 stopCapture(/*fast*/false);
1532             } catch (Throwable e) {
1533                 mCollector.addMessage(
1534                     String.format("Closing down for output combination %s failed due to: %s",
1535                             MaxStreamSizes.configToString(config), e.getMessage()));
1536             }
1537         }
1538 
1539         for (SurfaceTexture target : privTargets) {
1540             target.release();
1541         }
1542         for (ImageReader target : jpegTargets) {
1543             target.close();
1544         }
1545         for (ImageReader target : yuvTargets) {
1546             target.close();
1547         }
1548         for (ImageReader target : rawTargets) {
1549             target.close();
1550         }
1551     }
1552 
setupConfigurationTargets(int[] outputConfigs, MaxStreamSizes maxSizes, List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets, List<ImageReader> yuvTargets, List<ImageReader> rawTargets, List<Surface> outputSurfaces, int numBuffers)1553     private void setupConfigurationTargets(int[] outputConfigs, MaxStreamSizes maxSizes,
1554             List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
1555             List<ImageReader> yuvTargets, List<ImageReader> rawTargets,
1556             List<Surface> outputSurfaces, int numBuffers) {
1557 
1558         ImageDropperListener imageDropperListener = new ImageDropperListener();
1559 
1560         for (int i = 0; i < outputConfigs.length; i += 2) {
1561             int format = outputConfigs[i];
1562             int sizeLimit = outputConfigs[i + 1];
1563 
1564             switch (format) {
1565                 case PRIV: {
1566                     Size targetSize = maxSizes.maxPrivSizes[sizeLimit];
1567                     SurfaceTexture target = new SurfaceTexture(/*random int*/1);
1568                     target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight());
1569                     outputSurfaces.add(new Surface(target));
1570                     privTargets.add(target);
1571                     break;
1572                 }
1573                 case JPEG: {
1574                     Size targetSize = maxSizes.maxJpegSizes[sizeLimit];
1575                     ImageReader target = ImageReader.newInstance(
1576                         targetSize.getWidth(), targetSize.getHeight(), JPEG, numBuffers);
1577                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
1578                     outputSurfaces.add(target.getSurface());
1579                     jpegTargets.add(target);
1580                     break;
1581                 }
1582                 case YUV: {
1583                     Size targetSize = maxSizes.maxYuvSizes[sizeLimit];
1584                     ImageReader target = ImageReader.newInstance(
1585                         targetSize.getWidth(), targetSize.getHeight(), YUV, numBuffers);
1586                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
1587                     outputSurfaces.add(target.getSurface());
1588                     yuvTargets.add(target);
1589                     break;
1590                 }
1591                 case RAW: {
1592                     Size targetSize = maxSizes.maxRawSize;
1593                     ImageReader target = ImageReader.newInstance(
1594                         targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
1595                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
1596                     outputSurfaces.add(target.getSurface());
1597                     rawTargets.add(target);
1598                     break;
1599                 }
1600                 default:
1601                     fail("Unknown output format " + format);
1602             }
1603         }
1604     }
1605 
getMaxRecordingSize(String cameraId)1606     private static Size getMaxRecordingSize(String cameraId) {
1607         int id = Integer.valueOf(cameraId);
1608 
1609         int quality =
1610                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P) ?
1611                     CamcorderProfile.QUALITY_2160P :
1612                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P) ?
1613                     CamcorderProfile.QUALITY_1080P :
1614                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_720P) ?
1615                     CamcorderProfile.QUALITY_720P :
1616                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_480P) ?
1617                     CamcorderProfile.QUALITY_480P :
1618                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QVGA) ?
1619                     CamcorderProfile.QUALITY_QVGA :
1620                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_CIF) ?
1621                     CamcorderProfile.QUALITY_CIF :
1622                 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QCIF) ?
1623                     CamcorderProfile.QUALITY_QCIF :
1624                     -1;
1625 
1626         assertTrue("No recording supported for camera id " + cameraId, quality != -1);
1627 
1628         CamcorderProfile maxProfile = CamcorderProfile.get(id, quality);
1629         return new Size(maxProfile.videoFrameWidth, maxProfile.videoFrameHeight);
1630     }
1631 
1632     /**
1633      * Get maximum size in list that's equal or smaller to than the bound.
1634      * Returns null if no size is smaller than or equal to the bound.
1635      */
getMaxSize(Size[] sizes, Size bound)1636     private static Size getMaxSize(Size[] sizes, Size bound) {
1637         if (sizes == null || sizes.length == 0) {
1638             throw new IllegalArgumentException("sizes was empty");
1639         }
1640 
1641         Size sz = null;
1642         for (Size size : sizes) {
1643             if (size.getWidth() <= bound.getWidth() && size.getHeight() <= bound.getHeight()) {
1644 
1645                 if (sz == null) {
1646                     sz = size;
1647                 } else {
1648                     long curArea = sz.getWidth() * (long) sz.getHeight();
1649                     long newArea = size.getWidth() * (long) size.getHeight();
1650                     if ( newArea > curArea ) {
1651                         sz = size;
1652                     }
1653                 }
1654             }
1655         }
1656 
1657         assertTrue("No size under bound found: " + Arrays.toString(sizes) + " bound " + bound,
1658                 sz != null);
1659 
1660         return sz;
1661     }
1662 
getMaxPreviewSize(Context context, String cameraId)1663     private static Size getMaxPreviewSize(Context context, String cameraId) {
1664         try {
1665             WindowManager windowManager =
1666                 (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1667             Display display = windowManager.getDefaultDisplay();
1668 
1669             int width = display.getWidth();
1670             int height = display.getHeight();
1671 
1672             if (height > width) {
1673                 height = width;
1674                 width = display.getHeight();
1675             }
1676 
1677             CameraManager camMgr =
1678                 (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
1679             List<Size> orderedPreviewSizes = CameraTestUtils.getSupportedPreviewSizes(
1680                 cameraId, camMgr, PREVIEW_SIZE_BOUND);
1681 
1682             if (orderedPreviewSizes != null) {
1683                 for (Size size : orderedPreviewSizes) {
1684                     if (width >= size.getWidth() &&
1685                         height >= size.getHeight())
1686                         return size;
1687                 }
1688             }
1689         } catch (Exception e) {
1690             Log.e(TAG, "getMaxPreviewSize Failed. "+e.toString());
1691         }
1692         return PREVIEW_SIZE_BOUND;
1693     }
1694 }
1695