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