1 /*
2  * Copyright 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.cts.helpers;
18 
19 import android.graphics.Rect;
20 import android.graphics.ImageFormat;
21 import android.hardware.camera2.CameraCharacteristics;
22 import android.hardware.camera2.CameraCharacteristics.Key;
23 import android.hardware.camera2.CameraMetadata;
24 import android.hardware.camera2.CaptureRequest;
25 import android.hardware.camera2.CaptureResult;
26 import android.hardware.camera2.cts.CameraTestUtils;
27 import android.hardware.camera2.params.StreamConfigurationMap;
28 import android.util.Range;
29 import android.util.Size;
30 import android.util.Log;
31 import android.util.Rational;
32 
33 import junit.framework.Assert;
34 
35 import java.lang.reflect.Array;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Set;
43 
44 import static android.hardware.camera2.cts.helpers.AssertHelpers.*;
45 
46 /**
47  * Helpers to get common static info out of the camera.
48  *
49  * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p>
50  *
51  * <p>Attempt to be durable against the camera device having bad or missing metadata
52  * by providing reasonable defaults and logging warnings when that happens.</p>
53  */
54 public class StaticMetadata {
55 
56     private static final String TAG = "StaticMetadata";
57     private static final int IGNORE_SIZE_CHECK = -1;
58 
59     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
60     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
61     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
62     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800;
63     private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
64     private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
65     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
66     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
67     private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
68     private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
69     private static final int MAX_REPROCESS_MAX_CAPTURE_STALL = 4;
70 
71     // TODO: Consider making this work across any metadata object, not just camera characteristics
72     private final CameraCharacteristics mCharacteristics;
73     private final CheckLevel mLevel;
74     private final CameraErrorCollector mCollector;
75 
76     // Access via getAeModeName() to account for vendor extensions
77     public static final String[] AE_MODE_NAMES = new String[] {
78         "AE_MODE_OFF",
79         "AE_MODE_ON",
80         "AE_MODE_ON_AUTO_FLASH",
81         "AE_MODE_ON_ALWAYS_FLASH",
82         "AE_MODE_ON_AUTO_FLASH_REDEYE"
83     };
84 
85     // Access via getAfModeName() to account for vendor extensions
86     public static final String[] AF_MODE_NAMES = new String[] {
87         "AF_MODE_OFF",
88         "AF_MODE_AUTO",
89         "AF_MODE_MACRO",
90         "AF_MODE_CONTINUOUS_VIDEO",
91         "AF_MODE_CONTINUOUS_PICTURE",
92         "AF_MODE_EDOF"
93     };
94 
95     // Index with android.control.aeState
96     public static final String[] AE_STATE_NAMES = new String[] {
97         "AE_STATE_INACTIVE",
98         "AE_STATE_SEARCHING",
99         "AE_STATE_CONVERGED",
100         "AE_STATE_LOCKED",
101         "AE_STATE_FLASH_REQUIRED",
102         "AE_STATE_PRECAPTURE"
103     };
104 
105     // Index with android.control.afState
106     public static final String[] AF_STATE_NAMES = new String[] {
107         "AF_STATE_INACTIVE",
108         "AF_STATE_PASSIVE_SCAN",
109         "AF_STATE_PASSIVE_FOCUSED",
110         "AF_STATE_ACTIVE_SCAN",
111         "AF_STATE_FOCUSED_LOCKED",
112         "AF_STATE_NOT_FOCUSED_LOCKED",
113         "AF_STATE_PASSIVE_UNFOCUSED"
114     };
115 
116     public enum CheckLevel {
117         /** Only log warnings for metadata check failures. Execution continues. */
118         WARN,
119         /**
120          * Use ErrorCollector to collect the metadata check failures, Execution
121          * continues.
122          */
123         COLLECT,
124         /** Assert the metadata check failures. Execution aborts. */
125         ASSERT
126     }
127 
128     /**
129      * Construct a new StaticMetadata object.
130      *
131      *<p> Default constructor, only log warnings for the static metadata check failures</p>
132      *
133      * @param characteristics static info for a camera
134      * @throws IllegalArgumentException if characteristics was null
135      */
StaticMetadata(CameraCharacteristics characteristics)136     public StaticMetadata(CameraCharacteristics characteristics) {
137         this(characteristics, CheckLevel.WARN, /*collector*/null);
138     }
139 
140     /**
141      * Construct a new StaticMetadata object with {@link CameraErrorCollector}.
142      * <p>
143      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
144      * ignored, otherwise, it will be used to log the check failures.
145      * </p>
146      *
147      * @param characteristics static info for a camera
148      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
149      * @throws IllegalArgumentException if characteristics or collector was null.
150      */
StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector)151     public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) {
152         this(characteristics, CheckLevel.COLLECT, collector);
153     }
154 
155     /**
156      * Construct a new StaticMetadata object with {@link CheckLevel} and
157      * {@link CameraErrorCollector}.
158      * <p>
159      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
160      * ignored, otherwise, it will be used to log the check failures.
161      * </p>
162      *
163      * @param characteristics static info for a camera
164      * @param level The {@link CheckLevel} of this StaticMetadata
165      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
166      * @throws IllegalArgumentException if characteristics was null or level was
167      *         {@link CheckLevel.COLLECT} but collector was null.
168      */
StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, CameraErrorCollector collector)169     public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level,
170             CameraErrorCollector collector) {
171         if (characteristics == null) {
172             throw new IllegalArgumentException("characteristics was null");
173         }
174         if (level == CheckLevel.COLLECT && collector == null) {
175             throw new IllegalArgumentException("collector must valid when COLLECT level is set");
176         }
177 
178         mCharacteristics = characteristics;
179         mLevel = level;
180         mCollector = collector;
181     }
182 
183     /**
184      * Get the CameraCharacteristics associated with this StaticMetadata.
185      *
186      * @return A non-null CameraCharacteristics object
187      */
getCharacteristics()188     public CameraCharacteristics getCharacteristics() {
189         return mCharacteristics;
190     }
191 
192     /**
193      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
194      * is at least {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}.
195      *
196      * <p>If the camera device is not reporting the hardwareLevel, this
197      * will cause the test to fail.</p>
198      *
199      * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
200      */
isHardwareLevelAtLeastFull()201     public boolean isHardwareLevelAtLeastFull() {
202         return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
203     }
204 
205     /**
206      * Whether or not the hardware level reported by android.info.supportedHardwareLevel is
207      * at least the desired one (but could be higher)
208      */
isHardwareLevelAtLeast(int level)209     public boolean isHardwareLevelAtLeast(int level) {
210         int deviceLevel = getHardwareLevelChecked();
211         if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
212             return level == deviceLevel;
213         }
214         // deviceLevel is not LEGACY, can use numerical sort
215         return level <= deviceLevel;
216     }
217 
218     /**
219      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
220      * Return the supported hardware level of the device, or fail if no value is reported.
221      *
222      * @return the supported hardware level as a constant defined for
223      *      {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
224      */
getHardwareLevelChecked()225     public int getHardwareLevelChecked() {
226         Integer hwLevel = getValueFromKeyNonNull(
227                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
228         if (hwLevel == null) {
229             Assert.fail("No supported hardware level reported.");
230         }
231         return hwLevel;
232     }
233 
234     /**
235      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
236      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}.
237      *
238      * <p>If the camera device is not reporting the hardwareLevel, this
239      * will cause the test to fail.</p>
240      *
241      * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
242      */
isHardwareLevelLegacy()243     public boolean isHardwareLevelLegacy() {
244         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
245     }
246 
247     /**
248      * Whether or not the per frame control is supported by the camera device.
249      *
250      * @return {@code true} if per frame control is supported, {@code false} otherwise.
251      */
isPerFrameControlSupported()252     public boolean isPerFrameControlSupported() {
253         return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
254     }
255 
256     /**
257      * Get the maximum number of frames to wait for a request settings being applied
258      *
259      * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency
260      *         CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control
261      *         a positive int otherwise
262      */
getSyncMaxLatency()263     public int getSyncMaxLatency() {
264         Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY);
265         if (value == null) {
266             return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN;
267         }
268         return value;
269     }
270 
271     /**
272      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
273      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
274      *
275      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
276      * will always return {@code true}.</p>
277      *
278      * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise.
279      */
isHardwareLevelLimited()280     public boolean isHardwareLevelLimited() {
281         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
282     }
283 
284     /**
285      * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel}
286      * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
287      *
288      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
289      * will always return {@code false}.</p>
290      *
291      * @return
292      *          {@code true} if the device is {@code LIMITED} or {@code FULL},
293      *          {@code false} otherwise (i.e. LEGACY).
294      */
isHardwareLevelAtLeastLimited()295     public boolean isHardwareLevelAtLeastLimited() {
296         return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
297     }
298 
299     /**
300      * Get the maximum number of partial result a request can expect
301      *
302      * @return 1 if partial result is not supported.
303      *         a integer value larger than 1 if partial result is supported.
304      */
getPartialResultCount()305     public int getPartialResultCount() {
306         Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
307         if (value == null) {
308             // Optional key. Default value is 1 if key is missing.
309             return 1;
310         }
311         return value;
312     }
313 
314     /**
315      * Get the exposure time value and clamp to the range if needed.
316      *
317      * @param exposure Input exposure time value to check.
318      * @return Exposure value in the legal range.
319      */
getExposureClampToRange(long exposure)320     public long getExposureClampToRange(long exposure) {
321         long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE);
322         long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE);
323         if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) {
324             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
325                     String.format(
326                     "Min value %d is too large, set to maximal legal value %d",
327                     minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST));
328             minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST;
329         }
330         if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) {
331             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
332                     String.format(
333                     "Max value %d is too small, set to minimal legal value %d",
334                     maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST));
335             maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST;
336         }
337 
338         return Math.max(minExposure, Math.min(maxExposure, exposure));
339     }
340 
341     /**
342      * Check if the camera device support focuser.
343      *
344      * @return true if camera device support focuser, false otherwise.
345      */
hasFocuser()346     public boolean hasFocuser() {
347         if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
348             // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
349             return (getMinimumFocusDistanceChecked() > 0);
350         } else {
351             // Check available AF modes
352             int[] availableAfModes = mCharacteristics.get(
353                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
354 
355             if (availableAfModes == null) {
356                 return false;
357             }
358 
359             // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
360             boolean hasFocuser = false;
361             loop: for (int mode : availableAfModes) {
362                 switch (mode) {
363                     case CameraMetadata.CONTROL_AF_MODE_AUTO:
364                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
365                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
366                     case CameraMetadata.CONTROL_AF_MODE_MACRO:
367                         hasFocuser = true;
368                         break loop;
369                 }
370             }
371 
372             return hasFocuser;
373         }
374     }
375 
376     /**
377      * Check if the camera device has flash unit.
378      * @return true if flash unit is available, false otherwise.
379      */
hasFlash()380     public boolean hasFlash() {
381         return getFlashInfoChecked();
382     }
383 
384     /**
385      * Get minimum focus distance.
386      *
387      * @return minimum focus distance, 0 if minimum focus distance is invalid.
388      */
getMinimumFocusDistanceChecked()389     public float getMinimumFocusDistanceChecked() {
390         Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE;
391         Float minFocusDistance;
392 
393         /**
394          * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable
395          *   devices; optional for all other devices.
396          */
397         if (isHardwareLevelAtLeastFull() || isCapabilitySupported(
398                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
399             minFocusDistance = getValueFromKeyNonNull(key);
400         } else {
401             minFocusDistance = mCharacteristics.get(key);
402         }
403 
404         if (minFocusDistance == null) {
405             return 0.0f;
406         }
407 
408         checkTrueForKey(key, " minFocusDistance value shouldn't be negative",
409                 minFocusDistance >= 0);
410         if (minFocusDistance < 0) {
411             minFocusDistance = 0.0f;
412         }
413 
414         return minFocusDistance;
415     }
416 
417     /**
418      * Get focusDistanceCalibration.
419      *
420      * @return focusDistanceCalibration, UNCALIBRATED if value is invalid.
421      */
getFocusDistanceCalibrationChecked()422     public int getFocusDistanceCalibrationChecked() {
423         Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
424         Integer calibration = getValueFromKeyNonNull(key);
425 
426         if (calibration == null) {
427             return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
428         }
429 
430         checkTrueForKey(key, " value is out of range" ,
431                 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED &&
432                 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED);
433 
434         return calibration;
435     }
436 
getAeModeName(int aeMode)437     public static String getAeModeName(int aeMode) {
438         return (aeMode >= AE_MODE_NAMES.length) ? String.format("VENDOR_AE_MODE_%d", aeMode) :
439                 AE_MODE_NAMES[aeMode];
440     }
441 
getAfModeName(int afMode)442     public static String getAfModeName(int afMode) {
443         return (afMode >= AF_MODE_NAMES.length) ? String.format("VENDOR_AF_MODE_%d", afMode) :
444                 AF_MODE_NAMES[afMode];
445     }
446 
447     /**
448      * Get max AE regions and do sanity check.
449      *
450      * @return AE max regions supported by the camera device
451      */
getAeMaxRegionsChecked()452     public int getAeMaxRegionsChecked() {
453         Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
454         if (regionCount == null) {
455             return 0;
456         }
457         return regionCount;
458     }
459 
460     /**
461      * Get max AWB regions and do sanity check.
462      *
463      * @return AWB max regions supported by the camera device
464      */
getAwbMaxRegionsChecked()465     public int getAwbMaxRegionsChecked() {
466         Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
467         if (regionCount == null) {
468             return 0;
469         }
470         return regionCount;
471     }
472 
473     /**
474      * Get max AF regions and do sanity check.
475      *
476      * @return AF max regions supported by the camera device
477      */
getAfMaxRegionsChecked()478     public int getAfMaxRegionsChecked() {
479         Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
480         if (regionCount == null) {
481             return 0;
482         }
483         return regionCount;
484     }
485     /**
486      * Get the available anti-banding modes.
487      *
488      * @return The array contains available anti-banding modes.
489      */
getAeAvailableAntiBandingModesChecked()490     public int[] getAeAvailableAntiBandingModesChecked() {
491         Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
492         int[] modes = getValueFromKeyNonNull(key);
493 
494         boolean foundAuto = false;
495         boolean found50Hz = false;
496         boolean found60Hz = false;
497         for (int mode : modes) {
498             checkTrueForKey(key, "mode value " + mode + " is out if range",
499                     mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF ||
500                     mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
501             if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) {
502                 foundAuto = true;
503             } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ) {
504                 found50Hz = true;
505             } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ) {
506                 found60Hz = true;
507             }
508         }
509         // Must contain AUTO mode or one of 50/60Hz mode.
510         checkTrueForKey(key, "Either AUTO mode or both 50HZ/60HZ mode should present",
511                 foundAuto || (found50Hz && found60Hz));
512 
513         return modes;
514     }
515 
516     /**
517      * Check if the antibanding OFF mode is supported.
518      *
519      * @return true if antibanding OFF mode is supported, false otherwise.
520      */
isAntiBandingOffModeSupported()521     public boolean isAntiBandingOffModeSupported() {
522         List<Integer> antiBandingModes =
523                 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
524 
525         return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
526     }
527 
getFlashInfoChecked()528     public Boolean getFlashInfoChecked() {
529         Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
530         Boolean hasFlash = getValueFromKeyNonNull(key);
531 
532         // In case the failOnKey only gives warning.
533         if (hasFlash == null) {
534             return false;
535         }
536 
537         return hasFlash;
538     }
539 
getAvailableTestPatternModesChecked()540     public int[] getAvailableTestPatternModesChecked() {
541         Key<int[]> key =
542                 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
543         int[] modes = getValueFromKeyNonNull(key);
544 
545         if (modes == null) {
546             return new int[0];
547         }
548 
549         int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF;
550         Integer[] boxedModes = CameraTestUtils.toObject(modes);
551         checkTrueForKey(key, " value must contain OFF mode",
552                 Arrays.asList(boxedModes).contains(expectValue));
553 
554         return modes;
555     }
556 
557     /**
558      * Get available thumbnail sizes and do the sanity check.
559      *
560      * @return The array of available thumbnail sizes
561      */
getAvailableThumbnailSizesChecked()562     public Size[] getAvailableThumbnailSizesChecked() {
563         Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES;
564         Size[] sizes = getValueFromKeyNonNull(key);
565         final List<Size> sizeList = Arrays.asList(sizes);
566 
567         // Size must contain (0, 0).
568         checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0)));
569 
570         // Each size must be distinct.
571         checkElementDistinct(key, sizeList);
572 
573         // Must be sorted in ascending order by area, by width if areas are same.
574         List<Size> orderedSizes =
575                 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true);
576         checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString()
577                 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList));
578 
579         // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations
580         // implementation see b/12958122.
581 
582         return sizes;
583     }
584 
585     /**
586      * Get available focal lengths and do the sanity check.
587      *
588      * @return The array of available focal lengths
589      */
getAvailableFocalLengthsChecked()590     public float[] getAvailableFocalLengthsChecked() {
591         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
592         float[] focalLengths = getValueFromKeyNonNull(key);
593 
594         checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1);
595 
596         for (int i = 0; i < focalLengths.length; i++) {
597             checkTrueForKey(key,
598                     String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]),
599                     focalLengths[i] > 0);
600         }
601         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths)));
602 
603         return focalLengths;
604     }
605 
606     /**
607      * Get available apertures and do the sanity check.
608      *
609      * @return The non-null array of available apertures
610      */
getAvailableAperturesChecked()611     public float[] getAvailableAperturesChecked() {
612         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES;
613         float[] apertures = getValueFromKeyNonNull(key);
614 
615         checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1);
616 
617         for (int i = 0; i < apertures.length; i++) {
618             checkTrueForKey(key,
619                     String.format("apertures[%d] %f should be positive.", i, apertures[i]),
620                     apertures[i] > 0);
621         }
622         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures)));
623 
624         return apertures;
625     }
626 
627     /**
628      * Get and check the available hot pixel map modes.
629      *
630      * @return the available hot pixel map modes
631      */
getAvailableHotPixelModesChecked()632     public int[] getAvailableHotPixelModesChecked() {
633         Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
634         int[] modes = getValueFromKeyNonNull(key);
635 
636         if (modes == null) {
637             return new int[0];
638         }
639 
640         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
641         if (isHardwareLevelAtLeastFull()) {
642             checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
643                     modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
644         }
645 
646         if (isHardwareLevelAtLeastLimited()) {
647             // FAST and HIGH_QUALITY mode must be both present or both not present
648             List<Integer> coupledModes = Arrays.asList(new Integer[] {
649                     CameraMetadata.HOT_PIXEL_MODE_FAST,
650                     CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY
651             });
652             checkTrueForKey(
653                     key, " FAST and HIGH_QUALITY mode must both present or both not present",
654                     containsAllOrNone(modeList, coupledModes));
655         }
656         checkElementDistinct(key, modeList);
657         checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
658                 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
659 
660         return modes;
661     }
662 
663     /**
664      * Get and check available face detection modes.
665      *
666      * @return The non-null array of available face detection modes
667      */
getAvailableFaceDetectModesChecked()668     public int[] getAvailableFaceDetectModesChecked() {
669         Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
670         int[] modes = getValueFromKeyNonNull(key);
671 
672         if (modes == null) {
673             return new int[0];
674         }
675 
676         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
677         checkTrueForKey(key, "Array should contain OFF mode",
678                 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF));
679         checkElementDistinct(key, modeList);
680         checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF,
681                 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
682 
683         return modes;
684     }
685 
686     /**
687      * Get and check max face detected count.
688      *
689      * @return max number of faces that can be detected
690      */
getMaxFaceCountChecked()691     public int getMaxFaceCountChecked() {
692         Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT;
693         Integer count = getValueFromKeyNonNull(key);
694 
695         if (count == null) {
696             return 0;
697         }
698 
699         List<Integer> faceDetectModes =
700                 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked()));
701         if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) &&
702                 faceDetectModes.size() == 1) {
703             checkTrueForKey(key, " value must be 0 if only OFF mode is supported in "
704                     + "availableFaceDetectionModes", count == 0);
705         } else {
706             int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST;
707 
708             // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces.
709             if (isHardwareLevelLegacy()) {
710                 maxFaceCountAtLeast = 1;
711             }
712             checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE"
713                     + "or FULL is also supported in availableFaceDetectionModes",
714                     count >= maxFaceCountAtLeast);
715         }
716 
717         return count;
718     }
719 
720     /**
721      * Get and check the available tone map modes.
722      *
723      * @return the available tone map modes
724      */
getAvailableToneMapModesChecked()725     public int[] getAvailableToneMapModesChecked() {
726         Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES;
727         int[] modes = mCharacteristics.get(key);
728 
729         if (modes == null) {
730             return new int[0];
731         }
732 
733         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
734         checkTrueForKey(key, " Camera devices must always support FAST mode",
735                 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
736         // Qualification check for MANUAL_POSTPROCESSING capability is in
737         // StaticMetadataTest#testCapabilities
738 
739         if (isHardwareLevelAtLeastLimited()) {
740             // FAST and HIGH_QUALITY mode must be both present or both not present
741             List<Integer> coupledModes = Arrays.asList(new Integer[] {
742                     CameraMetadata.TONEMAP_MODE_FAST,
743                     CameraMetadata.TONEMAP_MODE_HIGH_QUALITY
744             });
745             checkTrueForKey(
746                     key, " FAST and HIGH_QUALITY mode must both present or both not present",
747                     containsAllOrNone(modeList, coupledModes));
748         }
749         checkElementDistinct(key, modeList);
750         checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
751                 CameraMetadata.TONEMAP_MODE_PRESET_CURVE);
752 
753         return modes;
754     }
755 
756     /**
757      * Get and check max tonemap curve point.
758      *
759      * @return Max tonemap curve points.
760      */
getMaxTonemapCurvePointChecked()761     public int getMaxTonemapCurvePointChecked() {
762         Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS;
763         Integer count = getValueFromKeyNonNull(key);
764         List<Integer> modeList =
765                 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked()));
766         boolean tonemapCurveOutputSupported =
767                 modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) ||
768                 modeList.contains(CameraMetadata.TONEMAP_MODE_GAMMA_VALUE) ||
769                 modeList.contains(CameraMetadata.TONEMAP_MODE_PRESET_CURVE);
770 
771         if (count == null) {
772             if (tonemapCurveOutputSupported) {
773                 Assert.fail("Tonemap curve output is supported but MAX_CURVE_POINTS is null");
774             }
775             return 0;
776         }
777 
778         if (tonemapCurveOutputSupported) {
779             checkTrueForKey(key, "Tonemap curve output supported camera device must support "
780                     + "maxCurvePoints >= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST,
781                     count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST);
782         }
783 
784         return count;
785     }
786 
787     /**
788      * Get and check pixel array size.
789      */
getPixelArraySizeChecked()790     public Size getPixelArraySizeChecked() {
791         Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE;
792         Size pixelArray = getValueFromKeyNonNull(key);
793         if (pixelArray == null) {
794             return new Size(0, 0);
795         }
796 
797         return pixelArray;
798     }
799 
800     /**
801      * Get and check pre-correction active array size.
802      */
getPreCorrectedActiveArraySizeChecked()803     public Rect getPreCorrectedActiveArraySizeChecked() {
804         Key<Rect> key = CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE;
805         Rect activeArray = getValueFromKeyNonNull(key);
806 
807         if (activeArray == null) {
808             return new Rect(0, 0, 0, 0);
809         }
810 
811         Size pixelArraySize = getPixelArraySizeChecked();
812         checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
813         checkTrueForKey(key, "values width/height are invalid",
814                 activeArray.width() <= pixelArraySize.getWidth() &&
815                 activeArray.height() <= pixelArraySize.getHeight());
816 
817         return activeArray;
818     }
819 
820     /**
821      * Get and check active array size.
822      */
getActiveArraySizeChecked()823     public Rect getActiveArraySizeChecked() {
824         Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE;
825         Rect activeArray = getValueFromKeyNonNull(key);
826 
827         if (activeArray == null) {
828             return new Rect(0, 0, 0, 0);
829         }
830 
831         Size pixelArraySize = getPixelArraySizeChecked();
832         checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
833         checkTrueForKey(key, "values width/height are invalid",
834                 activeArray.width() <= pixelArraySize.getWidth() &&
835                 activeArray.height() <= pixelArraySize.getHeight());
836 
837         return activeArray;
838     }
839 
840     /**
841      * Get the dimensions to use for RAW16 buffers.
842      */
getRawDimensChecked()843     public Size getRawDimensChecked() throws Exception {
844         Size[] targetCaptureSizes = getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
845                         StaticMetadata.StreamDirection.Output);
846         Assert.assertTrue("No capture sizes available for RAW format!",
847                 targetCaptureSizes.length != 0);
848         Rect activeArray = getPreCorrectedActiveArraySizeChecked();
849         Size preCorrectionActiveArraySize =
850                 new Size(activeArray.width(), activeArray.height());
851         Size pixelArraySize = getPixelArraySizeChecked();
852         Assert.assertTrue("Missing pre-correction active array size", activeArray.width() > 0 &&
853                 activeArray.height() > 0);
854         Assert.assertTrue("Missing pixel array size", pixelArraySize.getWidth() > 0 &&
855                 pixelArraySize.getHeight() > 0);
856         Size[] allowedArraySizes = new Size[] { preCorrectionActiveArraySize,
857                 pixelArraySize };
858         return assertArrayContainsAnyOf("Available sizes for RAW format" +
859                 " must include either the pre-corrected active array size, or the full " +
860                 "pixel array size", targetCaptureSizes, allowedArraySizes);
861     }
862 
863     /**
864      * Get the sensitivity value and clamp to the range if needed.
865      *
866      * @param sensitivity Input sensitivity value to check.
867      * @return Sensitivity value in legal range.
868      */
getSensitivityClampToRange(int sensitivity)869     public int getSensitivityClampToRange(int sensitivity) {
870         int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE);
871         int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE);
872         if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) {
873             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
874                     String.format(
875                     "Min value %d is too large, set to maximal legal value %d",
876                     minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST));
877             minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST;
878         }
879         if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) {
880             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
881                     String.format(
882                     "Max value %d is too small, set to minimal legal value %d",
883                     maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST));
884             maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST;
885         }
886 
887         return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity));
888     }
889 
890     /**
891      * Get maxAnalogSensitivity for a camera device.
892      * <p>
893      * This is only available for FULL capability device, return 0 if it is unavailable.
894      * </p>
895      *
896      * @return maxAnalogSensitivity, 0 if it is not available.
897      */
getMaxAnalogSensitivityChecked()898     public int getMaxAnalogSensitivityChecked() {
899 
900         Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
901         Integer maxAnalogsensitivity = mCharacteristics.get(key);
902         if (maxAnalogsensitivity == null) {
903             if (isHardwareLevelAtLeastFull()) {
904                 Assert.fail("Full device should report max analog sensitivity");
905             }
906             return 0;
907         }
908 
909         int minSensitivity = getSensitivityMinimumOrDefault();
910         int maxSensitivity = getSensitivityMaximumOrDefault();
911         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
912                 + " should be no larger than max sensitivity " + maxSensitivity,
913                 maxAnalogsensitivity <= maxSensitivity);
914         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
915                 + " should be larger than min sensitivity " + maxSensitivity,
916                 maxAnalogsensitivity > minSensitivity);
917 
918         return maxAnalogsensitivity;
919     }
920 
921     /**
922      * Get hyperfocalDistance and do the sanity check.
923      * <p>
924      * Note that, this tag is optional, will return -1 if this tag is not
925      * available.
926      * </p>
927      *
928      * @return hyperfocalDistance of this device, -1 if this tag is not available.
929      */
getHyperfocalDistanceChecked()930     public float getHyperfocalDistanceChecked() {
931         Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
932         Float hyperfocalDistance = getValueFromKeyNonNull(key);
933         if (hyperfocalDistance == null) {
934             return -1;
935         }
936 
937         if (hasFocuser()) {
938             float minFocusDistance = getMinimumFocusDistanceChecked();
939             checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of"
940                     + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f,
941                     minFocusDistance),
942                     hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance);
943         }
944 
945         return hyperfocalDistance;
946     }
947 
948     /**
949      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
950      *
951      * <p>If the camera is incorrectly reporting values, log a warning and return
952      * the default value instead, which is the largest minimum value required to be supported
953      * by all camera devices.</p>
954      *
955      * @return The value reported by the camera device or the defaultValue otherwise.
956      */
getSensitivityMinimumOrDefault()957     public int getSensitivityMinimumOrDefault() {
958         return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST);
959     }
960 
961     /**
962      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
963      *
964      * <p>If the camera is incorrectly reporting values, log a warning and return
965      * the default value instead.</p>
966      *
967      * @param defaultValue Value to return if no legal value is available
968      * @return The value reported by the camera device or the defaultValue otherwise.
969      */
getSensitivityMinimumOrDefault(int defaultValue)970     public int getSensitivityMinimumOrDefault(int defaultValue) {
971         Range<Integer> range = getValueFromKeyNonNull(
972                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
973         if (range == null) {
974             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
975                     "had no valid minimum value; using default of " + defaultValue);
976             return defaultValue;
977         }
978         return range.getLower();
979     }
980 
981     /**
982      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
983      *
984      * <p>If the camera is incorrectly reporting values, log a warning and return
985      * the default value instead, which is the smallest maximum value required to be supported
986      * by all camera devices.</p>
987      *
988      * @return The value reported by the camera device or the defaultValue otherwise.
989      */
getSensitivityMaximumOrDefault()990     public int getSensitivityMaximumOrDefault() {
991         return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST);
992     }
993 
994     /**
995      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
996      *
997      * <p>If the camera is incorrectly reporting values, log a warning and return
998      * the default value instead.</p>
999      *
1000      * @param defaultValue Value to return if no legal value is available
1001      * @return The value reported by the camera device or the defaultValue otherwise.
1002      */
getSensitivityMaximumOrDefault(int defaultValue)1003     public int getSensitivityMaximumOrDefault(int defaultValue) {
1004         Range<Integer> range = getValueFromKeyNonNull(
1005                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
1006         if (range == null) {
1007             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
1008                     "had no valid maximum value; using default of " + defaultValue);
1009             return defaultValue;
1010         }
1011         return range.getUpper();
1012     }
1013 
1014     /**
1015      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
1016      *
1017      * <p>If the camera is incorrectly reporting values, log a warning and return
1018      * the default value instead.</p>
1019      *
1020      * @param defaultValue Value to return if no legal value is available
1021      * @return The value reported by the camera device or the defaultValue otherwise.
1022      */
getExposureMinimumOrDefault(long defaultValue)1023     public long getExposureMinimumOrDefault(long defaultValue) {
1024         Range<Long> range = getValueFromKeyNonNull(
1025                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
1026         if (range == null) {
1027             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
1028                     "had no valid minimum value; using default of " + defaultValue);
1029             return defaultValue;
1030         }
1031         return range.getLower();
1032     }
1033 
1034     /**
1035      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
1036      *
1037      * <p>If the camera is incorrectly reporting values, log a warning and return
1038      * the default value instead, which is the largest minimum value required to be supported
1039      * by all camera devices.</p>
1040      *
1041      * @return The value reported by the camera device or the defaultValue otherwise.
1042      */
getExposureMinimumOrDefault()1043     public long getExposureMinimumOrDefault() {
1044         return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST);
1045     }
1046 
1047     /**
1048      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
1049      *
1050      * <p>If the camera is incorrectly reporting values, log a warning and return
1051      * the default value instead.</p>
1052      *
1053      * @param defaultValue Value to return if no legal value is available
1054      * @return The value reported by the camera device or the defaultValue otherwise.
1055      */
getExposureMaximumOrDefault(long defaultValue)1056     public long getExposureMaximumOrDefault(long defaultValue) {
1057         Range<Long> range = getValueFromKeyNonNull(
1058                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
1059         if (range == null) {
1060             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
1061                     "had no valid maximum value; using default of " + defaultValue);
1062             return defaultValue;
1063         }
1064         return range.getUpper();
1065     }
1066 
1067     /**
1068      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
1069      *
1070      * <p>If the camera is incorrectly reporting values, log a warning and return
1071      * the default value instead, which is the smallest maximum value required to be supported
1072      * by all camera devices.</p>
1073      *
1074      * @return The value reported by the camera device or the defaultValue otherwise.
1075      */
getExposureMaximumOrDefault()1076     public long getExposureMaximumOrDefault() {
1077         return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST);
1078     }
1079 
1080     /**
1081      * get android.control.availableModes and do the sanity check.
1082      *
1083      * @return available control modes.
1084      */
getAvailableControlModesChecked()1085     public int[] getAvailableControlModesChecked() {
1086         Key<int[]> modesKey = CameraCharacteristics.CONTROL_AVAILABLE_MODES;
1087         int[] modes = getValueFromKeyNonNull(modesKey);
1088         if (modes == null) {
1089             modes = new int[0];
1090         }
1091 
1092         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1093         checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
1094 
1095         // All camera device must support AUTO
1096         checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain AUTO mode",
1097                 modeList.contains(CameraMetadata.CONTROL_MODE_AUTO));
1098 
1099         boolean isAeOffSupported =  Arrays.asList(
1100                 CameraTestUtils.toObject(getAeAvailableModesChecked())).contains(
1101                         CameraMetadata.CONTROL_AE_MODE_OFF);
1102         boolean isAfOffSupported =  Arrays.asList(
1103                 CameraTestUtils.toObject(getAfAvailableModesChecked())).contains(
1104                         CameraMetadata.CONTROL_AF_MODE_OFF);
1105         boolean isAwbOffSupported =  Arrays.asList(
1106                 CameraTestUtils.toObject(getAwbAvailableModesChecked())).contains(
1107                         CameraMetadata.CONTROL_AWB_MODE_OFF);
1108         if (isAeOffSupported && isAfOffSupported && isAwbOffSupported) {
1109             // 3A OFF controls are supported, OFF mode must be supported here.
1110             checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain OFF mode",
1111                     modeList.contains(CameraMetadata.CONTROL_MODE_OFF));
1112         }
1113 
1114         if (isSceneModeSupported()) {
1115             checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain"
1116                     + " USE_SCENE_MODE",
1117                     modeList.contains(CameraMetadata.CONTROL_MODE_USE_SCENE_MODE));
1118         }
1119 
1120         return modes;
1121     }
1122 
isSceneModeSupported()1123     public boolean isSceneModeSupported() {
1124         List<Integer> availableSceneModes = Arrays.asList(
1125                 CameraTestUtils.toObject(getAvailableSceneModesChecked()));
1126 
1127         if (availableSceneModes.isEmpty()) {
1128             return false;
1129         }
1130 
1131         // If sceneMode is not supported, camera device will contain single entry: DISABLED.
1132         return availableSceneModes.size() > 1 ||
1133                 !availableSceneModes.contains(CameraMetadata.CONTROL_SCENE_MODE_DISABLED);
1134     }
1135 
1136     /**
1137      * Get aeAvailableModes and do the sanity check.
1138      *
1139      * <p>Depending on the check level this class has, for WAR or COLLECT levels,
1140      * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
1141      * have to abort the execution even the aeMode list is invalid.</p>
1142      * @return AE available modes
1143      */
getAeAvailableModesChecked()1144     public int[] getAeAvailableModesChecked() {
1145         Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
1146         int[] modes = getValueFromKeyNonNull(modesKey);
1147         if (modes == null) {
1148             modes = new int[0];
1149         }
1150         List<Integer> modeList = new ArrayList<Integer>();
1151         for (int mode : modes) {
1152             // Skip vendor-added modes
1153             if (mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
1154                 modeList.add(mode);
1155             }
1156         }
1157         checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
1158         modes = new int[modeList.size()];
1159         for (int i = 0; i < modeList.size(); i++) {
1160             modes[i] = modeList.get(i);
1161         }
1162 
1163         // All camera device must support ON
1164         checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
1165                 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
1166 
1167         // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
1168         Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
1169         Boolean hasFlash = getValueFromKeyNonNull(flashKey);
1170         if (hasFlash == null) {
1171             hasFlash = false;
1172         }
1173         if (hasFlash) {
1174             boolean flashModeConsistentWithFlash =
1175                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
1176                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
1177             checkTrueForKey(modesKey,
1178                     "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and  when flash is" +
1179                     "available", flashModeConsistentWithFlash);
1180         } else {
1181             boolean flashModeConsistentWithoutFlash =
1182                     !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
1183                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
1184                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
1185             checkTrueForKey(modesKey,
1186                     "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
1187                     "ON_AUTO_FLASH_REDEYE when flash is unavailable",
1188                     flashModeConsistentWithoutFlash);
1189         }
1190 
1191         // FULL mode camera devices always support OFF mode.
1192         boolean condition =
1193                 !isHardwareLevelAtLeastFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
1194         checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
1195 
1196         // Boundary check.
1197         for (int mode : modes) {
1198             checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
1199                     mode >= CameraMetadata.CONTROL_AE_MODE_OFF
1200                     && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
1201         }
1202 
1203         return modes;
1204     }
1205 
1206     /**
1207      * Get available AWB modes and do the sanity check.
1208      *
1209      * @return array that contains available AWB modes, empty array if awbAvailableModes is
1210      * unavailable.
1211      */
getAwbAvailableModesChecked()1212     public int[] getAwbAvailableModesChecked() {
1213         Key<int[]> key =
1214                 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
1215         int[] awbModes = getValueFromKeyNonNull(key);
1216 
1217         if (awbModes == null) {
1218             return new int[0];
1219         }
1220 
1221         List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
1222         checkTrueForKey(key, " All camera devices must support AUTO mode",
1223                 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
1224         if (isHardwareLevelAtLeastFull()) {
1225             checkTrueForKey(key, " Full capability camera devices must support OFF mode",
1226                     modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
1227         }
1228 
1229         return awbModes;
1230     }
1231 
1232     /**
1233      * Get available AF modes and do the sanity check.
1234      *
1235      * @return array that contains available AF modes, empty array if afAvailableModes is
1236      * unavailable.
1237      */
getAfAvailableModesChecked()1238     public int[] getAfAvailableModesChecked() {
1239         Key<int[]> key =
1240                 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
1241         int[] afModes = getValueFromKeyNonNull(key);
1242 
1243         if (afModes == null) {
1244             return new int[0];
1245         }
1246 
1247         List<Integer> modesList = new ArrayList<Integer>();
1248         for (int afMode : afModes) {
1249             // Skip vendor-added AF modes
1250             if (afMode > CameraCharacteristics.CONTROL_AF_MODE_EDOF) continue;
1251             modesList.add(afMode);
1252         }
1253         afModes = new int[modesList.size()];
1254         for (int i = 0; i < modesList.size(); i++) {
1255             afModes[i] = modesList.get(i);
1256         }
1257 
1258         if (isHardwareLevelAtLeastLimited()) {
1259             // Some LEGACY mode devices do not support AF OFF
1260             checkTrueForKey(key, " All camera devices must support OFF mode",
1261                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
1262         }
1263         if (hasFocuser()) {
1264             checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
1265                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
1266         }
1267 
1268         return afModes;
1269     }
1270 
1271     /**
1272      * Get supported raw output sizes and do the check.
1273      *
1274      * @return Empty size array if raw output is not supported
1275      */
getRawOutputSizesChecked()1276     public Size[] getRawOutputSizesChecked() {
1277         return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
1278                 StreamDirection.Output);
1279     }
1280 
1281     /**
1282      * Get supported jpeg output sizes and do the check.
1283      *
1284      * @return Empty size array if jpeg output is not supported
1285      */
getJpegOutputSizesChecked()1286     public Size[] getJpegOutputSizesChecked() {
1287         return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
1288                 StreamDirection.Output);
1289     }
1290 
1291     /**
1292      * Used to determine the stream direction for various helpers that look up
1293      * format or size information.
1294      */
1295     public enum StreamDirection {
1296         /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
1297         Output,
1298         /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
1299         Input
1300     }
1301 
1302     /**
1303      * Get available formats for a given direction.
1304      *
1305      * @param direction The stream direction, input or output.
1306      * @return The formats of the given direction, empty array if no available format is found.
1307      */
getAvailableFormats(StreamDirection direction)1308     public int[] getAvailableFormats(StreamDirection direction) {
1309         Key<StreamConfigurationMap> key =
1310                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1311         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1312 
1313         if (config == null) {
1314             return new int[0];
1315         }
1316 
1317         switch (direction) {
1318             case Output:
1319                 return config.getOutputFormats();
1320             case Input:
1321                 return config.getInputFormats();
1322             default:
1323                 throw new IllegalArgumentException("direction must be output or input");
1324         }
1325     }
1326 
1327     /**
1328      * Get valid output formats for a given input format.
1329      *
1330      * @param inputFormat The input format used to produce the output images.
1331      * @return The output formats for the given input format, empty array if
1332      *         no available format is found.
1333      */
getValidOutputFormatsForInput(int inputFormat)1334     public int[] getValidOutputFormatsForInput(int inputFormat) {
1335         Key<StreamConfigurationMap> key =
1336                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1337         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1338 
1339         if (config == null) {
1340             return new int[0];
1341         }
1342 
1343         return config.getValidOutputFormatsForInput(inputFormat);
1344     }
1345 
1346     /**
1347      * Get available sizes for given format and direction.
1348      *
1349      * @param format The format for the requested size array.
1350      * @param direction The stream direction, input or output.
1351      * @return The sizes of the given format, empty array if no available size is found.
1352      */
getAvailableSizesForFormatChecked(int format, StreamDirection direction)1353     public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
1354         return getAvailableSizesForFormatChecked(format, direction,
1355                 /*fastSizes*/true, /*slowSizes*/true);
1356     }
1357 
1358     /**
1359      * Get available sizes for given format and direction, and whether to limit to slow or fast
1360      * resolutions.
1361      *
1362      * @param format The format for the requested size array.
1363      * @param direction The stream direction, input or output.
1364      * @param fastSizes whether to include getOutputSizes() sizes (generally faster)
1365      * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower)
1366      * @return The sizes of the given format, empty array if no available size is found.
1367      */
getAvailableSizesForFormatChecked(int format, StreamDirection direction, boolean fastSizes, boolean slowSizes)1368     public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction,
1369             boolean fastSizes, boolean slowSizes) {
1370         Key<StreamConfigurationMap> key =
1371                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1372         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1373 
1374         if (config == null) {
1375             return new Size[0];
1376         }
1377 
1378         Size[] sizes = null;
1379 
1380         switch (direction) {
1381             case Output:
1382                 Size[] fastSizeList = null;
1383                 Size[] slowSizeList = null;
1384                 if (fastSizes) {
1385                     fastSizeList = config.getOutputSizes(format);
1386                 }
1387                 if (slowSizes) {
1388                     slowSizeList = config.getHighResolutionOutputSizes(format);
1389                 }
1390                 if (fastSizeList != null && slowSizeList != null) {
1391                     sizes = new Size[slowSizeList.length + fastSizeList.length];
1392                     System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length);
1393                     System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length);
1394                 } else if (fastSizeList != null) {
1395                     sizes = fastSizeList;
1396                 } else if (slowSizeList != null) {
1397                     sizes = slowSizeList;
1398                 }
1399                 break;
1400             case Input:
1401                 sizes = config.getInputSizes(format);
1402                 break;
1403             default:
1404                 throw new IllegalArgumentException("direction must be output or input");
1405         }
1406 
1407         if (sizes == null) {
1408             sizes = new Size[0];
1409         }
1410 
1411         return sizes;
1412     }
1413 
1414     /**
1415      * Get available AE target fps ranges.
1416      *
1417      * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
1418      */
1419     @SuppressWarnings("raw")
getAeAvailableTargetFpsRangesChecked()1420     public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
1421         Key<Range<Integer>[]> key =
1422                 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
1423         Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
1424 
1425         if (fpsRanges == null) {
1426             return new Range[0];
1427         }
1428 
1429         // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
1430         // in case the above check fails.
1431         int fpsRangeLength = fpsRanges.length;
1432         int minFps, maxFps;
1433         long maxFrameDuration = getMaxFrameDurationChecked();
1434         for (int i = 0; i < fpsRangeLength; i += 1) {
1435             minFps = fpsRanges[i].getLower();
1436             maxFps = fpsRanges[i].getUpper();
1437             checkTrueForKey(key, " min fps must be no larger than max fps!",
1438                     minFps > 0 && maxFps >= minFps);
1439             long maxDuration = (long) (1e9 / minFps);
1440             checkTrueForKey(key, String.format(
1441                     " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
1442                     maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
1443         }
1444         return fpsRanges;
1445     }
1446 
1447     /**
1448      * Get the highest supported target FPS range.
1449      * Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS.
1450      */
getAeMaxTargetFpsRange()1451     public Range<Integer> getAeMaxTargetFpsRange() {
1452         Range<Integer>[] fpsRanges = getAeAvailableTargetFpsRangesChecked();
1453 
1454         Range<Integer> targetRange = fpsRanges[0];
1455         // Assume unsorted list of target FPS ranges, so use two passes, first maximize min FPS
1456         for (Range<Integer> candidateRange : fpsRanges) {
1457             if (candidateRange.getLower() > targetRange.getLower()) {
1458                 targetRange = candidateRange;
1459             }
1460         }
1461         // Then maximize max FPS while not lowering min FPS
1462         for (Range<Integer> candidateRange : fpsRanges) {
1463             if (candidateRange.getLower() >= targetRange.getLower() &&
1464                     candidateRange.getUpper() > targetRange.getUpper()) {
1465                 targetRange = candidateRange;
1466             }
1467         }
1468         return targetRange;
1469     }
1470 
1471     /**
1472      * Get max frame duration.
1473      *
1474      * @return 0 if maxFrameDuration is null
1475      */
getMaxFrameDurationChecked()1476     public long getMaxFrameDurationChecked() {
1477         Key<Long> key =
1478                 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
1479         Long maxDuration = getValueFromKeyNonNull(key);
1480 
1481         if (maxDuration == null) {
1482             return 0;
1483         }
1484 
1485         return maxDuration;
1486     }
1487 
1488     /**
1489      * Get available minimal frame durations for a given format.
1490      *
1491      * @param format One of the format from {@link ImageFormat}.
1492      * @return HashMap of minimal frame durations for different sizes, empty HashMap
1493      *         if availableMinFrameDurations is null.
1494      */
getAvailableMinFrameDurationsForFormatChecked(int format)1495     public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
1496 
1497         HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
1498 
1499         Key<StreamConfigurationMap> key =
1500                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1501         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1502 
1503         if (config == null) {
1504             return minDurationMap;
1505         }
1506 
1507         for (android.util.Size size : getAvailableSizesForFormatChecked(format,
1508                 StreamDirection.Output)) {
1509             long minFrameDuration = config.getOutputMinFrameDuration(format, size);
1510 
1511             if (minFrameDuration != 0) {
1512                 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
1513             }
1514         }
1515 
1516         return minDurationMap;
1517     }
1518 
getAvailableEdgeModesChecked()1519     public int[] getAvailableEdgeModesChecked() {
1520         Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
1521         int[] edgeModes = getValueFromKeyNonNull(key);
1522 
1523         if (edgeModes == null) {
1524             return new int[0];
1525         }
1526 
1527         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
1528         // Full device should always include OFF and FAST
1529         if (isHardwareLevelAtLeastFull()) {
1530             checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
1531                     modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
1532                     modeList.contains(CameraMetadata.EDGE_MODE_FAST));
1533         }
1534 
1535         if (isHardwareLevelAtLeastLimited()) {
1536             // FAST and HIGH_QUALITY mode must be both present or both not present
1537             List<Integer> coupledModes = Arrays.asList(new Integer[] {
1538                     CameraMetadata.EDGE_MODE_FAST,
1539                     CameraMetadata.EDGE_MODE_HIGH_QUALITY
1540             });
1541             checkTrueForKey(
1542                     key, " FAST and HIGH_QUALITY mode must both present or both not present",
1543                     containsAllOrNone(modeList, coupledModes));
1544         }
1545 
1546         return edgeModes;
1547     }
1548 
getAvailableNoiseReductionModesChecked()1549     public int[] getAvailableNoiseReductionModesChecked() {
1550         Key<int[]> key =
1551                 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
1552         int[] noiseReductionModes = getValueFromKeyNonNull(key);
1553 
1554         if (noiseReductionModes == null) {
1555             return new int[0];
1556         }
1557 
1558         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
1559         // Full device should always include OFF and FAST
1560         if (isHardwareLevelAtLeastFull()) {
1561 
1562             checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
1563                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
1564                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
1565         }
1566 
1567         if (isHardwareLevelAtLeastLimited()) {
1568             // FAST and HIGH_QUALITY mode must be both present or both not present
1569             List<Integer> coupledModes = Arrays.asList(new Integer[] {
1570                     CameraMetadata.NOISE_REDUCTION_MODE_FAST,
1571                     CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY
1572             });
1573             checkTrueForKey(
1574                     key, " FAST and HIGH_QUALITY mode must both present or both not present",
1575                     containsAllOrNone(modeList, coupledModes));
1576         }
1577         return noiseReductionModes;
1578     }
1579 
1580     /**
1581      * Get value of key android.control.aeCompensationStep and do the sanity check.
1582      *
1583      * @return default value if the value is null.
1584      */
getAeCompensationStepChecked()1585     public Rational getAeCompensationStepChecked() {
1586         Key<Rational> key =
1587                 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
1588         Rational compensationStep = getValueFromKeyNonNull(key);
1589 
1590         if (compensationStep == null) {
1591             // Return default step.
1592             return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
1593         }
1594 
1595         // Legacy devices don't have a minimum step requirement
1596         if (isHardwareLevelAtLeastLimited()) {
1597             float compensationStepF =
1598                     (float) compensationStep.getNumerator() / compensationStep.getDenominator();
1599             checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
1600         }
1601 
1602         return compensationStep;
1603     }
1604 
1605     /**
1606      * Get value of key android.control.aeCompensationRange and do the sanity check.
1607      *
1608      * @return default value if the value is null or malformed.
1609      */
getAeCompensationRangeChecked()1610     public Range<Integer> getAeCompensationRangeChecked() {
1611         Key<Range<Integer>> key =
1612                 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
1613         Range<Integer> compensationRange = getValueFromKeyNonNull(key);
1614         Rational compensationStep = getAeCompensationStepChecked();
1615         float compensationStepF = compensationStep.floatValue();
1616         final Range<Integer> DEFAULT_RANGE = Range.create(
1617                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF),
1618                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
1619         final Range<Integer> ZERO_RANGE = Range.create(0, 0);
1620         if (compensationRange == null) {
1621             return ZERO_RANGE;
1622         }
1623 
1624         // Legacy devices don't have a minimum range requirement
1625         if (isHardwareLevelAtLeastLimited() && !compensationRange.equals(ZERO_RANGE)) {
1626             checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
1627                     + ", actual " + compensationRange + ", compensation step " + compensationStep,
1628                    compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
1629                    compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
1630         }
1631 
1632         return compensationRange;
1633     }
1634 
1635     /**
1636      * Get availableVideoStabilizationModes and do the sanity check.
1637      *
1638      * @return available video stabilization modes, empty array if it is unavailable.
1639      */
getAvailableVideoStabilizationModesChecked()1640     public int[] getAvailableVideoStabilizationModesChecked() {
1641         Key<int[]> key =
1642                 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
1643         int[] modes = getValueFromKeyNonNull(key);
1644 
1645         if (modes == null) {
1646             return new int[0];
1647         }
1648 
1649         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1650         checkTrueForKey(key, " All device should support OFF mode",
1651                 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
1652         checkArrayValuesInRange(key, modes,
1653                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
1654                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
1655 
1656         return modes;
1657     }
1658 
isVideoStabilizationSupported()1659     public boolean isVideoStabilizationSupported() {
1660         Integer[] videoStabModes =
1661                 CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked());
1662         return Arrays.asList(videoStabModes).contains(
1663                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
1664     }
1665 
1666     /**
1667      * Get availableOpticalStabilization and do the sanity check.
1668      *
1669      * @return available optical stabilization modes, empty array if it is unavailable.
1670      */
getAvailableOpticalStabilizationChecked()1671     public int[] getAvailableOpticalStabilizationChecked() {
1672         Key<int[]> key =
1673                 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
1674         int[] modes = getValueFromKeyNonNull(key);
1675 
1676         if (modes == null) {
1677             return new int[0];
1678         }
1679 
1680         checkArrayValuesInRange(key, modes,
1681                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
1682                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
1683 
1684         return modes;
1685     }
1686 
1687     /**
1688      * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
1689      * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
1690      */
getAvailableMaxDigitalZoomChecked()1691     public float getAvailableMaxDigitalZoomChecked() {
1692         Key<Float> key =
1693                 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
1694 
1695         Float maxZoom = getValueFromKeyNonNull(key);
1696         if (maxZoom == null) {
1697             return 1.0f;
1698         }
1699 
1700         checkTrueForKey(key, " max digital zoom should be no less than 1",
1701                 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
1702 
1703         return maxZoom;
1704     }
1705 
getAvailableSceneModesChecked()1706     public int[] getAvailableSceneModesChecked() {
1707         Key<int[]> key =
1708                 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
1709         int[] modes = getValueFromKeyNonNull(key);
1710 
1711         if (modes == null) {
1712             return new int[0];
1713         }
1714 
1715         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1716         // FACE_PRIORITY must be included if face detection is supported.
1717         if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
1718                 getMaxFaceCountChecked() > 0) {
1719             checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
1720                     modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
1721         }
1722 
1723         return modes;
1724     }
1725 
getAvailableEffectModesChecked()1726     public int[] getAvailableEffectModesChecked() {
1727         Key<int[]> key =
1728                 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
1729         int[] modes = getValueFromKeyNonNull(key);
1730 
1731         if (modes == null) {
1732             return new int[0];
1733         }
1734 
1735         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1736         // OFF must be included.
1737         checkTrueForKey(key, " OFF must be included",
1738                 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
1739 
1740         return modes;
1741     }
1742 
1743     /**
1744      * Get and check the available color aberration modes
1745      *
1746      * @return the available color aberration modes
1747      */
getAvailableColorAberrationModesChecked()1748     public int[] getAvailableColorAberrationModesChecked() {
1749         Key<int[]> key =
1750                 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
1751         int[] modes = getValueFromKeyNonNull(key);
1752 
1753         if (modes == null) {
1754             return new int[0];
1755         }
1756 
1757         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1758         checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode",
1759                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) ||
1760                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST));
1761 
1762         if (isHardwareLevelAtLeastLimited()) {
1763             // FAST and HIGH_QUALITY mode must be both present or both not present
1764             List<Integer> coupledModes = Arrays.asList(new Integer[] {
1765                     CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST,
1766                     CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
1767             });
1768             checkTrueForKey(
1769                     key, " FAST and HIGH_QUALITY mode must both present or both not present",
1770                     containsAllOrNone(modeList, coupledModes));
1771         }
1772         checkElementDistinct(key, modeList);
1773         checkArrayValuesInRange(key, modes,
1774                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
1775                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
1776 
1777         return modes;
1778     }
1779 
1780     /**
1781      * Get max pipeline depth and do the sanity check.
1782      *
1783      * @return max pipeline depth, default value if it is not available.
1784      */
getPipelineMaxDepthChecked()1785     public byte getPipelineMaxDepthChecked() {
1786         Key<Byte> key =
1787                 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
1788         Byte maxDepth = getValueFromKeyNonNull(key);
1789 
1790         if (maxDepth == null) {
1791             return REQUEST_PIPELINE_MAX_DEPTH_MAX;
1792         }
1793 
1794         checkTrueForKey(key, " max pipeline depth should be no larger than "
1795                 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
1796 
1797         return maxDepth;
1798     }
1799 
1800     /**
1801      * Get available lens shading modes.
1802      */
getAvailableLensShadingModesChecked()1803      public int[] getAvailableLensShadingModesChecked() {
1804          Key<int[]> key =
1805                  CameraCharacteristics.SHADING_AVAILABLE_MODES;
1806          int[] modes = getValueFromKeyNonNull(key);
1807          if (modes == null) {
1808              return new int[0];
1809          }
1810 
1811          List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1812          // FAST must be included.
1813          checkTrueForKey(key, " FAST must be included",
1814                  modeList.contains(CameraMetadata.SHADING_MODE_FAST));
1815 
1816          if (isCapabilitySupported(
1817                  CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) {
1818              checkTrueForKey(key, " OFF must be included for MANUAL_POST_PROCESSING devices",
1819                      modeList.contains(CameraMetadata.SHADING_MODE_OFF));
1820          }
1821          return modes;
1822      }
1823 
1824      /**
1825       * Get available lens shading map modes.
1826       */
getAvailableLensShadingMapModesChecked()1827       public int[] getAvailableLensShadingMapModesChecked() {
1828           Key<int[]> key =
1829                   CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
1830           int[] modes = getValueFromKeyNonNull(key);
1831           if (modes == null) {
1832               return new int[0];
1833           }
1834 
1835           List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1836 
1837           if (isCapabilitySupported(
1838                   CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
1839               checkTrueForKey(key, " ON must be included for RAW capability devices",
1840                       modeList.contains(CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON));
1841           }
1842           return modes;
1843       }
1844 
1845 
1846     /**
1847      * Get available capabilities and do the sanity check.
1848      *
1849      * @return reported available capabilities list, empty list if the value is unavailable.
1850      */
getAvailableCapabilitiesChecked()1851     public List<Integer> getAvailableCapabilitiesChecked() {
1852         Key<int[]> key =
1853                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
1854         int[] availableCaps = getValueFromKeyNonNull(key);
1855         List<Integer> capList;
1856 
1857         if (availableCaps == null) {
1858             return new ArrayList<Integer>();
1859         }
1860 
1861         checkArrayValuesInRange(key, availableCaps,
1862                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
1863                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO);
1864         capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
1865         return capList;
1866     }
1867 
1868     /**
1869      * Determine whether the current device supports a capability or not.
1870      *
1871      * @param capability (non-negative)
1872      *
1873      * @return {@code true} if the capability is supported, {@code false} otherwise.
1874      *
1875      * @throws IllegalArgumentException if {@code capability} was negative
1876      *
1877      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
1878      */
isCapabilitySupported(int capability)1879     public boolean isCapabilitySupported(int capability) {
1880         if (capability < 0) {
1881             throw new IllegalArgumentException("capability must be non-negative");
1882         }
1883 
1884         List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
1885 
1886         return availableCapabilities.contains(capability);
1887     }
1888 
1889     /**
1890      * Determine whether or not all the {@code keys} are available characteristics keys
1891      * (as in {@link CameraCharacteristics#getKeys}.
1892      *
1893      * <p>If this returns {@code true}, then querying for this key from a characteristics
1894      * object will always return a non-{@code null} value.</p>
1895      *
1896      * @param keys collection of camera characteristics keys
1897      * @return whether or not all characteristics keys are available
1898      */
areCharacteristicsKeysAvailable( Collection<CameraCharacteristics.Key<?>> keys)1899     public final boolean areCharacteristicsKeysAvailable(
1900             Collection<CameraCharacteristics.Key<?>> keys) {
1901         return mCharacteristics.getKeys().containsAll(keys);
1902     }
1903 
1904     /**
1905      * Determine whether or not all the {@code keys} are available result keys
1906      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1907      *
1908      * <p>If this returns {@code true}, then querying for this key from a result
1909      * object will almost always return a non-{@code null} value.</p>
1910      *
1911      * <p>In some cases (e.g. lens shading map), the request must have additional settings
1912      * configured in order for the key to correspond to a value.</p>
1913      *
1914      * @param keys collection of capture result keys
1915      * @return whether or not all result keys are available
1916      */
areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys)1917     public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
1918         return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
1919     }
1920 
1921     /**
1922      * Determine whether or not all the {@code keys} are available request keys
1923      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1924      *
1925      * <p>If this returns {@code true}, then setting this key in the request builder
1926      * may have some effect (and if it's {@code false}, then the camera device will
1927      * definitely ignore it).</p>
1928      *
1929      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1930      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1931      *
1932      * @param keys collection of capture request keys
1933      * @return whether or not all result keys are available
1934      */
areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys)1935     public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
1936         return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
1937     }
1938 
1939     /**
1940      * Determine whether or not all the {@code keys} are available characteristics keys
1941      * (as in {@link CameraCharacteristics#getKeys}.
1942      *
1943      * <p>If this returns {@code true}, then querying for this key from a characteristics
1944      * object will always return a non-{@code null} value.</p>
1945      *
1946      * @param keys one or more camera characteristic keys
1947      * @return whether or not all characteristics keys are available
1948      */
1949     @SafeVarargs
areKeysAvailable(CameraCharacteristics.Key<?>.... keys)1950     public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) {
1951         return areCharacteristicsKeysAvailable(Arrays.asList(keys));
1952     }
1953 
1954     /**
1955      * Determine whether or not all the {@code keys} are available result keys
1956      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1957      *
1958      * <p>If this returns {@code true}, then querying for this key from a result
1959      * object will almost always return a non-{@code null} value.</p>
1960      *
1961      * <p>In some cases (e.g. lens shading map), the request must have additional settings
1962      * configured in order for the key to correspond to a value.</p>
1963      *
1964      * @param keys one or more capture result keys
1965      * @return whether or not all result keys are available
1966      */
1967     @SafeVarargs
areKeysAvailable(CaptureResult.Key<?>.... keys)1968     public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
1969         return areResultKeysAvailable(Arrays.asList(keys));
1970     }
1971 
1972     /**
1973      * Determine whether or not all the {@code keys} are available request keys
1974      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1975      *
1976      * <p>If this returns {@code true}, then setting this key in the request builder
1977      * may have some effect (and if it's {@code false}, then the camera device will
1978      * definitely ignore it).</p>
1979      *
1980      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1981      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1982      *
1983      * @param keys one or more capture request keys
1984      * @return whether or not all result keys are available
1985      */
1986     @SafeVarargs
areKeysAvailable(CaptureRequest.Key<?>.... keys)1987     public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
1988         return areRequestKeysAvailable(Arrays.asList(keys));
1989     }
1990 
1991     /*
1992      * Determine if camera device support AE lock control
1993      *
1994      * @return {@code true} if AE lock control is supported
1995      */
isAeLockSupported()1996     public boolean isAeLockSupported() {
1997         return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
1998     }
1999 
2000     /*
2001      * Determine if camera device support AWB lock control
2002      *
2003      * @return {@code true} if AWB lock control is supported
2004      */
isAwbLockSupported()2005     public boolean isAwbLockSupported() {
2006         return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
2007     }
2008 
2009 
2010     /*
2011      * Determine if camera device support manual lens shading map control
2012      *
2013      * @return {@code true} if manual lens shading map control is supported
2014      */
isManualLensShadingMapSupported()2015     public boolean isManualLensShadingMapSupported() {
2016         return areKeysAvailable(CaptureRequest.SHADING_MODE);
2017     }
2018 
2019     /**
2020      * Determine if camera device support manual color correction control
2021      *
2022      * @return {@code true} if manual color correction control is supported
2023      */
isColorCorrectionSupported()2024     public boolean isColorCorrectionSupported() {
2025         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
2026     }
2027 
2028     /**
2029      * Determine if camera device support manual tone mapping control
2030      *
2031      * @return {@code true} if manual tone mapping control is supported
2032      */
isManualToneMapSupported()2033     public boolean isManualToneMapSupported() {
2034         return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
2035     }
2036 
2037     /**
2038      * Determine if camera device support manual color aberration control
2039      *
2040      * @return {@code true} if manual color aberration control is supported
2041      */
isManualColorAberrationControlSupported()2042     public boolean isManualColorAberrationControlSupported() {
2043         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
2044     }
2045 
2046     /**
2047      * Determine if camera device support edge mode control
2048      *
2049      * @return {@code true} if edge mode control is supported
2050      */
isEdgeModeControlSupported()2051     public boolean isEdgeModeControlSupported() {
2052         return areKeysAvailable(CaptureRequest.EDGE_MODE);
2053     }
2054 
2055     /**
2056      * Determine if camera device support hot pixel mode control
2057      *
2058      * @return {@code true} if hot pixel mode control is supported
2059      */
isHotPixelMapModeControlSupported()2060     public boolean isHotPixelMapModeControlSupported() {
2061         return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
2062     }
2063 
2064     /**
2065      * Determine if camera device support noise reduction mode control
2066      *
2067      * @return {@code true} if noise reduction mode control is supported
2068      */
isNoiseReductionModeControlSupported()2069     public boolean isNoiseReductionModeControlSupported() {
2070         return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
2071     }
2072 
2073     /**
2074      * Get max number of output raw streams and do the basic sanity check.
2075      *
2076      * @return reported max number of raw output stream
2077      */
getMaxNumOutputStreamsRawChecked()2078     public int getMaxNumOutputStreamsRawChecked() {
2079         Integer maxNumStreams =
2080                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
2081         if (maxNumStreams == null)
2082             return 0;
2083         return maxNumStreams;
2084     }
2085 
2086     /**
2087      * Get max number of output processed streams and do the basic sanity check.
2088      *
2089      * @return reported max number of processed output stream
2090      */
getMaxNumOutputStreamsProcessedChecked()2091     public int getMaxNumOutputStreamsProcessedChecked() {
2092         Integer maxNumStreams =
2093                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
2094         if (maxNumStreams == null)
2095             return 0;
2096         return maxNumStreams;
2097     }
2098 
2099     /**
2100      * Get max number of output stalling processed streams and do the basic sanity check.
2101      *
2102      * @return reported max number of stalling processed output stream
2103      */
getMaxNumOutputStreamsProcessedStallChecked()2104     public int getMaxNumOutputStreamsProcessedStallChecked() {
2105         Integer maxNumStreams =
2106                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
2107         if (maxNumStreams == null)
2108             return 0;
2109         return maxNumStreams;
2110     }
2111 
2112     /**
2113      * Get lens facing and do the sanity check
2114      * @return lens facing, return default value (BACK) if value is unavailable.
2115      */
getLensFacingChecked()2116     public int getLensFacingChecked() {
2117         Key<Integer> key =
2118                 CameraCharacteristics.LENS_FACING;
2119         Integer facing = getValueFromKeyNonNull(key);
2120 
2121         if (facing == null) {
2122             return CameraCharacteristics.LENS_FACING_BACK;
2123         }
2124 
2125         checkTrueForKey(key, " value is out of range ",
2126                 facing >= CameraCharacteristics.LENS_FACING_FRONT &&
2127                 facing <= CameraCharacteristics.LENS_FACING_EXTERNAL);
2128         return facing;
2129     }
2130 
2131     /**
2132      * Get maxCaptureStall frames or default value (if value doesn't exist)
2133      * @return maxCaptureStall frames or default value.
2134      */
getMaxCaptureStallOrDefault()2135     public int getMaxCaptureStallOrDefault() {
2136         Key<Integer> key =
2137                 CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL;
2138         Integer value = getValueFromKeyNonNull(key);
2139 
2140         if (value == null) {
2141             return MAX_REPROCESS_MAX_CAPTURE_STALL;
2142         }
2143 
2144         checkTrueForKey(key, " value is out of range ",
2145                 value >= 0 &&
2146                 value <= MAX_REPROCESS_MAX_CAPTURE_STALL);
2147 
2148         return value;
2149     }
2150 
2151     /**
2152      * Get the scaler's cropping type (center only or freeform)
2153      * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
2154      */
getScalerCroppingTypeChecked()2155     public int getScalerCroppingTypeChecked() {
2156         Key<Integer> key =
2157                 CameraCharacteristics.SCALER_CROPPING_TYPE;
2158         Integer value = getValueFromKeyNonNull(key);
2159 
2160         if (value == null) {
2161             return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
2162         }
2163 
2164         checkTrueForKey(key, " value is out of range ",
2165                 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
2166                 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
2167 
2168         return value;
2169     }
2170 
2171     /**
2172      * Check if the constrained high speed video is supported by the camera device.
2173      * The high speed FPS ranges and sizes are sanitized in
2174      * ExtendedCameraCharacteristicsTest#testConstrainedHighSpeedCapability.
2175      *
2176      * @return true if the constrained high speed video is supported, false otherwise.
2177      */
isConstrainedHighSpeedVideoSupported()2178     public boolean isConstrainedHighSpeedVideoSupported() {
2179         List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
2180         return (availableCapabilities.contains(
2181                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO));
2182     }
2183 
2184     /**
2185      * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
2186      * supported, supported high speed fps ranges and sizes are valid).
2187      *
2188      * @return true if high speed video is supported.
2189      */
isHighSpeedVideoSupported()2190     public boolean isHighSpeedVideoSupported() {
2191         List<Integer> sceneModes =
2192                 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
2193         if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
2194             StreamConfigurationMap config =
2195                     getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
2196             if (config == null) {
2197                 return false;
2198             }
2199             Size[] availableSizes = config.getHighSpeedVideoSizes();
2200             if (availableSizes.length == 0) {
2201                 return false;
2202             }
2203 
2204             for (Size size : availableSizes) {
2205                 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
2206                 if (availableFpsRanges.length == 0) {
2207                     return false;
2208                 }
2209             }
2210 
2211             return true;
2212         } else {
2213             return false;
2214         }
2215     }
2216 
2217     /**
2218      * Check if depth output is supported, based on the depth capability
2219      */
isDepthOutputSupported()2220     public boolean isDepthOutputSupported() {
2221         return isCapabilitySupported(
2222                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
2223     }
2224 
2225     /**
2226      * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the
2227      * backwards-compatible capability
2228      */
isColorOutputSupported()2229     public boolean isColorOutputSupported() {
2230         return isCapabilitySupported(
2231                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
2232     }
2233 
2234     /**
2235      * Check if optical black regions key is supported.
2236      */
isOpticalBlackRegionSupported()2237     public boolean isOpticalBlackRegionSupported() {
2238         return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
2239     }
2240 
2241     /**
2242      * Check if the dynamic black level is supported.
2243      *
2244      * <p>
2245      * Note that: This also indicates if the white level is supported, as dynamic black and white
2246      * level must be all supported or none of them is supported.
2247      * </p>
2248      */
isDynamicBlackLevelSupported()2249     public boolean isDynamicBlackLevelSupported() {
2250         return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
2251     }
2252 
2253     /**
2254      * Check if the enable ZSL key is supported.
2255      */
isEnableZslSupported()2256     public boolean isEnableZslSupported() {
2257         return areKeysAvailable(CaptureRequest.CONTROL_ENABLE_ZSL);
2258     }
2259 
2260     /**
2261      * Get the value in index for a fixed-size array from a given key.
2262      *
2263      * <p>If the camera device is incorrectly reporting values, log a warning and return
2264      * the default value instead.</p>
2265      *
2266      * @param key Key to fetch
2267      * @param defaultValue Default value to return if camera device uses invalid values
2268      * @param name Human-readable name for the array index (logging only)
2269      * @param index Array index of the subelement
2270      * @param size Expected fixed size of the array
2271      *
2272      * @return The value reported by the camera device, or the defaultValue otherwise.
2273      */
getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, int size)2274     private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
2275             int size) {
2276         T elementValue = getArrayElementCheckRangeNonNull(
2277                 key,
2278                 index,
2279                 size);
2280 
2281         if (elementValue == null) {
2282             failKeyCheck(key,
2283                     "had no valid " + name + " value; using default of " + defaultValue);
2284             elementValue = defaultValue;
2285         }
2286 
2287         return elementValue;
2288     }
2289 
2290     /**
2291      * Fetch an array sub-element from an array value given by a key.
2292      *
2293      * <p>
2294      * Prints a warning if the sub-element was null.
2295      * </p>
2296      *
2297      * <p>Use for variable-size arrays since this does not check the array size.</p>
2298      *
2299      * @param key Metadata key to look up
2300      * @param element A non-negative index value.
2301      * @return The array sub-element, or null if the checking failed.
2302      */
getArrayElementNonNull(Key<?> key, int element)2303     private <T> T getArrayElementNonNull(Key<?> key, int element) {
2304         return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
2305     }
2306 
2307     /**
2308      * Fetch an array sub-element from an array value given by a key.
2309      *
2310      * <p>
2311      * Prints a warning if the array size does not match the size, or if the sub-element was null.
2312      * </p>
2313      *
2314      * @param key Metadata key to look up
2315      * @param element The index in [0,size)
2316      * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
2317      * @return The array sub-element, or null if the checking failed.
2318      */
getArrayElementCheckRangeNonNull(Key<?> key, int element, int size)2319     private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
2320         Object array = getValueFromKeyNonNull(key);
2321 
2322         if (array == null) {
2323             // Warning already printed
2324             return null;
2325         }
2326 
2327         if (size != IGNORE_SIZE_CHECK) {
2328             int actualLength = Array.getLength(array);
2329             if (actualLength != size) {
2330                 failKeyCheck(key,
2331                         String.format("had the wrong number of elements (%d), expected (%d)",
2332                                 actualLength, size));
2333                 return null;
2334             }
2335         }
2336 
2337         @SuppressWarnings("unchecked")
2338         T val = (T) Array.get(array, element);
2339 
2340         if (val == null) {
2341             failKeyCheck(key, "had a null element at index" + element);
2342             return null;
2343         }
2344 
2345         return val;
2346     }
2347 
2348     /**
2349      * Gets the key, logging warnings for null values.
2350      */
getValueFromKeyNonNull(Key<T> key)2351     public <T> T getValueFromKeyNonNull(Key<T> key) {
2352         if (key == null) {
2353             throw new IllegalArgumentException("key was null");
2354         }
2355 
2356         T value = mCharacteristics.get(key);
2357 
2358         if (value == null) {
2359             failKeyCheck(key, "was null");
2360         }
2361 
2362         return value;
2363     }
2364 
checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max)2365     private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
2366         for (int value : array) {
2367             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
2368                     value <= max && value >= min);
2369         }
2370     }
2371 
checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max)2372     private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
2373         for (byte value : array) {
2374             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
2375                     value <= max && value >= min);
2376         }
2377     }
2378 
2379     /**
2380      * Check the uniqueness of the values in a list.
2381      *
2382      * @param key The key to be checked
2383      * @param list The list contains the value of the key
2384      */
checkElementDistinct(Key<U> key, List<T> list)2385     private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
2386         // Each size must be distinct.
2387         Set<T> sizeSet = new HashSet<T>(list);
2388         checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
2389     }
2390 
checkTrueForKey(Key<T> key, String message, boolean condition)2391     private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
2392         if (!condition) {
2393             failKeyCheck(key, message);
2394         }
2395     }
2396 
2397     /* Helper function to check if the coupled modes are either all present or all non-present */
containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes)2398     private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) {
2399         if (observedModes.containsAll(coupledModes)) {
2400             return true;
2401         }
2402         for (T mode : coupledModes) {
2403             if (observedModes.contains(mode)) {
2404                 return false;
2405             }
2406         }
2407         return true;
2408     }
2409 
failKeyCheck(Key<T> key, String message)2410     private <T> void failKeyCheck(Key<T> key, String message) {
2411         // TODO: Consider only warning once per key/message combination if it's too spammy.
2412         // TODO: Consider offering other options such as throwing an assertion exception
2413         String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
2414         switch (mLevel) {
2415             case WARN:
2416                 Log.w(TAG, failureCause);
2417                 break;
2418             case COLLECT:
2419                 mCollector.addMessage(failureCause);
2420                 break;
2421             case ASSERT:
2422                 Assert.fail(failureCause);
2423             default:
2424                 throw new UnsupportedOperationException("Unhandled level " + mLevel);
2425         }
2426     }
2427 }
2428