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