1 /*
2  * Copyright (C) 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 android.content.Context;
20 import android.graphics.ImageFormat;
21 import android.graphics.Rect;
22 import android.graphics.SurfaceTexture;
23 import android.hardware.camera2.CameraCharacteristics;
24 import android.hardware.camera2.CameraCharacteristics.Key;
25 import android.hardware.camera2.CameraManager;
26 import android.hardware.camera2.CaptureRequest;
27 import android.hardware.camera2.CaptureResult;
28 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
29 import android.hardware.camera2.params.BlackLevelPattern;
30 import android.hardware.camera2.params.ColorSpaceTransform;
31 import android.hardware.camera2.params.StreamConfigurationMap;
32 import android.media.CamcorderProfile;
33 import android.media.ImageReader;
34 import android.test.AndroidTestCase;
35 import android.util.Log;
36 import android.util.Rational;
37 import android.util.Range;
38 import android.util.Size;
39 import android.view.Surface;
40 
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.List;
44 import java.util.Objects;
45 
46 import static android.hardware.camera2.cts.helpers.AssertHelpers.*;
47 
48 /**
49  * Extended tests for static camera characteristics.
50  */
51 public class ExtendedCameraCharacteristicsTest extends AndroidTestCase {
52     private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw
53     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
54 
55     private static final String PREFIX_ANDROID = "android";
56     private static final String PREFIX_VENDOR = "com";
57 
58     /*
59      * Constants for static RAW metadata.
60      */
61     private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5
62 
63     private CameraManager mCameraManager;
64     private List<CameraCharacteristics> mCharacteristics;
65     private String[] mIds;
66     private CameraErrorCollector mCollector;
67 
68     private static final Size FULLHD = new Size(1920, 1080);
69     private static final Size FULLHD_ALT = new Size(1920, 1088);
70     private static final Size HD = new Size(1280, 720);
71     private static final Size VGA = new Size(640, 480);
72     private static final Size QVGA = new Size(320, 240);
73 
74     /*
75      * HW Levels short hand
76      */
77     private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
78     private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
79     private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
80     private static final int LEVEL_3 = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3;
81     private static final int OPT = Integer.MAX_VALUE;  // For keys that are optional on all hardware levels.
82 
83     /*
84      * Capabilities short hand
85      */
86     private static final int NONE = -1;
87     private static final int BC =
88             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
89     private static final int MANUAL_SENSOR =
90             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR;
91     private static final int MANUAL_POSTPROC =
92             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING;
93     private static final int RAW =
94             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW;
95     private static final int YUV_REPROCESS =
96             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING;
97     private static final int OPAQUE_REPROCESS =
98             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING;
99     private static final int CONSTRAINED_HIGH_SPEED =
100             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO;
101     private static final int HIGH_SPEED_FPS_LOWER_MIN = 30;
102     private static final int HIGH_SPEED_FPS_UPPER_MIN = 120;
103 
104     @Override
setContext(Context context)105     public void setContext(Context context) {
106         super.setContext(context);
107         mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
108         assertNotNull("Can't connect to camera manager", mCameraManager);
109     }
110 
111     @Override
setUp()112     protected void setUp() throws Exception {
113         super.setUp();
114         mIds = mCameraManager.getCameraIdList();
115         mCharacteristics = new ArrayList<>();
116         mCollector = new CameraErrorCollector();
117         for (int i = 0; i < mIds.length; i++) {
118             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]);
119             assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]),
120                     props);
121             mCharacteristics.add(props);
122         }
123     }
124 
125     @Override
tearDown()126     protected void tearDown() throws Exception {
127         mCharacteristics = null;
128 
129         try {
130             mCollector.verify();
131         } catch (Throwable e) {
132             // When new Exception(e) is used, exception info will be printed twice.
133             throw new Exception(e.getMessage());
134         } finally {
135             super.tearDown();
136         }
137     }
138 
139     /**
140      * Test that the available stream configurations contain a few required formats and sizes.
141      */
testAvailableStreamConfigs()142     public void testAvailableStreamConfigs() {
143         int counter = 0;
144         for (CameraCharacteristics c : mCharacteristics) {
145             StreamConfigurationMap config =
146                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
147             assertNotNull(String.format("No stream configuration map found for: ID %s",
148                     mIds[counter]), config);
149             int[] outputFormats = config.getOutputFormats();
150 
151             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
152             assertNotNull("android.request.availableCapabilities must never be null",
153                     actualCapabilities);
154 
155             // Check required formats exist (JPEG, and YUV_420_888).
156             if (!arrayContains(actualCapabilities, BC)) {
157                 Log.i(TAG, "Camera " + mIds[counter] +
158                     ": BACKWARD_COMPATIBLE capability not supported, skipping test");
159                 continue;
160             }
161 
162             assertArrayContains(
163                     String.format("No valid YUV_420_888 preview formats found for: ID %s",
164                             mIds[counter]), outputFormats, ImageFormat.YUV_420_888);
165             assertArrayContains(String.format("No JPEG image format for: ID %s",
166                     mIds[counter]), outputFormats, ImageFormat.JPEG);
167 
168             Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888);
169             Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG);
170             Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE);
171 
172             CameraTestUtils.assertArrayNotEmpty(yuvSizes,
173                     String.format("No sizes for preview format %x for: ID %s",
174                             ImageFormat.YUV_420_888, mIds[counter]));
175 
176             Rect activeRect = CameraTestUtils.getValueNotNull(
177                     c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
178             Size activeArraySize = new Size(activeRect.width(), activeRect.height());
179             Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
180 
181             if (activeArraySize.getWidth() >= FULLHD.getWidth() &&
182                     activeArraySize.getHeight() >= FULLHD.getHeight()) {
183                 assertArrayContainsAnyOf(String.format(
184                         "Required FULLHD size not found for format %x for: ID %s",
185                         ImageFormat.JPEG, mIds[counter]), jpegSizes,
186                         new Size[] {FULLHD, FULLHD_ALT});
187             }
188 
189             if (activeArraySize.getWidth() >= HD.getWidth() &&
190                     activeArraySize.getHeight() >= HD.getHeight()) {
191                 assertArrayContains(String.format(
192                         "Required HD size not found for format %x for: ID %s",
193                         ImageFormat.JPEG, mIds[counter]), jpegSizes, HD);
194             }
195 
196             if (activeArraySize.getWidth() >= VGA.getWidth() &&
197                     activeArraySize.getHeight() >= VGA.getHeight()) {
198                 assertArrayContains(String.format(
199                         "Required VGA size not found for format %x for: ID %s",
200                         ImageFormat.JPEG, mIds[counter]), jpegSizes, VGA);
201             }
202 
203             if (activeArraySize.getWidth() >= QVGA.getWidth() &&
204                     activeArraySize.getHeight() >= QVGA.getHeight()) {
205                 assertArrayContains(String.format(
206                         "Required QVGA size not found for format %x for: ID %s",
207                         ImageFormat.JPEG, mIds[counter]), jpegSizes, QVGA);
208             }
209 
210             ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes));
211             ArrayList<Size> yuvSizesList = new ArrayList<>(Arrays.asList(yuvSizes));
212             ArrayList<Size> privateSizesList = new ArrayList<>(Arrays.asList(privateSizes));
213 
214             int cameraId = Integer.valueOf(mIds[counter]);
215             CamcorderProfile maxVideoProfile = CamcorderProfile.get(
216                     cameraId, CamcorderProfile.QUALITY_HIGH);
217             Size maxVideoSize = new Size(
218                     maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight);
219 
220             // Handle FullHD special case first
221             if (jpegSizesList.contains(FULLHD)) {
222                 if (hwLevel >= LEVEL_3 || hwLevel == FULL || (hwLevel == LIMITED &&
223                         maxVideoSize.getWidth() >= FULLHD.getWidth() &&
224                         maxVideoSize.getHeight() >= FULLHD.getHeight())) {
225                     boolean yuvSupportFullHD = yuvSizesList.contains(FULLHD) ||
226                             yuvSizesList.contains(FULLHD_ALT);
227                     boolean privateSupportFullHD = privateSizesList.contains(FULLHD) ||
228                             privateSizesList.contains(FULLHD_ALT);
229                     assertTrue("Full device FullHD YUV size not found", yuvSupportFullHD);
230                     assertTrue("Full device FullHD PRIVATE size not found", privateSupportFullHD);
231                 }
232                 // remove all FullHD or FullHD_Alt sizes for the remaining of the test
233                 jpegSizesList.remove(FULLHD);
234                 jpegSizesList.remove(FULLHD_ALT);
235             }
236 
237             // Check all sizes other than FullHD
238             if (hwLevel == LIMITED) {
239                 // Remove all jpeg sizes larger than max video size
240                 ArrayList<Size> toBeRemoved = new ArrayList<>();
241                 for (Size size : jpegSizesList) {
242                     if (size.getWidth() >= maxVideoSize.getWidth() &&
243                             size.getHeight() >= maxVideoSize.getHeight()) {
244                         toBeRemoved.add(size);
245                     }
246                 }
247                 jpegSizesList.removeAll(toBeRemoved);
248             }
249 
250             if (hwLevel >= LEVEL_3 || hwLevel == FULL || hwLevel == LIMITED) {
251                 if (!yuvSizesList.containsAll(jpegSizesList)) {
252                     for (Size s : jpegSizesList) {
253                         if (!yuvSizesList.contains(s)) {
254                             fail("Size " + s + " not found in YUV format");
255                         }
256                     }
257                 }
258             }
259 
260             if (!privateSizesList.containsAll(yuvSizesList)) {
261                 for (Size s : yuvSizesList) {
262                     if (!privateSizesList.contains(s)) {
263                         fail("Size " + s + " not found in PRIVATE format");
264                     }
265                 }
266             }
267 
268             counter++;
269         }
270     }
271 
272     /**
273      * Test {@link CameraCharacteristics#getKeys}
274      */
testKeys()275     public void testKeys() {
276         int counter = 0;
277         for (CameraCharacteristics c : mCharacteristics) {
278             mCollector.setCameraId(mIds[counter]);
279 
280             if (VERBOSE) {
281                 Log.v(TAG, "testKeys - testing characteristics for camera " + mIds[counter]);
282             }
283 
284             List<CameraCharacteristics.Key<?>> allKeys = c.getKeys();
285             assertNotNull("Camera characteristics keys must not be null", allKeys);
286             assertFalse("Camera characteristics keys must have at least 1 key",
287                     allKeys.isEmpty());
288 
289             for (CameraCharacteristics.Key<?> key : allKeys) {
290                 assertKeyPrefixValid(key.getName());
291 
292                 // All characteristics keys listed must never be null
293                 mCollector.expectKeyValueNotNull(c, key);
294 
295                 // TODO: add a check that key must not be @hide
296             }
297 
298             /*
299              * List of keys that must be present in camera characteristics (not null).
300              *
301              * Keys for LIMITED, FULL devices might be available despite lacking either
302              * the hardware level or the capability. This is *OK*. This only lists the
303              * *minimal* requirements for a key to be listed.
304              *
305              * LEGACY devices are a bit special since they map to api1 devices, so we know
306              * for a fact most keys are going to be illegal there so they should never be
307              * available.
308              *
309              * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to
310              * do the actual checking.
311              */
312             {
313                 //                                           (Key Name)                                     (HW Level)  (Capabilities <Var-Arg>)
314                 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES     , OPT      ,   BC                   );
315                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES                         , OPT      ,   BC                   );
316                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          , OPT      ,   BC                   );
317                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      , OPT      ,   BC                   );
318                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          , OPT      ,   BC                   );
319                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   , OPT      ,   BC                   );
320                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    , OPT      ,   BC                   );
321                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE                       , OPT      ,   BC                   );
322                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      , OPT      ,   BC                   );
323                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       , OPT      ,   BC                   );
324                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   , OPT      ,   BC                   );
325                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     , OPT      ,   BC                   );
326                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     , OPT      ,   BC                   );
327                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE                      , OPT      ,   BC                   );
328                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE                          , OPT      ,   BC                   );
329                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF                          , OPT      ,   BC                   );
330                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB                         , OPT      ,   BC                   );
331                 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES                       , FULL     ,   NONE                 );
332                 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE                            , OPT      ,   BC                   );
333                 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES             , OPT      ,   RAW                  );
334                 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   , OPT      ,   BC                   );
335                 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  , OPT      ,   BC                   );
336                 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING                                     , OPT      ,   BC                   );
337                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES                   , FULL     ,   MANUAL_SENSOR        );
338                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES            , FULL     ,   MANUAL_SENSOR        );
339                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               , OPT      ,   BC                   );
340                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION       , LIMITED  ,   BC                   );
341                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION            , LIMITED  ,   MANUAL_SENSOR        );
342                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE                   , LIMITED  ,   BC                   );
343                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE                , LIMITED  ,   BC                   );
344                 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT      ,   BC                   );
345                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  , OPT      ,   BC                   );
346                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS                   , OPT      ,   YUV_REPROCESS, OPAQUE_REPROCESS);
347                 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , OPT      ,   CONSTRAINED_HIGH_SPEED);
348                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC                     , OPT      ,   BC                   );
349                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING            , OPT      ,   BC                   );
350                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW                      , OPT      ,   BC                   );
351                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    , OPT      ,   BC                   );
352                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      , OPT      ,   BC                   );
353                 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               , OPT      ,   BC                   );
354                 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , OPT      ,   BC                   );
355                 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE                            , OPT      ,   BC                   );
356                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             , OPT      ,   BC                   );
357                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN                      , FULL     ,   MANUAL_SENSOR, RAW   );
358                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1                   , OPT      ,   RAW                  );
359                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1                         , OPT      ,   RAW                  );
360                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1                          , OPT      ,   RAW                  );
361                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   , OPT      ,   BC, RAW              );
362                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT            , FULL     ,   RAW                  );
363                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE                 , FULL     ,   MANUAL_SENSOR        );
364                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION                  , FULL     ,   MANUAL_SENSOR        );
365                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       , OPT      ,   BC                   );
366                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    , OPT      ,   BC                   );
367                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE                   , FULL     ,   MANUAL_SENSOR        );
368                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL                         , OPT      ,   RAW                  );
369                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE                    , OPT      ,   BC                   );
370                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY                   , FULL     ,   MANUAL_SENSOR        );
371                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION                              , OPT      ,   BC                   );
372                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1                    , OPT      ,   RAW                  );
373                 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES                         , LIMITED  ,   MANUAL_POSTPROC, RAW );
374                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     , OPT      ,   BC                   );
375                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES   , OPT      ,   RAW                  );
376                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED  ,   RAW                  );
377                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  , OPT      ,   BC                   );
378                 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY                                , OPT      ,   BC                   );
379                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES                , FULL     ,   MANUAL_POSTPROC      );
380                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS                        , FULL     ,   MANUAL_POSTPROC      );
381 
382                 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line
383 
384                 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list
385             }
386 
387             // Only check for these if the second reference illuminant is included
388             if (allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)) {
389                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2                    , OPT      ,   RAW                  );
390                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2                         , OPT      ,   RAW                  );
391                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2                   , OPT      ,   RAW                  );
392                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2                          , OPT      ,   RAW                  );
393             }
394 
395             // Required key if any of RAW format output is supported
396             StreamConfigurationMap config =
397                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
398             assertNotNull(String.format("No stream configuration map found for: ID %s",
399                     mIds[counter]), config);
400             if (config.isOutputSupportedFor(ImageFormat.RAW_SENSOR) ||
401                     config.isOutputSupportedFor(ImageFormat.RAW10)  ||
402                     config.isOutputSupportedFor(ImageFormat.RAW12)  ||
403                     config.isOutputSupportedFor(ImageFormat.RAW_PRIVATE)) {
404                 expectKeyAvailable(c,
405                         CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, OPT, BC);
406             }
407             counter++;
408         }
409     }
410 
411     /**
412      * Test values for static metadata used by the RAW capability.
413      */
testStaticRawCharacteristics()414     public void testStaticRawCharacteristics() {
415         int counter = 0;
416         for (CameraCharacteristics c : mCharacteristics) {
417             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
418             assertNotNull("android.request.availableCapabilities must never be null",
419                     actualCapabilities);
420             if (!arrayContains(actualCapabilities,
421                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
422                 Log.i(TAG, "RAW capability is not supported in camera " + counter++ +
423                         ". Skip the test.");
424                 continue;
425             }
426 
427             Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
428             if (actualHwLevel != null && actualHwLevel == FULL) {
429                 mCollector.expectKeyValueContains(c,
430                         CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
431                         CameraCharacteristics.HOT_PIXEL_MODE_FAST);
432             }
433             mCollector.expectKeyValueContains(c,
434                     CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false);
435             mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL,
436                     MIN_ALLOWABLE_WHITELEVEL);
437 
438             mCollector.expectKeyValueIsIn(c,
439                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
440                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
441                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
442                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
443                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR);
444             // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet.
445 
446             mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1,
447                     CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT,
448                     CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN);
449             // Only check the range if the second reference illuminant is avaliable
450             if (c.get(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2) != null) {
451                 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2,
452                         (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT,
453                         (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN);
454             }
455 
456             Rational[] zeroes = new Rational[9];
457             Arrays.fill(zeroes, Rational.ZERO);
458 
459             ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes);
460             mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed,
461                     c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1));
462             mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed,
463                     c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2));
464             mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.",
465                     zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1));
466             mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.",
467                     zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2));
468             mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.",
469                     zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1));
470             mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.",
471                     zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2));
472 
473             BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c,
474                     CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
475             if (blackLevel != null) {
476                 String blackLevelPatternString = blackLevel.toString();
477                 if (VERBOSE) {
478                     Log.v(TAG, "Black level pattern: " + blackLevelPatternString);
479                 }
480                 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT];
481                 blackLevel.copyTo(blackLevelPattern, /*offset*/0);
482                 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
483                 if (whitelevel != null) {
484                     mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0,
485                             whitelevel);
486                 } else {
487                     mCollector.addMessage(
488                             "No WhiteLevel available, cannot check BlackLevelPattern range.");
489                 }
490             }
491 
492             // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
493             counter++;
494         }
495     }
496 
497     /**
498      * Test values for static metadata used by the BURST capability.
499      */
testStaticBurstCharacteristics()500     public void testStaticBurstCharacteristics() throws Exception {
501         int counter = 0;
502         final float SIZE_ERROR_MARGIN = 0.03f;
503         for (CameraCharacteristics c : mCharacteristics) {
504             int[] actualCapabilities = CameraTestUtils.getValueNotNull(
505                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
506 
507             // Check if the burst capability is defined
508             boolean haveBurstCapability = arrayContains(actualCapabilities,
509                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
510             boolean haveBC = arrayContains(actualCapabilities,
511                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
512 
513             if(haveBurstCapability && !haveBC) {
514                 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined");
515             }
516 
517             if (!haveBC) continue;
518 
519             StreamConfigurationMap config =
520                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
521             assertNotNull(String.format("No stream configuration map found for: ID %s",
522                     mIds[counter]), config);
523             Rect activeRect = CameraTestUtils.getValueNotNull(
524                     c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
525             Size sensorSize = new Size(activeRect.width(), activeRect.height());
526 
527             // Ensure that max YUV size matches max JPEG size
528             Size maxYuvSize = CameraTestUtils.getMaxSize(
529                     config.getOutputSizes(ImageFormat.YUV_420_888));
530             Size maxFastYuvSize = maxYuvSize;
531 
532             Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888);
533             if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) {
534                 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes);
535                 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize});
536             }
537 
538             Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat(
539                     ImageFormat.JPEG, mIds[counter], mCameraManager));
540 
541             boolean haveMaxYuv = maxYuvSize != null ?
542                 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
543                         maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false;
544 
545             float croppedWidth = (float)sensorSize.getWidth();
546             float croppedHeight = (float)sensorSize.getHeight();
547             float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
548             float maxYuvAspectRatio = (float)maxYuvSize.getWidth() / (float)maxYuvSize.getHeight();
549             if (sensorAspectRatio < maxYuvAspectRatio) {
550                 croppedHeight = (float)sensorSize.getWidth() / maxYuvAspectRatio;
551             } else if (sensorAspectRatio > maxYuvAspectRatio) {
552                 croppedWidth = (float)sensorSize.getHeight() * maxYuvAspectRatio;
553             }
554             Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
555 
556             boolean maxYuvMatchSensor =
557                     (maxYuvSize.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) &&
558                      maxYuvSize.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) &&
559                      maxYuvSize.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
560                      maxYuvSize.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
561 
562             // No need to do null check since framework will generate the key if HAL don't supply
563             boolean haveAeLock = CameraTestUtils.getValueNotNull(
564                     c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
565             boolean haveAwbLock = CameraTestUtils.getValueNotNull(
566                     c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
567 
568             // Ensure that max YUV output is fast enough - needs to be at least 10 fps
569 
570             long maxYuvRate =
571                 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
572             final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps
573             boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS;
574 
575             // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps
576 
577             long maxFastYuvRate =
578                     config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize);
579             final long MIN_8MP_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps
580             boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS;
581 
582             final int SIZE_8MP_BOUND = 8000000;
583             boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) >
584                     SIZE_8MP_BOUND;
585 
586             // Ensure that there's an FPS range that's fast enough to capture at above
587             // minFrameDuration, for full-auto bursts at the fast resolutions
588             Range[] fpsRanges = CameraTestUtils.getValueNotNull(
589                     c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
590             float minYuvFps = 1.f / maxFastYuvRate;
591 
592             boolean haveFastAeTargetFps = false;
593             for (Range<Integer> r : fpsRanges) {
594                 if (r.getLower() >= minYuvFps) {
595                     haveFastAeTargetFps = true;
596                     break;
597                 }
598             }
599 
600             // Ensure that maximum sync latency is small enough for fast setting changes, even if
601             // it's not quite per-frame
602 
603             Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY);
604             assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]),
605                     maxSyncLatencyValue);
606 
607             int maxSyncLatency = maxSyncLatencyValue;
608             final long MAX_LATENCY_BOUND = 4;
609             boolean haveFastSyncLatency =
610                 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0);
611 
612             if (haveBurstCapability) {
613                 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!",
614                         slowYuvSizes != null);
615                 assertTrue(
616                         String.format("BURST-capable camera device %s does not have maximum YUV " +
617                                 "size that is at least max JPEG size",
618                                 mIds[counter]),
619                         haveMaxYuv);
620                 assertTrue(
621                         String.format("BURST-capable camera device %s max-resolution " +
622                                 "YUV frame rate is too slow" +
623                                 "(%d ns min frame duration reported, less than %d ns expected)",
624                                 mIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS),
625                         haveMaxYuvRate);
626                 assertTrue(
627                         String.format("BURST-capable camera device %s >= 8MP YUV output " +
628                                 "frame rate is too slow" +
629                                 "(%d ns min frame duration reported, less than %d ns expected)",
630                                 mIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS),
631                         haveFastYuvRate);
632                 assertTrue(
633                         String.format("BURST-capable camera device %s does not list an AE target " +
634                                 " FPS range with min FPS >= %f, for full-AUTO bursts",
635                                 mIds[counter], minYuvFps),
636                         haveFastAeTargetFps);
637                 assertTrue(
638                         String.format("BURST-capable camera device %s YUV sync latency is too long" +
639                                 "(%d frames reported, [0, %d] frames expected)",
640                                 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND),
641                         haveFastSyncLatency);
642                 assertTrue(
643                         String.format("BURST-capable camera device %s max YUV size %s should be" +
644                                 "close to active array size %s or cropped active array size %s",
645                                 mIds[counter], maxYuvSize.toString(), sensorSize.toString(),
646                                 croppedSensorSize.toString()),
647                         maxYuvMatchSensor);
648                 assertTrue(
649                         String.format("BURST-capable camera device %s does not support AE lock",
650                                 mIds[counter]),
651                         haveAeLock);
652                 assertTrue(
653                         String.format("BURST-capable camera device %s does not support AWB lock",
654                                 mIds[counter]),
655                         haveAwbLock);
656             } else {
657                 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!",
658                         slowYuvSizes == null);
659                 assertTrue(
660                         String.format("Camera device %s has all the requirements for BURST" +
661                                 " capability but does not report it!", mIds[counter]),
662                         !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps &&
663                                 haveFastSyncLatency && maxYuvMatchSensor &&
664                                 haveAeLock && haveAwbLock));
665             }
666 
667             counter++;
668         }
669     }
670 
671     /**
672      * Check reprocessing capabilities.
673      */
testReprocessingCharacteristics()674     public void testReprocessingCharacteristics() {
675         int counter = 0;
676 
677         for (CameraCharacteristics c : mCharacteristics) {
678             Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mIds[counter]);
679 
680             int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
681             assertNotNull("android.request.availableCapabilities must never be null",
682                     capabilities);
683             boolean supportYUV = arrayContains(capabilities,
684                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
685             boolean supportOpaque = arrayContains(capabilities,
686                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
687             StreamConfigurationMap configs =
688                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
689             Integer maxNumInputStreams =
690                     c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS);
691             int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES);
692             int[] availableNoiseReductionModes = c.get(
693                     CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES);
694 
695             int[] inputFormats = configs.getInputFormats();
696 
697             boolean supportZslEdgeMode = false;
698             boolean supportZslNoiseReductionMode = false;
699             boolean supportHiQNoiseReductionMode = false;
700             boolean supportHiQEdgeMode = false;
701 
702             if (availableEdgeModes != null) {
703                 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)).
704                         contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
705                 supportHiQEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)).
706                         contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY);
707             }
708 
709             if (availableNoiseReductionModes != null) {
710                 supportZslNoiseReductionMode = Arrays.asList(
711                         CameraTestUtils.toObject(availableNoiseReductionModes)).contains(
712                         CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
713                 supportHiQNoiseReductionMode = Arrays.asList(
714                         CameraTestUtils.toObject(availableNoiseReductionModes)).contains(
715                         CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
716             }
717 
718             if (supportYUV || supportOpaque) {
719                 mCollector.expectTrue("Support reprocessing but max number of input stream is " +
720                         maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0);
721                 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " +
722                         "not supported", supportZslEdgeMode);
723                 mCollector.expectTrue("Support reprocessing but " +
724                         "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported",
725                         supportZslNoiseReductionMode);
726 
727                 // For reprocessing, if we only require OFF and ZSL mode, it will be just like jpeg
728                 // encoding. We implicitly require FAST to make reprocessing meaningful, which means
729                 // that we also require HIGH_QUALITY.
730                 mCollector.expectTrue("Support reprocessing but EDGE_MODE_HIGH_QUALITY is " +
731                         "not supported", supportHiQEdgeMode);
732                 mCollector.expectTrue("Support reprocessing but " +
733                         "NOISE_REDUCTION_MODE_HIGH_QUALITY is not supported",
734                         supportHiQNoiseReductionMode);
735 
736                 // Verify mandatory input formats are supported
737                 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing",
738                         !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888));
739                 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing",
740                         !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE));
741 
742                 // max capture stall must be reported if one of the reprocessing is supported.
743                 final int MAX_ALLOWED_STALL_FRAMES = 4;
744                 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL);
745                 mCollector.expectTrue("max capture stall must be non-null and no larger than "
746                         + MAX_ALLOWED_STALL_FRAMES,
747                         maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES);
748 
749                 for (int input : inputFormats) {
750                     // Verify mandatory output formats are supported
751                     int[] outputFormats = configs.getValidOutputFormatsForInput(input);
752                     mCollector.expectTrue("YUV_420_888 output must be supported for reprocessing",
753                             arrayContains(outputFormats, ImageFormat.YUV_420_888));
754                     mCollector.expectTrue("JPEG output must be supported for reprocessing",
755                             arrayContains(outputFormats, ImageFormat.JPEG));
756 
757                     // Verify camera can output the reprocess input formats and sizes.
758                     Size[] inputSizes = configs.getInputSizes(input);
759                     Size[] outputSizes = configs.getOutputSizes(input);
760                     Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input);
761                     mCollector.expectTrue("no input size supported for format " + input,
762                             inputSizes.length > 0);
763                     mCollector.expectTrue("no output size supported for format " + input,
764                             outputSizes.length > 0);
765 
766                     for (Size inputSize : inputSizes) {
767                         mCollector.expectTrue("Camera must be able to output the supported " +
768                                 "reprocessing input size",
769                                 arrayContains(outputSizes, inputSize) ||
770                                 arrayContains(highResOutputSizes, inputSize));
771                     }
772                 }
773             } else {
774                 mCollector.expectTrue("Doesn't support reprocessing but report input format: " +
775                         Arrays.toString(inputFormats), inputFormats.length == 0);
776                 mCollector.expectTrue("Doesn't support reprocessing but max number of input " +
777                         "stream is " + maxNumInputStreams,
778                         maxNumInputStreams == null || maxNumInputStreams == 0);
779                 mCollector.expectTrue("Doesn't support reprocessing but " +
780                         "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode);
781                 mCollector.expectTrue("Doesn't support reprocessing but " +
782                         "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported",
783                         !supportZslNoiseReductionMode);
784             }
785             counter++;
786         }
787     }
788 
789     /**
790      * Check depth output capability
791      */
testDepthOutputCharacteristics()792     public void testDepthOutputCharacteristics() {
793         int counter = 0;
794 
795         for (CameraCharacteristics c : mCharacteristics) {
796             Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mIds[counter]);
797 
798             int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
799             assertNotNull("android.request.availableCapabilities must never be null",
800                     capabilities);
801             boolean supportDepth = arrayContains(capabilities,
802                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
803             StreamConfigurationMap configs =
804                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
805 
806             int[] outputFormats = configs.getOutputFormats();
807             boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16);
808 
809             Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE);
810 
811             float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION);
812             float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION);
813             float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION);
814             float[] radialDistortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION);
815 
816             if (supportDepth) {
817                 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16",
818                         hasDepth16);
819                 if (hasDepth16) {
820                     Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16);
821                     mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!",
822                             depthSizes != null && depthSizes.length > 0);
823                     if (depthSizes != null) {
824                         for (Size depthSize : depthSizes) {
825                             mCollector.expectTrue("All depth16 sizes must be positive",
826                                     depthSize.getWidth() > 0 && depthSize.getHeight() > 0);
827                             long minFrameDuration = configs.getOutputMinFrameDuration(
828                                     ImageFormat.DEPTH16, depthSize);
829                             mCollector.expectTrue("Non-negative min frame duration for depth size "
830                                     + depthSize + " expected, got " + minFrameDuration,
831                                     minFrameDuration >= 0);
832                             long stallDuration = configs.getOutputStallDuration(
833                                     ImageFormat.DEPTH16, depthSize);
834                             mCollector.expectTrue("Non-negative stall duration for depth size "
835                                     + depthSize + " expected, got " + stallDuration,
836                                     stallDuration >= 0);
837                         }
838                     }
839                 }
840                 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) {
841                     Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD);
842                     mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " +
843                             "but no sizes for DEPTH_POINT_CLOUD supported!",
844                             depthCloudSizes != null && depthCloudSizes.length > 0);
845                     if (depthCloudSizes != null) {
846                         for (Size depthCloudSize : depthCloudSizes) {
847                             mCollector.expectTrue("All depth point cloud sizes must be nonzero",
848                                     depthCloudSize.getWidth() > 0);
849                             mCollector.expectTrue("All depth point cloud sizes must be N x 1",
850                                     depthCloudSize.getHeight() == 1);
851                             long minFrameDuration = configs.getOutputMinFrameDuration(
852                                     ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize);
853                             mCollector.expectTrue("Non-negative min frame duration for depth size "
854                                     + depthCloudSize + " expected, got " + minFrameDuration,
855                                     minFrameDuration >= 0);
856                             long stallDuration = configs.getOutputStallDuration(
857                                     ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize);
858                             mCollector.expectTrue("Non-negative stall duration for depth size "
859                                     + depthCloudSize + " expected, got " + stallDuration,
860                                     stallDuration >= 0);
861                         }
862                     }
863                 }
864 
865                 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined",
866                         depthIsExclusive != null);
867 
868                 mCollector.expectTrue(
869                         "Supports DEPTH_OUTPUT but LENS_POSE_ROTATION not right size",
870                         poseRotation != null && poseRotation.length == 4);
871                 mCollector.expectTrue(
872                         "Supports DEPTH_OUTPUT but LENS_POSE_TRANSLATION not right size",
873                         poseTranslation != null && poseTranslation.length == 3);
874                 mCollector.expectTrue(
875                         "Supports DEPTH_OUTPUT but LENS_INTRINSIC_CALIBRATION not right size",
876                         cameraIntrinsics != null && cameraIntrinsics.length == 5);
877                 mCollector.expectTrue(
878                         "Supports DEPTH_OUTPUT but LENS_RADIAL_DISTORTION not right size",
879                         radialDistortion != null && radialDistortion.length == 6);
880 
881                 if (poseRotation != null && poseRotation.length == 4) {
882                     float normSq =
883                         poseRotation[0] * poseRotation[0] +
884                         poseRotation[1] * poseRotation[1] +
885                         poseRotation[2] * poseRotation[2] +
886                         poseRotation[3] * poseRotation[3];
887                     mCollector.expectTrue(
888                             "LENS_POSE_ROTATION quarternion must be unit-length",
889                             0.9999f < normSq && normSq < 1.0001f);
890 
891                     // TODO: Cross-validate orientation/facing and poseRotation
892                     Integer orientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
893                     Integer facing = c.get(CameraCharacteristics.LENS_FACING);
894                 }
895 
896                 if (poseTranslation != null && poseTranslation.length == 3) {
897                     float normSq =
898                         poseTranslation[0] * poseTranslation[0] +
899                         poseTranslation[1] * poseTranslation[1] +
900                         poseTranslation[2] * poseTranslation[2];
901                     mCollector.expectTrue("Pose translation is larger than 1 m",
902                             normSq < 1.f);
903                 }
904 
905                 Rect precorrectionArray =
906                     c.get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
907                 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not have " +
908                         "precorrection active array defined", precorrectionArray != null);
909 
910                 if (cameraIntrinsics != null && precorrectionArray != null) {
911                     float fx = cameraIntrinsics[0];
912                     float fy = cameraIntrinsics[1];
913                     float cx = cameraIntrinsics[2];
914                     float cy = cameraIntrinsics[3];
915                     float s = cameraIntrinsics[4];
916                     mCollector.expectTrue("Optical center expected to be within precorrection array",
917                             0 <= cx && cx < precorrectionArray.width() &&
918                             0 <= cy && cy < precorrectionArray.height());
919 
920                     // TODO: Verify focal lengths and skew are reasonable
921                 }
922 
923                 if (radialDistortion != null) {
924                     // TODO: Verify radial distortion
925                 }
926 
927             } else {
928                 boolean hasFields =
929                     hasDepth16 && (poseTranslation != null) &&
930                     (poseRotation != null) && (cameraIntrinsics != null) &&
931                     (radialDistortion != null) && (depthIsExclusive != null);
932 
933                 mCollector.expectTrue(
934                         "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed",
935                         !hasFields);
936             }
937             counter++;
938         }
939     }
940 
941     /**
942      * Cross-check StreamConfigurationMap output
943      */
testStreamConfigurationMap()944     public void testStreamConfigurationMap() throws Exception {
945         int counter = 0;
946         for (CameraCharacteristics c : mCharacteristics) {
947             Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]);
948             StreamConfigurationMap config =
949                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
950             assertNotNull(String.format("No stream configuration map found for: ID %s",
951                             mIds[counter]), config);
952 
953             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
954             assertNotNull("android.request.availableCapabilities must never be null",
955                     actualCapabilities);
956 
957             if (arrayContains(actualCapabilities, BC)) {
958                 assertTrue("ImageReader must be supported",
959                     config.isOutputSupportedFor(android.media.ImageReader.class));
960                 assertTrue("MediaRecorder must be supported",
961                     config.isOutputSupportedFor(android.media.MediaRecorder.class));
962                 assertTrue("MediaCodec must be supported",
963                     config.isOutputSupportedFor(android.media.MediaCodec.class));
964                 assertTrue("Allocation must be supported",
965                     config.isOutputSupportedFor(android.renderscript.Allocation.class));
966                 assertTrue("SurfaceHolder must be supported",
967                     config.isOutputSupportedFor(android.view.SurfaceHolder.class));
968                 assertTrue("SurfaceTexture must be supported",
969                     config.isOutputSupportedFor(android.graphics.SurfaceTexture.class));
970 
971                 assertTrue("YUV_420_888 must be supported",
972                     config.isOutputSupportedFor(ImageFormat.YUV_420_888));
973                 assertTrue("JPEG must be supported",
974                     config.isOutputSupportedFor(ImageFormat.JPEG));
975             } else {
976                 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed",
977                     !config.isOutputSupportedFor(ImageFormat.YUV_420_888));
978                 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed",
979                     !config.isOutputSupportedFor(ImageFormat.JPEG));
980             }
981 
982             // Check RAW
983 
984             if (arrayContains(actualCapabilities,
985                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
986                 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised",
987                     config.isOutputSupportedFor(ImageFormat.RAW_SENSOR));
988             }
989 
990             // Cross check public formats and sizes
991 
992             int[] supportedFormats = config.getOutputFormats();
993             for (int format : supportedFormats) {
994                 assertTrue("Format " + format + " fails cross check",
995                         config.isOutputSupportedFor(format));
996                 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes(
997                         Arrays.asList(config.getOutputSizes(format)), /*ascending*/true);
998                 if (arrayContains(actualCapabilities,
999                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
1000                     supportedSizes.addAll(
1001                         Arrays.asList(config.getHighResolutionOutputSizes(format)));
1002                     supportedSizes = CameraTestUtils.getAscendingOrderSizes(
1003                         supportedSizes, /*ascending*/true);
1004                 }
1005                 assertTrue("Supported format " + format + " has no sizes listed",
1006                         supportedSizes.size() > 0);
1007                 for (int i = 0; i < supportedSizes.size(); i++) {
1008                     Size size = supportedSizes.get(i);
1009                     if (VERBOSE) {
1010                         Log.v(TAG,
1011                                 String.format("Testing camera %s, format %d, size %s",
1012                                         mIds[counter], format, size.toString()));
1013                     }
1014 
1015                     long stallDuration = config.getOutputStallDuration(format, size);
1016                     switch(format) {
1017                         case ImageFormat.YUV_420_888:
1018                             assertTrue("YUV_420_888 may not have a non-zero stall duration",
1019                                     stallDuration == 0);
1020                             break;
1021                         case ImageFormat.JPEG:
1022                         case ImageFormat.RAW_SENSOR:
1023                             final float TOLERANCE_FACTOR = 2.0f;
1024                             long prevDuration = 0;
1025                             if (i > 0) {
1026                                 prevDuration = config.getOutputStallDuration(
1027                                         format, supportedSizes.get(i - 1));
1028                             }
1029                             long nextDuration = Long.MAX_VALUE;
1030                             if (i < (supportedSizes.size() - 1)) {
1031                                 nextDuration = config.getOutputStallDuration(
1032                                         format, supportedSizes.get(i + 1));
1033                             }
1034                             long curStallDuration = config.getOutputStallDuration(format, size);
1035                             // Stall duration should be in a reasonable range: larger size should
1036                             // normally have larger stall duration.
1037                             mCollector.expectInRange("Stall duration (format " + format +
1038                                     " and size " + size + ") is not in the right range",
1039                                     curStallDuration,
1040                                     (long) (prevDuration / TOLERANCE_FACTOR),
1041                                     (long) (nextDuration * TOLERANCE_FACTOR));
1042                             break;
1043                         default:
1044                             assertTrue("Negative stall duration for format " + format,
1045                                     stallDuration >= 0);
1046                             break;
1047                     }
1048                     long minDuration = config.getOutputMinFrameDuration(format, size);
1049                     if (arrayContains(actualCapabilities,
1050                             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1051                         assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
1052                                 + "format " + format + " for size " + size + " minDuration " +
1053                                 minDuration,
1054                                 minDuration > 0);
1055                     } else {
1056                         assertTrue("Need non-negative min frame duration for format " + format,
1057                                 minDuration >= 0);
1058                     }
1059 
1060                     // todo: test opaque image reader when it's supported.
1061                     if (format != ImageFormat.PRIVATE) {
1062                         ImageReader testReader = ImageReader.newInstance(
1063                             size.getWidth(),
1064                             size.getHeight(),
1065                             format,
1066                             1);
1067                         Surface testSurface = testReader.getSurface();
1068 
1069                         assertTrue(
1070                             String.format("isOutputSupportedFor fails for config %s, format %d",
1071                                     size.toString(), format),
1072                             config.isOutputSupportedFor(testSurface));
1073 
1074                         testReader.close();
1075                     }
1076                 } // sizes
1077 
1078                 // Try an invalid size in this format, should round
1079                 Size invalidSize = findInvalidSize(supportedSizes);
1080                 int MAX_ROUNDING_WIDTH = 1920;
1081                 // todo: test opaque image reader when it's supported.
1082                 if (format != ImageFormat.PRIVATE &&
1083                         invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) {
1084                     ImageReader testReader = ImageReader.newInstance(
1085                                                                      invalidSize.getWidth(),
1086                                                                      invalidSize.getHeight(),
1087                                                                      format,
1088                                                                      1);
1089                     Surface testSurface = testReader.getSurface();
1090 
1091                     assertTrue(
1092                                String.format("isOutputSupportedFor fails for config %s, %d",
1093                                        invalidSize.toString(), format),
1094                                config.isOutputSupportedFor(testSurface));
1095 
1096                     testReader.close();
1097                 }
1098             } // formats
1099 
1100             // Cross-check opaque format and sizes
1101             if (arrayContains(actualCapabilities, BC)) {
1102                 SurfaceTexture st = new SurfaceTexture(1);
1103                 Surface surf = new Surface(st);
1104 
1105                 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class,
1106                         mIds[counter], mCameraManager);
1107                 assertTrue("Opaque format has no sizes listed",
1108                         opaqueSizes.length > 0);
1109                 for (Size size : opaqueSizes) {
1110                     long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size);
1111                     assertTrue("Opaque output may not have a non-zero stall duration",
1112                             stallDuration == 0);
1113 
1114                     long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size);
1115                     if (arrayContains(actualCapabilities,
1116                                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1117                         assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
1118                                 + "opaque format",
1119                                 minDuration > 0);
1120                     } else {
1121                         assertTrue("Need non-negative min frame duration for opaque format ",
1122                                 minDuration >= 0);
1123                     }
1124                     st.setDefaultBufferSize(size.getWidth(), size.getHeight());
1125 
1126                     assertTrue(
1127                             String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
1128                                     size.toString()),
1129                             config.isOutputSupportedFor(surf));
1130 
1131                 } // opaque sizes
1132 
1133                 // Try invalid opaque size, should get rounded
1134                 Size invalidSize = findInvalidSize(opaqueSizes);
1135                 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight());
1136                 assertTrue(
1137                         String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
1138                                 invalidSize.toString()),
1139                         config.isOutputSupportedFor(surf));
1140 
1141             }
1142             counter++;
1143         } // mCharacteristics
1144     }
1145 
1146     /**
1147      * Test high speed capability and cross-check the high speed sizes and fps ranges from
1148      * the StreamConfigurationMap.
1149      */
testConstrainedHighSpeedCapability()1150     public void testConstrainedHighSpeedCapability() throws Exception {
1151         int counter = 0;
1152         for (CameraCharacteristics c : mCharacteristics) {
1153             int[] capabilities = CameraTestUtils.getValueNotNull(
1154                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1155             boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED);
1156             if (supportHighSpeed) {
1157                 StreamConfigurationMap config =
1158                         CameraTestUtils.getValueNotNull(
1159                                 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1160                 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
1161                 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0);
1162                 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE,
1163                         mIds[counter], mCameraManager);
1164                 assertTrue("Normal size for PRIVATE format shouldn't be null or empty",
1165                         allSizes != null && allSizes.length > 0);
1166                 for (Size size: highSpeedSizes) {
1167                     // The sizes must be a subset of the normal sizes
1168                     assertTrue("High speed size " + size +
1169                             " must be part of normal sizes " + Arrays.toString(allSizes),
1170                             Arrays.asList(allSizes).contains(size));
1171 
1172                     // Sanitize the high speed FPS ranges for each size
1173                     List<Range<Integer>> ranges =
1174                             Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size));
1175                     for (Range<Integer> range : ranges) {
1176                         assertTrue("The range " + range + " doesn't satisfy the"
1177                                 + " min/max boundary requirements.",
1178                                 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN &&
1179                                 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN);
1180                         assertTrue("The range " + range + " should be multiple of 30fps",
1181                                 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0);
1182                         // If the range is fixed high speed range, it should contain the
1183                         // [30, fps_max] in the high speed range list; if it's variable FPS range,
1184                         // the corresponding fixed FPS Range must be included in the range list.
1185                         if (range.getLower() == range.getUpper()) {
1186                             Range<Integer> variableRange = new Range<Integer>(30, range.getUpper());
1187                             assertTrue("The variable FPS range " + variableRange +
1188                                     " shoould be included in the high speed ranges for size " +
1189                                     size, ranges.contains(variableRange));
1190                         } else {
1191                             Range<Integer> fixedRange =
1192                                     new Range<Integer>(range.getUpper(), range.getUpper());
1193                             assertTrue("The fixed FPS range " + fixedRange +
1194                                     " shoould be included in the high speed ranges for size " +
1195                                     size, ranges.contains(fixedRange));
1196                         }
1197                     }
1198                 }
1199                 // If the device advertise some high speed profiles, the sizes and FPS ranges
1200                 // should be advertise by the camera.
1201                 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P;
1202                         quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) {
1203                     int cameraId = Integer.valueOf(mIds[counter]);
1204                     if (CamcorderProfile.hasProfile(cameraId, quality)) {
1205                         CamcorderProfile profile = CamcorderProfile.get(cameraId, quality);
1206                         Size camcorderProfileSize =
1207                                 new Size(profile.videoFrameWidth, profile.videoFrameHeight);
1208                         assertTrue("CamcorderPrfile size " + camcorderProfileSize +
1209                                 " must be included in the high speed sizes " +
1210                                 Arrays.toString(highSpeedSizes.toArray()),
1211                                 highSpeedSizes.contains(camcorderProfileSize));
1212                         Range<Integer> camcorderFpsRange =
1213                                 new Range<Integer>(profile.videoFrameRate, profile.videoFrameRate);
1214                         List<Range<Integer>> allRanges =
1215                                 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(
1216                                         camcorderProfileSize));
1217                         assertTrue("Camcorder fps range " + camcorderFpsRange +
1218                                 " should be included by high speed fps ranges " +
1219                                 Arrays.toString(allRanges.toArray()),
1220                                 allRanges.contains(camcorderFpsRange));
1221                     }
1222                 }
1223             }
1224             counter++;
1225         }
1226     }
1227 
1228     /**
1229      * Sanity check of optical black regions.
1230      */
testOpticalBlackRegions()1231     public void testOpticalBlackRegions() {
1232         int counter = 0;
1233         for (CameraCharacteristics c : mCharacteristics) {
1234             List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys();
1235             boolean hasDynamicBlackLevel =
1236                     resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
1237             boolean hasDynamicWhiteLevel =
1238                     resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
1239             boolean hasFixedBlackLevel =
1240                     c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
1241             boolean hasFixedWhiteLevel =
1242                     c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
1243             // The black and white levels should be either all supported or none of them is
1244             // supported.
1245             mCollector.expectTrue("Dynamic black and white level should be all or none of them"
1246                     + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel);
1247             mCollector.expectTrue("Fixed black and white level should be all or none of them"
1248                     + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel);
1249             mCollector.expectTrue("Fixed black level should be supported if dynamic black"
1250                     + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel);
1251 
1252             if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) {
1253                 // Regions shouldn't be null or empty.
1254                 Rect[] regions = CameraTestUtils.getValueNotNull(c,
1255                         CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
1256                 CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not"
1257                         + " be empty");
1258 
1259                 // Dynamic black level should be supported if the optical black region is
1260                 // advertised.
1261                 mCollector.expectTrue("Dynamic black and white level keys should be advertised in "
1262                         + "available capture result key list", hasDynamicWhiteLevel);
1263 
1264                 // Range check.
1265                 for (Rect region : regions) {
1266                     mCollector.expectTrue("Camera " + mIds[counter] + ": optical black region" +
1267                             " shouldn't be empty!", !region.isEmpty());
1268                     mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/,
1269                             region.left/*actual*/);
1270                     mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
1271                             region.top/*actual*/);
1272                     mCollector.expectTrue("Optical black region left/right/width/height must be"
1273                             + " even number, otherwise, the bayer CFA pattern in this region will"
1274                             + " be messed up",
1275                             region.left % 2 == 0 && region.top % 2 == 0 &&
1276                             region.width() % 2 == 0 && region.height() % 2 == 0);
1277                     mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
1278                             region.top/*actual*/);
1279                     Size size = CameraTestUtils.getValueNotNull(c,
1280                             CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
1281                     mCollector.expectLessOrEqual("Optical black region width",
1282                             size.getWidth()/*expected*/, region.width());
1283                     mCollector.expectLessOrEqual("Optical black region height",
1284                             size.getHeight()/*expected*/, region.height());
1285                     Rect activeArray = CameraTestUtils.getValueNotNull(c,
1286                             CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
1287                     mCollector.expectTrue("Optical black region" + region + " should be outside of"
1288                             + " active array " + activeArray,
1289                             !region.intersect(activeArray));
1290                     // Region need to be disjoint:
1291                     for (Rect region2 : regions) {
1292                         mCollector.expectTrue("Optical black region" + region + " should have no "
1293                                 + "overlap with " + region2,
1294                                 region == region2 || !region.intersect(region2));
1295                     }
1296                 }
1297             } else {
1298                 Log.i(TAG, "Camera " + mIds[counter] + " doesn't support optical black regions,"
1299                         + " skip the region test");
1300             }
1301             counter++;
1302         }
1303     }
1304     /**
1305      * Create an invalid size that's close to one of the good sizes in the list, but not one of them
1306      */
findInvalidSize(Size[] goodSizes)1307     private Size findInvalidSize(Size[] goodSizes) {
1308         return findInvalidSize(Arrays.asList(goodSizes));
1309     }
1310 
1311     /**
1312      * Create an invalid size that's close to one of the good sizes in the list, but not one of them
1313      */
findInvalidSize(List<Size> goodSizes)1314     private Size findInvalidSize(List<Size> goodSizes) {
1315         Size invalidSize = new Size(goodSizes.get(0).getWidth() + 1, goodSizes.get(0).getHeight());
1316         while(goodSizes.contains(invalidSize)) {
1317             invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight());
1318         }
1319         return invalidSize;
1320     }
1321 
1322     /**
1323      * Check key is present in characteristics if the hardware level is at least {@code hwLevel};
1324      * check that the key is present if the actual capabilities are one of {@code capabilities}.
1325      *
1326      * @return value of the {@code key} from {@code c}
1327      */
expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, int hwLevel, int... capabilities)1328     private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key,
1329             int hwLevel, int... capabilities) {
1330 
1331         Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
1332         assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel);
1333 
1334         int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1335         assertNotNull("android.request.availableCapabilities must never be null",
1336                 actualCapabilities);
1337 
1338         List<Key<?>> allKeys = c.getKeys();
1339 
1340         T value = c.get(key);
1341 
1342         // For LIMITED-level targeted keys, rely on capability check, not level
1343         if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) {
1344             mCollector.expectTrue(
1345                     String.format("Key (%s) must be in characteristics for this hardware level " +
1346                             "(required minimal HW level %s, actual HW level %s)",
1347                             key.getName(), toStringHardwareLevel(hwLevel),
1348                             toStringHardwareLevel(actualHwLevel)),
1349                     value != null);
1350             mCollector.expectTrue(
1351                     String.format("Key (%s) must be in characteristics list of keys for this " +
1352                             "hardware level (required minimal HW level %s, actual HW level %s)",
1353                             key.getName(), toStringHardwareLevel(hwLevel),
1354                             toStringHardwareLevel(actualHwLevel)),
1355                     allKeys.contains(key));
1356         } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) {
1357             if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) {
1358                 // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined
1359                 mCollector.expectTrue(
1360                     String.format("Key (%s) must be in characteristics for these capabilities " +
1361                             "(required capabilities %s, actual capabilities %s)",
1362                             key.getName(), Arrays.toString(capabilities),
1363                             Arrays.toString(actualCapabilities)),
1364                     value != null);
1365                 mCollector.expectTrue(
1366                     String.format("Key (%s) must be in characteristics list of keys for " +
1367                             "these capabilities (required capabilities %s, actual capabilities %s)",
1368                             key.getName(), Arrays.toString(capabilities),
1369                             Arrays.toString(actualCapabilities)),
1370                     allKeys.contains(key));
1371             }
1372         } else {
1373             if (actualHwLevel == LEGACY && hwLevel != OPT) {
1374                 if (value != null || allKeys.contains(key)) {
1375                     Log.w(TAG, String.format(
1376                             "Key (%s) is not required for LEGACY devices but still appears",
1377                             key.getName()));
1378                 }
1379             }
1380             // OK: Key may or may not be present.
1381         }
1382         return value;
1383     }
1384 
arrayContains(int[] arr, int needle)1385     private static boolean arrayContains(int[] arr, int needle) {
1386         if (arr == null) {
1387             return false;
1388         }
1389 
1390         for (int elem : arr) {
1391             if (elem == needle) {
1392                 return true;
1393             }
1394         }
1395 
1396         return false;
1397     }
1398 
arrayContains(T[] arr, T needle)1399     private static <T> boolean arrayContains(T[] arr, T needle) {
1400         if (arr == null) {
1401             return false;
1402         }
1403 
1404         for (T elem : arr) {
1405             if (elem.equals(needle)) {
1406                 return true;
1407             }
1408         }
1409 
1410         return false;
1411     }
1412 
arrayContainsAnyOf(int[] arr, int[] needles)1413     private static boolean arrayContainsAnyOf(int[] arr, int[] needles) {
1414         for (int needle : needles) {
1415             if (arrayContains(arr, needle)) {
1416                 return true;
1417             }
1418         }
1419         return false;
1420     }
1421 
1422     /**
1423      * The key name has a prefix of either "android." or "com."; other prefixes are not valid.
1424      */
assertKeyPrefixValid(String keyName)1425     private static void assertKeyPrefixValid(String keyName) {
1426         assertStartsWithAnyOf(
1427                 "All metadata keys must start with 'android.' (built-in keys) " +
1428                 "or 'com.' (vendor-extended keys)", new String[] {
1429                         PREFIX_ANDROID + ".",
1430                         PREFIX_VENDOR + ".",
1431                 }, keyName);
1432     }
1433 
assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, boolean actual)1434     private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key,
1435             boolean actual) {
1436         assertTrue(msg + " (key = '" + key.getName() + "')", actual);
1437     }
1438 
assertOneOf(String msg, T[] expected, T actual)1439     private static <T> void assertOneOf(String msg, T[] expected, T actual) {
1440         for (int i = 0; i < expected.length; ++i) {
1441             if (Objects.equals(expected[i], actual)) {
1442                 return;
1443             }
1444         }
1445 
1446         fail(String.format("%s: (expected one of %s, actual %s)",
1447                 msg, Arrays.toString(expected), actual));
1448     }
1449 
assertStartsWithAnyOf(String msg, String[] expected, String actual)1450     private static <T> void assertStartsWithAnyOf(String msg, String[] expected, String actual) {
1451         for (int i = 0; i < expected.length; ++i) {
1452             if (actual.startsWith(expected[i])) {
1453                 return;
1454             }
1455         }
1456 
1457         fail(String.format("%s: (expected to start with any of %s, but value was %s)",
1458                 msg, Arrays.toString(expected), actual));
1459     }
1460 
1461     /** Return a positive int if left > right, 0 if left==right, negative int if left < right */
compareHardwareLevel(int left, int right)1462     private static int compareHardwareLevel(int left, int right) {
1463         return remapHardwareLevel(left) - remapHardwareLevel(right);
1464     }
1465 
1466     /** Remap HW levels worst<->best, 0 = LEGACY, 1 = LIMITED, 2 = FULL, ..., N = LEVEL_N */
remapHardwareLevel(int level)1467     private static int remapHardwareLevel(int level) {
1468         switch (level) {
1469             case OPT:
1470                 return Integer.MAX_VALUE;
1471             case LEGACY:
1472                 return 0; // lowest
1473             case LIMITED:
1474                 return 1; // second lowest
1475             case FULL:
1476                 return 2; // good
1477             default:
1478                 if (level >= LEVEL_3) {
1479                     return level; // higher levels map directly
1480                 }
1481         }
1482 
1483         fail("Unknown HW level: " + level);
1484         return -1;
1485     }
1486 
toStringHardwareLevel(int level)1487     private static String toStringHardwareLevel(int level) {
1488         switch (level) {
1489             case LEGACY:
1490                 return "LEGACY";
1491             case LIMITED:
1492                 return "LIMITED";
1493             case FULL:
1494                 return "FULL";
1495             default:
1496                 if (level >= LEVEL_3) {
1497                     return String.format("LEVEL_%d", level);
1498                 }
1499         }
1500 
1501         // unknown
1502         Log.w(TAG, "Unknown hardware level " + level);
1503         return Integer.toString(level);
1504     }
1505 }
1506