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 /**
     45  * Helpers to get common static info out of the camera.
     46  *
     47  * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p>
     48  *
     49  * <p>Attempt to be durable against the camera device having bad or missing metadata
     50  * by providing reasonable defaults and logging warnings when that happens.</p>
     51  */
     52 public class StaticMetadata {
     53 
     54     private static final String TAG = "StaticMetadata";
     55     private static final int IGNORE_SIZE_CHECK = -1;
     56 
     57     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
     58     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
     59     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
     60     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 1600;
     61     private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
     62     private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
     63     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
     64     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
     65     private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
     66     private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
     67 
     68     // TODO: Consider making this work across any metadata object, not just camera characteristics
     69     private final CameraCharacteristics mCharacteristics;
     70     private final CheckLevel mLevel;
     71     private final CameraErrorCollector mCollector;
     72 
     73     public enum CheckLevel {
     74         /** Only log warnings for metadata check failures. Execution continues. */
     75         WARN,
     76         /**
     77          * Use ErrorCollector to collect the metadata check failures, Execution
     78          * continues.
     79          */
     80         COLLECT,
     81         /** Assert the metadata check failures. Execution aborts. */
     82         ASSERT
     83     }
     84 
     85     /**
     86      * Construct a new StaticMetadata object.
     87      *
     88      *<p> Default constructor, only log warnings for the static metadata check failures</p>
     89      *
     90      * @param characteristics static info for a camera
     91      * @throws IllegalArgumentException if characteristics was null
     92      */
     93     public StaticMetadata(CameraCharacteristics characteristics) {
     94         this(characteristics, CheckLevel.WARN, /*collector*/null);
     95     }
     96 
     97     /**
     98      * Construct a new StaticMetadata object with {@link CameraErrorCollector}.
     99      * <p>
    100      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
    101      * ignored, otherwise, it will be used to log the check failures.
    102      * </p>
    103      *
    104      * @param characteristics static info for a camera
    105      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
    106      * @throws IllegalArgumentException if characteristics or collector was null.
    107      */
    108     public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) {
    109         this(characteristics, CheckLevel.COLLECT, collector);
    110     }
    111 
    112     /**
    113      * Construct a new StaticMetadata object with {@link CheckLevel} and
    114      * {@link CameraErrorCollector}.
    115      * <p>
    116      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
    117      * ignored, otherwise, it will be used to log the check failures.
    118      * </p>
    119      *
    120      * @param characteristics static info for a camera
    121      * @param level The {@link CheckLevel} of this StaticMetadata
    122      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
    123      * @throws IllegalArgumentException if characteristics was null or level was
    124      *         {@link CheckLevel.COLLECT} but collector was null.
    125      */
    126     public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level,
    127             CameraErrorCollector collector) {
    128         if (characteristics == null) {
    129             throw new IllegalArgumentException("characteristics was null");
    130         }
    131         if (level == CheckLevel.COLLECT && collector == null) {
    132             throw new IllegalArgumentException("collector must valid when COLLECT level is set");
    133         }
    134 
    135         mCharacteristics = characteristics;
    136         mLevel = level;
    137         mCollector = collector;
    138     }
    139 
    140     /**
    141      * Get the CameraCharacteristics associated with this StaticMetadata.
    142      *
    143      * @return A non-null CameraCharacteristics object
    144      */
    145     public CameraCharacteristics getCharacteristics() {
    146         return mCharacteristics;
    147     }
    148 
    149     /**
    150      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
    151      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}.
    152      *
    153      * <p>If the camera device is not reporting the hardwareLevel, this
    154      * will cause the test to fail.</p>
    155      *
    156      * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
    157      */
    158     public boolean isHardwareLevelFull() {
    159         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
    160     }
    161 
    162     /**
    163      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
    164      * Return the supported hardware level of the device, or fail if no value is reported.
    165      *
    166      * @return the supported hardware level as a constant defined for
    167      *      {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
    168      */
    169     public int getHardwareLevelChecked() {
    170         Integer hwLevel = getValueFromKeyNonNull(
    171                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    172         if (hwLevel == null) {
    173             Assert.fail("No supported hardware level reported.");
    174         }
    175         return hwLevel;
    176     }
    177 
    178     /**
    179      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
    180      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}.
    181      *
    182      * <p>If the camera device is not reporting the hardwareLevel, this
    183      * will cause the test to fail.</p>
    184      *
    185      * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
    186      */
    187     public boolean isHardwareLevelLegacy() {
    188         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
    189     }
    190 
    191     /**
    192      * Whether or not the per frame control is supported by the camera device.
    193      *
    194      * @return {@code true} if per frame control is supported, {@code false} otherwise.
    195      */
    196     public boolean isPerFrameControlSupported() {
    197         return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
    198     }
    199 
    200     /**
    201      * Get the maximum number of frames to wait for a request settings being applied
    202      *
    203      * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency
    204      *         CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control
    205      *         a positive int otherwise
    206      */
    207     public int getSyncMaxLatency() {
    208         Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY);
    209         if (value == null) {
    210             return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN;
    211         }
    212         return value;
    213     }
    214 
    215     /**
    216      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
    217      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
    218      *
    219      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
    220      * will always return {@code true}.</p>
    221      *
    222      * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise.
    223      */
    224     public boolean isHardwareLevelLimited() {
    225         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
    226     }
    227 
    228     /**
    229      * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel}
    230      * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
    231      *
    232      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
    233      * will always return {@code false}.</p>
    234      *
    235      * @return
    236      *          {@code true} if the device is {@code LIMITED} or {@code FULL},
    237      *          {@code false} otherwise (i.e. LEGACY).
    238      */
    239     public boolean isHardwareLevelLimitedOrBetter() {
    240         Integer hwLevel = getValueFromKeyNonNull(
    241                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    242 
    243         if (hwLevel == null) {
    244             return false;
    245         }
    246 
    247         // Normal. Device could be limited.
    248         int hwLevelInt = hwLevel;
    249         return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
    250                 hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
    251     }
    252 
    253     /**
    254      * Get the maximum number of partial result a request can expect
    255      *
    256      * @return 1 if partial result is not supported.
    257      *         a integer value larger than 1 if partial result is supported.
    258      */
    259     public int getPartialResultCount() {
    260         Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
    261         if (value == null) {
    262             // Optional key. Default value is 1 if key is missing.
    263             return 1;
    264         }
    265         return value;
    266     }
    267 
    268     /**
    269      * Get the exposure time value and clamp to the range if needed.
    270      *
    271      * @param exposure Input exposure time value to check.
    272      * @return Exposure value in the legal range.
    273      */
    274     public long getExposureClampToRange(long exposure) {
    275         long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE);
    276         long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE);
    277         if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) {
    278             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
    279                     String.format(
    280                     "Min value %d is too large, set to maximal legal value %d",
    281                     minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST));
    282             minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST;
    283         }
    284         if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) {
    285             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
    286                     String.format(
    287                     "Max value %d is too small, set to minimal legal value %d",
    288                     maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST));
    289             maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST;
    290         }
    291 
    292         return Math.max(minExposure, Math.min(maxExposure, exposure));
    293     }
    294 
    295     /**
    296      * Check if the camera device support focuser.
    297      *
    298      * @return true if camera device support focuser, false otherwise.
    299      */
    300     public boolean hasFocuser() {
    301         if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
    302             // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
    303             return (getMinimumFocusDistanceChecked() > 0);
    304         } else {
    305             // Check available AF modes
    306             int[] availableAfModes = mCharacteristics.get(
    307                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
    308 
    309             if (availableAfModes == null) {
    310                 return false;
    311             }
    312 
    313             // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
    314             boolean hasFocuser = false;
    315             loop: for (int mode : availableAfModes) {
    316                 switch (mode) {
    317                     case CameraMetadata.CONTROL_AF_MODE_AUTO:
    318                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
    319                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
    320                     case CameraMetadata.CONTROL_AF_MODE_MACRO:
    321                         hasFocuser = true;
    322                         break loop;
    323                 }
    324             }
    325 
    326             return hasFocuser;
    327         }
    328     }
    329 
    330     /**
    331      * Check if the camera device has flash unit.
    332      * @return true if flash unit is available, false otherwise.
    333      */
    334     public boolean hasFlash() {
    335         return getFlashInfoChecked();
    336     }
    337 
    338     /**
    339      * Get minimum focus distance.
    340      *
    341      * @return minimum focus distance, 0 if minimum focus distance is invalid.
    342      */
    343     public float getMinimumFocusDistanceChecked() {
    344         Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE;
    345         Float minFocusDistance;
    346 
    347         /**
    348          * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable
    349          *   devices; optional for all other devices.
    350          */
    351         if (isHardwareLevelFull() || isCapabilitySupported(
    352                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
    353             minFocusDistance = getValueFromKeyNonNull(key);
    354         } else {
    355             minFocusDistance = mCharacteristics.get(key);
    356         }
    357 
    358         if (minFocusDistance == null) {
    359             return 0.0f;
    360         }
    361 
    362         checkTrueForKey(key, " minFocusDistance value shouldn't be negative",
    363                 minFocusDistance >= 0);
    364         if (minFocusDistance < 0) {
    365             minFocusDistance = 0.0f;
    366         }
    367 
    368         return minFocusDistance;
    369     }
    370 
    371     /**
    372      * Get focusDistanceCalibration.
    373      *
    374      * @return focusDistanceCalibration, UNCALIBRATED if value is invalid.
    375      */
    376     public int getFocusDistanceCalibrationChecked() {
    377         Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
    378         Integer calibration = getValueFromKeyNonNull(key);
    379 
    380         if (calibration == null) {
    381             return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
    382         }
    383 
    384         checkTrueForKey(key, " value is out of range" ,
    385                 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED &&
    386                 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED);
    387 
    388         return calibration;
    389     }
    390 
    391     /**
    392      * Get max AE regions and do sanity check.
    393      *
    394      * @return AE max regions supported by the camera device
    395      */
    396     public int getAeMaxRegionsChecked() {
    397         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
    398         if (regionCount == null) {
    399             return 0;
    400         }
    401         return regionCount;
    402     }
    403 
    404     /**
    405      * Get max AWB regions and do sanity check.
    406      *
    407      * @return AWB max regions supported by the camera device
    408      */
    409     public int getAwbMaxRegionsChecked() {
    410         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
    411         if (regionCount == null) {
    412             return 0;
    413         }
    414         return regionCount;
    415     }
    416 
    417     /**
    418      * Get max AF regions and do sanity check.
    419      *
    420      * @return AF max regions supported by the camera device
    421      */
    422     public int getAfMaxRegionsChecked() {
    423         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
    424         if (regionCount == null) {
    425             return 0;
    426         }
    427         return regionCount;
    428     }
    429     /**
    430      * Get the available anti-banding modes.
    431      *
    432      * @return The array contains available anti-banding modes.
    433      */
    434     public int[] getAeAvailableAntiBandingModesChecked() {
    435         Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
    436         int[] modes = getValueFromKeyNonNull(key);
    437 
    438         boolean foundAuto = false;
    439         for (int mode : modes) {
    440             checkTrueForKey(key, "mode value " + mode + " is out if range",
    441                     mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF ||
    442                     mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
    443             if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) {
    444                 foundAuto = true;
    445                 return modes;
    446             }
    447         }
    448         // Must contain AUTO mode.
    449         checkTrueForKey(key, "AUTO mode is missing", foundAuto);
    450 
    451         return modes;
    452     }
    453 
    454     /**
    455      * Check if the antibanding OFF mode is supported.
    456      *
    457      * @return true if antibanding OFF mode is supported, false otherwise.
    458      */
    459     public boolean isAntiBandingOffModeSupported() {
    460         List<Integer> antiBandingModes =
    461                 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
    462 
    463         return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
    464     }
    465 
    466     public Boolean getFlashInfoChecked() {
    467         Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
    468         Boolean hasFlash = getValueFromKeyNonNull(key);
    469 
    470         // In case the failOnKey only gives warning.
    471         if (hasFlash == null) {
    472             return false;
    473         }
    474 
    475         return hasFlash;
    476     }
    477 
    478     public int[] getAvailableTestPatternModesChecked() {
    479         Key<int[]> key =
    480                 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
    481         int[] modes = getValueFromKeyNonNull(key);
    482 
    483         if (modes == null) {
    484             return new int[0];
    485         }
    486 
    487         int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF;
    488         Integer[] boxedModes = CameraTestUtils.toObject(modes);
    489         checkTrueForKey(key, " value must contain OFF mode",
    490                 Arrays.asList(boxedModes).contains(expectValue));
    491 
    492         return modes;
    493     }
    494 
    495     /**
    496      * Get available thumbnail sizes and do the sanity check.
    497      *
    498      * @return The array of available thumbnail sizes
    499      */
    500     public Size[] getAvailableThumbnailSizesChecked() {
    501         Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES;
    502         Size[] sizes = getValueFromKeyNonNull(key);
    503         final List<Size> sizeList = Arrays.asList(sizes);
    504 
    505         // Size must contain (0, 0).
    506         checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0)));
    507 
    508         // Each size must be distinct.
    509         checkElementDistinct(key, sizeList);
    510 
    511         // Must be sorted in ascending order by area, by width if areas are same.
    512         List<Size> orderedSizes =
    513                 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true);
    514         checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString()
    515                 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList));
    516 
    517         // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations
    518         // implementation see b/12958122.
    519 
    520         return sizes;
    521     }
    522 
    523     /**
    524      * Get available focal lengths and do the sanity check.
    525      *
    526      * @return The array of available focal lengths
    527      */
    528     public float[] getAvailableFocalLengthsChecked() {
    529         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
    530         float[] focalLengths = getValueFromKeyNonNull(key);
    531 
    532         checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1);
    533 
    534         for (int i = 0; i < focalLengths.length; i++) {
    535             checkTrueForKey(key,
    536                     String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]),
    537                     focalLengths[i] > 0);
    538         }
    539         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths)));
    540 
    541         return focalLengths;
    542     }
    543 
    544     /**
    545      * Get available apertures and do the sanity check.
    546      *
    547      * @return The non-null array of available apertures
    548      */
    549     public float[] getAvailableAperturesChecked() {
    550         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES;
    551         float[] apertures = getValueFromKeyNonNull(key);
    552 
    553         checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1);
    554 
    555         for (int i = 0; i < apertures.length; i++) {
    556             checkTrueForKey(key,
    557                     String.format("apertures[%d] %f should be positive.", i, apertures[i]),
    558                     apertures[i] > 0);
    559         }
    560         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures)));
    561 
    562         return apertures;
    563     }
    564 
    565     /**
    566      * Get and check the available hot pixel map modes.
    567      *
    568      * @return the available hot pixel map modes
    569      */
    570     public int[] getAvailableHotPixelModesChecked() {
    571         Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
    572         int[] modes = getValueFromKeyNonNull(key);
    573 
    574         if (modes == null) {
    575             return new int[0];
    576         }
    577 
    578         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
    579         if (isHardwareLevelFull()) {
    580             checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
    581                     modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
    582         }
    583         checkElementDistinct(key, modeList);
    584         checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
    585                 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
    586 
    587         return modes;
    588     }
    589 
    590     /**
    591      * Get and check available face detection modes.
    592      *
    593      * @return The non-null array of available face detection modes
    594      */
    595     public int[] getAvailableFaceDetectModesChecked() {
    596         Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
    597         int[] modes = getValueFromKeyNonNull(key);
    598 
    599         if (modes == null) {
    600             return new int[0];
    601         }
    602 
    603         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
    604         checkTrueForKey(key, "Array should contain OFF mode",
    605                 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF));
    606         checkElementDistinct(key, modeList);
    607         checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF,
    608                 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
    609 
    610         return modes;
    611     }
    612 
    613     /**
    614      * Get and check max face detected count.
    615      *
    616      * @return max number of faces that can be detected
    617      */
    618     public int getMaxFaceCountChecked() {
    619         Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT;
    620         Integer count = getValueFromKeyNonNull(key);
    621 
    622         if (count == null) {
    623             return 0;
    624         }
    625 
    626         List<Integer> faceDetectModes =
    627                 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked()));
    628         if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) &&
    629                 faceDetectModes.size() == 1) {
    630             checkTrueForKey(key, " value must be 0 if only OFF mode is supported in "
    631                     + "availableFaceDetectionModes", count == 0);
    632         } else {
    633             int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST;
    634 
    635             // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces.
    636             if (isHardwareLevelLegacy()) {
    637                 maxFaceCountAtLeast = 1;
    638             }
    639             checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE"
    640                     + "or FULL is also supported in availableFaceDetectionModes",
    641                     count >= maxFaceCountAtLeast);
    642         }
    643 
    644         return count;
    645     }
    646 
    647     /**
    648      * Get and check the available tone map modes.
    649      *
    650      * @return the available tone map modes
    651      */
    652     public int[] getAvailableToneMapModesChecked() {
    653         Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES;
    654         int[] modes = getValueFromKeyNonNull(key);
    655 
    656         if (modes == null) {
    657             return new int[0];
    658         }
    659 
    660         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
    661         checkTrueForKey(key, " Camera devices must always support FAST mode",
    662                 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
    663         if (isHardwareLevelFull()) {
    664             checkTrueForKey(key, "Full-capability camera devices must support"
    665                     + "CONTRAST_CURVE mode",
    666                     modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) &&
    667                     modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
    668         }
    669         checkElementDistinct(key, modeList);
    670         checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
    671                 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY);
    672 
    673         return modes;
    674     }
    675 
    676     /**
    677      * Get and check max tonemap curve point.
    678      *
    679      * @return Max tonemap curve points.
    680      */
    681     public int getMaxTonemapCurvePointChecked() {
    682         Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS;
    683         Integer count = getValueFromKeyNonNull(key);
    684 
    685         if (count == null) {
    686             return 0;
    687         }
    688 
    689         List<Integer> modeList =
    690                 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked()));
    691         if (modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE)) {
    692             checkTrueForKey(key, "Full-capability camera device must support maxCurvePoints "
    693                     + ">= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST,
    694                     count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST);
    695         }
    696 
    697         return count;
    698     }
    699 
    700     /**
    701      * Get and check pixel array size.
    702      */
    703     public Size getPixelArraySizeChecked() {
    704         Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE;
    705         Size pixelArray = getValueFromKeyNonNull(key);
    706         if (pixelArray == null) {
    707             return new Size(0, 0);
    708         }
    709 
    710         return pixelArray;
    711     }
    712 
    713     /**
    714      * Get and check active array size.
    715      */
    716     public Rect getActiveArraySizeChecked() {
    717         Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE;
    718         Rect activeArray = getValueFromKeyNonNull(key);
    719 
    720         if (activeArray == null) {
    721             return new Rect(0, 0, 0, 0);
    722         }
    723 
    724         Size pixelArraySize = getPixelArraySizeChecked();
    725         checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
    726         checkTrueForKey(key, "values width/height are invalid",
    727                 activeArray.width() <= pixelArraySize.getWidth() &&
    728                 activeArray.height() <= pixelArraySize.getHeight());
    729 
    730         return activeArray;
    731     }
    732 
    733     /**
    734      * Get the sensitivity value and clamp to the range if needed.
    735      *
    736      * @param sensitivity Input sensitivity value to check.
    737      * @return Sensitivity value in legal range.
    738      */
    739     public int getSensitivityClampToRange(int sensitivity) {
    740         int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE);
    741         int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE);
    742         if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) {
    743             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
    744                     String.format(
    745                     "Min value %d is too large, set to maximal legal value %d",
    746                     minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST));
    747             minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST;
    748         }
    749         if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) {
    750             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
    751                     String.format(
    752                     "Max value %d is too small, set to minimal legal value %d",
    753                     maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST));
    754             maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST;
    755         }
    756 
    757         return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity));
    758     }
    759 
    760     /**
    761      * Get maxAnalogSensitivity for a camera device.
    762      * <p>
    763      * This is only available for FULL capability device, return 0 if it is unavailable.
    764      * </p>
    765      *
    766      * @return maxAnalogSensitivity, 0 if it is not available.
    767      */
    768     public int getMaxAnalogSensitivityChecked() {
    769 
    770         Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
    771         Integer maxAnalogsensitivity = mCharacteristics.get(key);
    772         if (maxAnalogsensitivity == null) {
    773             if (isHardwareLevelFull()) {
    774                 Assert.fail("Full device should report max analog sensitivity");
    775             }
    776             return 0;
    777         }
    778 
    779         int minSensitivity = getSensitivityMinimumOrDefault();
    780         int maxSensitivity = getSensitivityMaximumOrDefault();
    781         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
    782                 + " should be no larger than max sensitivity " + maxSensitivity,
    783                 maxAnalogsensitivity <= maxSensitivity);
    784         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
    785                 + " should be larger than min sensitivity " + maxSensitivity,
    786                 maxAnalogsensitivity > minSensitivity);
    787 
    788         return maxAnalogsensitivity;
    789     }
    790 
    791     /**
    792      * Get hyperfocalDistance and do the sanity check.
    793      * <p>
    794      * Note that, this tag is optional, will return -1 if this tag is not
    795      * available.
    796      * </p>
    797      *
    798      * @return hyperfocalDistance of this device, -1 if this tag is not available.
    799      */
    800     public float getHyperfocalDistanceChecked() {
    801         Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
    802         Float hyperfocalDistance = getValueFromKeyNonNull(key);
    803         if (hyperfocalDistance == null) {
    804             return -1;
    805         }
    806 
    807         if (hasFocuser()) {
    808             float minFocusDistance = getMinimumFocusDistanceChecked();
    809             checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of"
    810                     + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f,
    811                     minFocusDistance),
    812                     hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance);
    813         }
    814 
    815         return hyperfocalDistance;
    816     }
    817 
    818     /**
    819      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
    820      *
    821      * <p>If the camera is incorrectly reporting values, log a warning and return
    822      * the default value instead, which is the largest minimum value required to be supported
    823      * by all camera devices.</p>
    824      *
    825      * @return The value reported by the camera device or the defaultValue otherwise.
    826      */
    827     public int getSensitivityMinimumOrDefault() {
    828         return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST);
    829     }
    830 
    831     /**
    832      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
    833      *
    834      * <p>If the camera is incorrectly reporting values, log a warning and return
    835      * the default value instead.</p>
    836      *
    837      * @param defaultValue Value to return if no legal value is available
    838      * @return The value reported by the camera device or the defaultValue otherwise.
    839      */
    840     public int getSensitivityMinimumOrDefault(int defaultValue) {
    841         Range<Integer> range = getValueFromKeyNonNull(
    842                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
    843         if (range == null) {
    844             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
    845                     "had no valid minimum value; using default of " + defaultValue);
    846             return defaultValue;
    847         }
    848         return range.getLower();
    849     }
    850 
    851     /**
    852      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
    853      *
    854      * <p>If the camera is incorrectly reporting values, log a warning and return
    855      * the default value instead, which is the smallest maximum value required to be supported
    856      * by all camera devices.</p>
    857      *
    858      * @return The value reported by the camera device or the defaultValue otherwise.
    859      */
    860     public int getSensitivityMaximumOrDefault() {
    861         return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST);
    862     }
    863 
    864     /**
    865      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
    866      *
    867      * <p>If the camera is incorrectly reporting values, log a warning and return
    868      * the default value instead.</p>
    869      *
    870      * @param defaultValue Value to return if no legal value is available
    871      * @return The value reported by the camera device or the defaultValue otherwise.
    872      */
    873     public int getSensitivityMaximumOrDefault(int defaultValue) {
    874         Range<Integer> range = getValueFromKeyNonNull(
    875                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
    876         if (range == null) {
    877             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
    878                     "had no valid maximum value; using default of " + defaultValue);
    879             return defaultValue;
    880         }
    881         return range.getUpper();
    882     }
    883 
    884     /**
    885      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
    886      *
    887      * <p>If the camera is incorrectly reporting values, log a warning and return
    888      * the default value instead.</p>
    889      *
    890      * @param defaultValue Value to return if no legal value is available
    891      * @return The value reported by the camera device or the defaultValue otherwise.
    892      */
    893     public long getExposureMinimumOrDefault(long defaultValue) {
    894         Range<Long> range = getValueFromKeyNonNull(
    895                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
    896         if (range == null) {
    897             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
    898                     "had no valid minimum value; using default of " + defaultValue);
    899             return defaultValue;
    900         }
    901         return range.getLower();
    902     }
    903 
    904     /**
    905      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
    906      *
    907      * <p>If the camera is incorrectly reporting values, log a warning and return
    908      * the default value instead, which is the largest minimum value required to be supported
    909      * by all camera devices.</p>
    910      *
    911      * @return The value reported by the camera device or the defaultValue otherwise.
    912      */
    913     public long getExposureMinimumOrDefault() {
    914         return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST);
    915     }
    916 
    917     /**
    918      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
    919      *
    920      * <p>If the camera is incorrectly reporting values, log a warning and return
    921      * the default value instead.</p>
    922      *
    923      * @param defaultValue Value to return if no legal value is available
    924      * @return The value reported by the camera device or the defaultValue otherwise.
    925      */
    926     public long getExposureMaximumOrDefault(long defaultValue) {
    927         Range<Long> range = getValueFromKeyNonNull(
    928                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
    929         if (range == null) {
    930             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
    931                     "had no valid maximum value; using default of " + defaultValue);
    932             return defaultValue;
    933         }
    934         return range.getUpper();
    935     }
    936 
    937     /**
    938      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
    939      *
    940      * <p>If the camera is incorrectly reporting values, log a warning and return
    941      * the default value instead, which is the smallest maximum value required to be supported
    942      * by all camera devices.</p>
    943      *
    944      * @return The value reported by the camera device or the defaultValue otherwise.
    945      */
    946     public long getExposureMaximumOrDefault() {
    947         return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST);
    948     }
    949 
    950     /**
    951      * Get aeAvailableModes and do the sanity check.
    952      *
    953      * <p>Depending on the check level this class has, for WAR or COLLECT levels,
    954      * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
    955      * have to abort the execution even the aeMode list is invalid.</p>
    956      * @return AE available modes
    957      */
    958     public int[] getAeAvailableModesChecked() {
    959         Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
    960         int[] modes = getValueFromKeyNonNull(modesKey);
    961         if (modes == null) {
    962             modes = new int[0];
    963         }
    964         List<Integer> modeList = new ArrayList<Integer>();
    965         for (int mode : modes) {
    966             modeList.add(mode);
    967         }
    968         checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
    969 
    970         // All camera device must support ON
    971         checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
    972                 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
    973 
    974         // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
    975         Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
    976         Boolean hasFlash = getValueFromKeyNonNull(flashKey);
    977         if (hasFlash == null) {
    978             hasFlash = false;
    979         }
    980         if (hasFlash) {
    981             boolean flashModeConsistentWithFlash =
    982                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
    983                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
    984             checkTrueForKey(modesKey,
    985                     "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and  when flash is" +
    986                     "available", flashModeConsistentWithFlash);
    987         } else {
    988             boolean flashModeConsistentWithoutFlash =
    989                     !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
    990                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
    991                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
    992             checkTrueForKey(modesKey,
    993                     "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
    994                     "ON_AUTO_FLASH_REDEYE when flash is unavailable",
    995                     flashModeConsistentWithoutFlash);
    996         }
    997 
    998         // FULL mode camera devices always support OFF mode.
    999         boolean condition =
   1000                 !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
   1001         checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
   1002 
   1003         // Boundary check.
   1004         for (int mode : modes) {
   1005             checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
   1006                     mode >= CameraMetadata.CONTROL_AE_MODE_OFF
   1007                     && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
   1008         }
   1009 
   1010         return modes;
   1011     }
   1012 
   1013     /**
   1014      * Get available AWB modes and do the sanity check.
   1015      *
   1016      * @return array that contains available AWB modes, empty array if awbAvailableModes is
   1017      * unavailable.
   1018      */
   1019     public int[] getAwbAvailableModesChecked() {
   1020         Key<int[]> key =
   1021                 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
   1022         int[] awbModes = getValueFromKeyNonNull(key);
   1023 
   1024         if (awbModes == null) {
   1025             return new int[0];
   1026         }
   1027 
   1028         List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
   1029         checkTrueForKey(key, " All camera devices must support AUTO mode",
   1030                 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
   1031         if (isHardwareLevelFull()) {
   1032             checkTrueForKey(key, " Full capability camera devices must support OFF mode",
   1033                     modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
   1034         }
   1035 
   1036         return awbModes;
   1037     }
   1038 
   1039     /**
   1040      * Get available AF modes and do the sanity check.
   1041      *
   1042      * @return array that contains available AF modes, empty array if afAvailableModes is
   1043      * unavailable.
   1044      */
   1045     public int[] getAfAvailableModesChecked() {
   1046         Key<int[]> key =
   1047                 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
   1048         int[] afModes = getValueFromKeyNonNull(key);
   1049 
   1050         if (afModes == null) {
   1051             return new int[0];
   1052         }
   1053 
   1054         List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes));
   1055         if (isHardwareLevelLimitedOrBetter()) {
   1056             // Some LEGACY mode devices do not support AF OFF
   1057             checkTrueForKey(key, " All camera devices must support OFF mode",
   1058                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
   1059         }
   1060         if (hasFocuser()) {
   1061             checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
   1062                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
   1063         }
   1064 
   1065         return afModes;
   1066     }
   1067 
   1068     /**
   1069      * Get supported raw output sizes and do the check.
   1070      *
   1071      * @return Empty size array if raw output is not supported
   1072      */
   1073     public Size[] getRawOutputSizesChecked() {
   1074         return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
   1075                 StreamDirection.Output);
   1076     }
   1077 
   1078     /**
   1079      * Get supported jpeg output sizes and do the check.
   1080      *
   1081      * @return Empty size array if jpeg output is not supported
   1082      */
   1083     public Size[] getJpegOutputSizeChecked() {
   1084         return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
   1085                 StreamDirection.Output);
   1086     }
   1087 
   1088     /**
   1089      * Used to determine the stream direction for various helpers that look up
   1090      * format or size information.
   1091      */
   1092     public enum StreamDirection {
   1093         /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
   1094         Output,
   1095         /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
   1096         Input
   1097     }
   1098 
   1099     /**
   1100      * Get available sizes for given user-defined format.
   1101      *
   1102      * <p><strong>Does not</strong> work with implementation-defined format.</p>
   1103      *
   1104      * @param format The format for the requested size array.
   1105      * @param direction The stream direction, input or output.
   1106      * @return The sizes of the given format, empty array if no available size is found.
   1107      */
   1108     public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
   1109         Key<StreamConfigurationMap> key =
   1110                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
   1111         StreamConfigurationMap config = getValueFromKeyNonNull(key);
   1112 
   1113         if (config == null) {
   1114             return new Size[0];
   1115         }
   1116 
   1117         android.util.Size[] utilSizes;
   1118 
   1119         switch (direction) {
   1120             case Output:
   1121                 utilSizes = config.getOutputSizes(format);
   1122                 break;
   1123             case Input:
   1124                 utilSizes = null;
   1125                 break;
   1126             default:
   1127                 throw new IllegalArgumentException("direction must be output or input");
   1128         }
   1129 
   1130         // TODO: Get rid of android.util.Size
   1131         if (utilSizes == null) {
   1132             Log.i(TAG, "This camera doesn't support format " + format + " for " + direction);
   1133             return new Size[0];
   1134         }
   1135 
   1136         Size[] sizes = new Size[utilSizes.length];
   1137         for (int i = 0; i < utilSizes.length; ++i) {
   1138             sizes[i] = new Size(utilSizes[i].getWidth(), utilSizes[i].getHeight());
   1139         }
   1140 
   1141         return sizes;
   1142     }
   1143 
   1144     /**
   1145      * Get available AE target fps ranges.
   1146      *
   1147      * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
   1148      */
   1149     @SuppressWarnings("raw")
   1150     public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
   1151         Key<Range<Integer>[]> key =
   1152                 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
   1153         Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
   1154 
   1155         if (fpsRanges == null) {
   1156             return new Range[0];
   1157         }
   1158 
   1159         // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
   1160         // in case the above check fails.
   1161         int fpsRangeLength = fpsRanges.length;
   1162         int minFps, maxFps;
   1163         long maxFrameDuration = getMaxFrameDurationChecked();
   1164         for (int i = 0; i < fpsRangeLength; i += 1) {
   1165             minFps = fpsRanges[i].getLower();
   1166             maxFps = fpsRanges[i].getUpper();
   1167             checkTrueForKey(key, " min fps must be no larger than max fps!",
   1168                     minFps > 0 && maxFps >= minFps);
   1169             long maxDuration = (long) (1e9 / minFps);
   1170             checkTrueForKey(key, String.format(
   1171                     " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
   1172                     maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
   1173         }
   1174 
   1175         return fpsRanges;
   1176     }
   1177 
   1178     /**
   1179      * Get max frame duration.
   1180      *
   1181      * @return 0 if maxFrameDuration is null
   1182      */
   1183     public long getMaxFrameDurationChecked() {
   1184         Key<Long> key =
   1185                 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
   1186         Long maxDuration = getValueFromKeyNonNull(key);
   1187 
   1188         if (maxDuration == null) {
   1189             return 0;
   1190         }
   1191 
   1192         return maxDuration;
   1193     }
   1194 
   1195     /**
   1196      * Get available minimal frame durations for a given user-defined format.
   1197      *
   1198      * <p><strong>Does not</strong> work with implementation-defined format.</p>
   1199      *
   1200      * @param format One of the format from {@link ImageFormat}.
   1201      * @return HashMap of minimal frame durations for different sizes, empty HashMap
   1202      *         if availableMinFrameDurations is null.
   1203      */
   1204     public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
   1205 
   1206         HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
   1207 
   1208         Key<StreamConfigurationMap> key =
   1209                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
   1210         StreamConfigurationMap config = getValueFromKeyNonNull(key);
   1211 
   1212         if (config == null) {
   1213             return minDurationMap;
   1214         }
   1215 
   1216         for (android.util.Size size : config.getOutputSizes(format)) {
   1217             long minFrameDuration = config.getOutputMinFrameDuration(format, size);
   1218 
   1219             if (minFrameDuration != 0) {
   1220                 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
   1221             }
   1222         }
   1223 
   1224         return minDurationMap;
   1225     }
   1226 
   1227     public int[] getAvailableEdgeModesChecked() {
   1228         Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
   1229         int[] edgeModes = getValueFromKeyNonNull(key);
   1230 
   1231         if (edgeModes == null) {
   1232             return new int[0];
   1233         }
   1234 
   1235         // Full device should always include OFF and FAST
   1236         if (isHardwareLevelFull()) {
   1237             List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
   1238             checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
   1239                     modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
   1240                     modeList.contains(CameraMetadata.EDGE_MODE_FAST));
   1241         }
   1242 
   1243         return edgeModes;
   1244     }
   1245 
   1246     public int[] getAvailableNoiseReductionModesChecked() {
   1247         Key<int[]> key =
   1248                 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
   1249         int[] noiseReductionModes = getValueFromKeyNonNull(key);
   1250 
   1251         if (noiseReductionModes == null) {
   1252             return new int[0];
   1253         }
   1254 
   1255         // Full device should always include OFF and FAST
   1256         if (isHardwareLevelFull()) {
   1257             List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
   1258             checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
   1259                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
   1260                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
   1261         }
   1262 
   1263         return noiseReductionModes;
   1264     }
   1265 
   1266     /**
   1267      * Get value of key android.control.aeCompensationStep and do the sanity check.
   1268      *
   1269      * @return default value if the value is null.
   1270      */
   1271     public Rational getAeCompensationStepChecked() {
   1272         Key<Rational> key =
   1273                 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
   1274         Rational compensationStep = getValueFromKeyNonNull(key);
   1275 
   1276         if (compensationStep == null) {
   1277             // Return default step.
   1278             return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
   1279         }
   1280 
   1281         // Legacy devices don't have a minimum step requirement
   1282         if (isHardwareLevelLimitedOrBetter()) {
   1283             float compensationStepF =
   1284                     (float) compensationStep.getNumerator() / compensationStep.getDenominator();
   1285             checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
   1286         }
   1287 
   1288         return compensationStep;
   1289     }
   1290 
   1291     /**
   1292      * Get value of key android.control.aeCompensationRange and do the sanity check.
   1293      *
   1294      * @return default value if the value is null or malformed.
   1295      */
   1296     public Range<Integer> getAeCompensationRangeChecked() {
   1297         Key<Range<Integer>> key =
   1298                 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
   1299         Range<Integer> compensationRange = getValueFromKeyNonNull(key);
   1300         Rational compensationStep = getAeCompensationStepChecked();
   1301         float compensationStepF = compensationStep.floatValue();
   1302         final Range<Integer> DEFAULT_RANGE = Range.create(
   1303                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF),
   1304                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
   1305         if (compensationRange == null) {
   1306             return DEFAULT_RANGE;
   1307         }
   1308 
   1309         // Legacy devices don't have a minimum range requirement
   1310         if (isHardwareLevelLimitedOrBetter()) {
   1311             checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
   1312                     + ", actual " + compensationRange + ", compensation step " + compensationStep,
   1313                    compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
   1314                    compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
   1315         }
   1316 
   1317         return compensationRange;
   1318     }
   1319 
   1320     /**
   1321      * Get availableVideoStabilizationModes and do the sanity check.
   1322      *
   1323      * @return available video stabilization modes, empty array if it is unavailable.
   1324      */
   1325     public int[] getAvailableVideoStabilizationModesChecked() {
   1326         Key<int[]> key =
   1327                 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
   1328         int[] modes = getValueFromKeyNonNull(key);
   1329 
   1330         if (modes == null) {
   1331             return new int[0];
   1332         }
   1333 
   1334         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
   1335         checkTrueForKey(key, " All device should support OFF mode",
   1336                 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
   1337         checkArrayValuesInRange(key, modes,
   1338                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
   1339                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
   1340 
   1341         return modes;
   1342     }
   1343 
   1344     /**
   1345      * Get availableOpticalStabilization and do the sanity check.
   1346      *
   1347      * @return available optical stabilization modes, empty array if it is unavailable.
   1348      */
   1349     public int[] getAvailableOpticalStabilizationChecked() {
   1350         Key<int[]> key =
   1351                 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
   1352         int[] modes = getValueFromKeyNonNull(key);
   1353 
   1354         if (modes == null) {
   1355             return new int[0];
   1356         }
   1357 
   1358         checkArrayValuesInRange(key, modes,
   1359                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
   1360                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
   1361 
   1362         return modes;
   1363     }
   1364 
   1365     /**
   1366      * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
   1367      * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
   1368      */
   1369     public float getAvailableMaxDigitalZoomChecked() {
   1370         Key<Float> key =
   1371                 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
   1372 
   1373         Float maxZoom = getValueFromKeyNonNull(key);
   1374         if (maxZoom == null) {
   1375             return 1.0f;
   1376         }
   1377 
   1378         checkTrueForKey(key, " max digital zoom should be no less than 1",
   1379                 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
   1380 
   1381         return maxZoom;
   1382     }
   1383 
   1384     public int[] getAvailableSceneModesChecked() {
   1385         Key<int[]> key =
   1386                 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
   1387         int[] modes = getValueFromKeyNonNull(key);
   1388 
   1389         if (modes == null) {
   1390             return new int[0];
   1391         }
   1392 
   1393         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
   1394         // FACE_PRIORITY must be included if face detection is supported.
   1395         if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
   1396                 getMaxFaceCountChecked() > 0) {
   1397             checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
   1398                     modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
   1399         }
   1400 
   1401         return modes;
   1402     }
   1403 
   1404     public int[] getAvailableEffectModesChecked() {
   1405         Key<int[]> key =
   1406                 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
   1407         int[] modes = getValueFromKeyNonNull(key);
   1408 
   1409         if (modes == null) {
   1410             return new int[0];
   1411         }
   1412 
   1413         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
   1414         // OFF must be included.
   1415         checkTrueForKey(key, " OFF must be included",
   1416                 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
   1417 
   1418         return modes;
   1419     }
   1420 
   1421     /**
   1422      * Get and check the available color aberration modes
   1423      *
   1424      * @return the available color aberration modes
   1425      */
   1426     public int[] getAvailableColorAberrationModesChecked() {
   1427         Key<int[]> key =
   1428                 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
   1429         int[] modes = getValueFromKeyNonNull(key);
   1430 
   1431         if (modes == null) {
   1432             return new int[0];
   1433         }
   1434 
   1435         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
   1436         checkTrueForKey(key, " Camera devices must always support OFF mode",
   1437                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF));
   1438         checkElementDistinct(key, modeList);
   1439         checkArrayValuesInRange(key, modes,
   1440                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
   1441                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
   1442 
   1443         return modes;
   1444     }
   1445 
   1446     /**
   1447      * Get max pipeline depth and do the sanity check.
   1448      *
   1449      * @return max pipeline depth, default value if it is not available.
   1450      */
   1451     public byte getPipelineMaxDepthChecked() {
   1452         Key<Byte> key =
   1453                 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
   1454         Byte maxDepth = getValueFromKeyNonNull(key);
   1455 
   1456         if (maxDepth == null) {
   1457             return REQUEST_PIPELINE_MAX_DEPTH_MAX;
   1458         }
   1459 
   1460         checkTrueForKey(key, " max pipeline depth should be no larger than "
   1461                 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
   1462 
   1463         return maxDepth;
   1464     }
   1465 
   1466     /**
   1467      * Get available capabilities and do the sanity check.
   1468      *
   1469      * @return reported available capabilities list, empty list if the value is unavailable.
   1470      */
   1471     public List<Integer> getAvailableCapabilitiesChecked() {
   1472         Key<int[]> key =
   1473                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
   1474         int[] availableCaps = getValueFromKeyNonNull(key);
   1475         List<Integer> capList;
   1476 
   1477         if (availableCaps == null) {
   1478             return new ArrayList<Integer>();
   1479         }
   1480 
   1481         checkArrayValuesInRange(key, availableCaps,
   1482                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
   1483                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW);
   1484         capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
   1485         return capList;
   1486     }
   1487 
   1488     /**
   1489      * Determine whether the current device supports a capability or not.
   1490      *
   1491      * @param capability (non-negative)
   1492      *
   1493      * @return {@code true} if the capability is supported, {@code false} otherwise.
   1494      *
   1495      * @throws IllegalArgumentException if {@code capability} was negative
   1496      *
   1497      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
   1498      */
   1499     public boolean isCapabilitySupported(int capability) {
   1500         if (capability < 0) {
   1501             throw new IllegalArgumentException("capability must be non-negative");
   1502         }
   1503 
   1504         List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
   1505 
   1506         return availableCapabilities.contains(capability);
   1507     }
   1508 
   1509     /**
   1510      * Determine whether or not all the {@code keys} are available characteristics keys
   1511      * (as in {@link CameraCharacteristics#getKeys}.
   1512      *
   1513      * <p>If this returns {@code true}, then querying for this key from a characteristics
   1514      * object will always return a non-{@code null} value.</p>
   1515      *
   1516      * @param keys collection of camera characteristics keys
   1517      * @return whether or not all characteristics keys are available
   1518      */
   1519     public final boolean areCharacteristicsKeysAvailable(
   1520             Collection<CameraCharacteristics.Key<?>> keys) {
   1521         return mCharacteristics.getKeys().containsAll(keys);
   1522     }
   1523 
   1524     /**
   1525      * Determine whether or not all the {@code keys} are available result keys
   1526      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
   1527      *
   1528      * <p>If this returns {@code true}, then querying for this key from a result
   1529      * object will almost always return a non-{@code null} value.</p>
   1530      *
   1531      * <p>In some cases (e.g. lens shading map), the request must have additional settings
   1532      * configured in order for the key to correspond to a value.</p>
   1533      *
   1534      * @param keys collection of capture result keys
   1535      * @return whether or not all result keys are available
   1536      */
   1537     public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
   1538         return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
   1539     }
   1540 
   1541     /**
   1542      * Determine whether or not all the {@code keys} are available request keys
   1543      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
   1544      *
   1545      * <p>If this returns {@code true}, then setting this key in the request builder
   1546      * may have some effect (and if it's {@code false}, then the camera device will
   1547      * definitely ignore it).</p>
   1548      *
   1549      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
   1550      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
   1551      *
   1552      * @param keys collection of capture request keys
   1553      * @return whether or not all result keys are available
   1554      */
   1555     public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
   1556         return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
   1557     }
   1558 
   1559     /**
   1560      * Determine whether or not all the {@code keys} are available characteristics keys
   1561      * (as in {@link CameraCharacteristics#getKeys}.
   1562      *
   1563      * <p>If this returns {@code true}, then querying for this key from a characteristics
   1564      * object will always return a non-{@code null} value.</p>
   1565      *
   1566      * @param keys one or more camera characteristic keys
   1567      * @return whether or not all characteristics keys are available
   1568      */
   1569     @SafeVarargs
   1570     public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) {
   1571         return areCharacteristicsKeysAvailable(Arrays.asList(keys));
   1572     }
   1573 
   1574     /**
   1575      * Determine whether or not all the {@code keys} are available result keys
   1576      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
   1577      *
   1578      * <p>If this returns {@code true}, then querying for this key from a result
   1579      * object will almost always return a non-{@code null} value.</p>
   1580      *
   1581      * <p>In some cases (e.g. lens shading map), the request must have additional settings
   1582      * configured in order for the key to correspond to a value.</p>
   1583      *
   1584      * @param keys one or more capture result keys
   1585      * @return whether or not all result keys are available
   1586      */
   1587     @SafeVarargs
   1588     public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
   1589         return areResultKeysAvailable(Arrays.asList(keys));
   1590     }
   1591 
   1592     /**
   1593      * Determine whether or not all the {@code keys} are available request keys
   1594      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
   1595      *
   1596      * <p>If this returns {@code true}, then setting this key in the request builder
   1597      * may have some effect (and if it's {@code false}, then the camera device will
   1598      * definitely ignore it).</p>
   1599      *
   1600      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
   1601      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
   1602      *
   1603      * @param keys one or more capture request keys
   1604      * @return whether or not all result keys are available
   1605      */
   1606     @SafeVarargs
   1607     public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
   1608         return areRequestKeysAvailable(Arrays.asList(keys));
   1609     }
   1610 
   1611     /*
   1612      * Determine if camera device support manual lens shading map control
   1613      *
   1614      * @return {@code true} if manual lens shading map control is supported
   1615      */
   1616     public boolean isManualLensShadingMapSupported() {
   1617         return areKeysAvailable(CaptureRequest.SHADING_MODE);
   1618     }
   1619 
   1620     /**
   1621      * Determine if camera device support manual color correction control
   1622      *
   1623      * @return {@code true} if manual color correction control is supported
   1624      */
   1625     public boolean isManualColorCorrectionSupported() {
   1626         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
   1627     }
   1628 
   1629     /**
   1630      * Determine if camera device support manual tone mapping control
   1631      *
   1632      * @return {@code true} if manual tone mapping control is supported
   1633      */
   1634     public boolean isManualToneMapSupported() {
   1635         return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
   1636     }
   1637 
   1638     /**
   1639      * Determine if camera device support manual color aberration control
   1640      *
   1641      * @return {@code true} if manual color aberration control is supported
   1642      */
   1643     public boolean isManualColorAberrationControlSupported() {
   1644         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
   1645     }
   1646 
   1647     /**
   1648      * Determine if camera device support edge mode control
   1649      *
   1650      * @return {@code true} if edge mode control is supported
   1651      */
   1652     public boolean isEdgeModeControlSupported() {
   1653         return areKeysAvailable(CaptureRequest.EDGE_MODE);
   1654     }
   1655 
   1656     /**
   1657      * Determine if camera device support hot pixel mode control
   1658      *
   1659      * @return {@code true} if hot pixel mode control is supported
   1660      */
   1661     public boolean isHotPixelMapModeControlSupported() {
   1662         return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
   1663     }
   1664 
   1665     /**
   1666      * Determine if camera device support noise reduction mode control
   1667      *
   1668      * @return {@code true} if noise reduction mode control is supported
   1669      */
   1670     public boolean isNoiseReductionModeControlSupported() {
   1671         return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
   1672     }
   1673 
   1674     /**
   1675      * Get max number of output raw streams and do the basic sanity check.
   1676      *
   1677      * @return reported max number of raw output stream
   1678      */
   1679     public int getMaxNumOutputStreamsRawChecked() {
   1680         Integer maxNumStreams =
   1681                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
   1682         if (maxNumStreams == null)
   1683             return 0;
   1684         return maxNumStreams;
   1685     }
   1686 
   1687     /**
   1688      * Get max number of output processed streams and do the basic sanity check.
   1689      *
   1690      * @return reported max number of processed output stream
   1691      */
   1692     public int getMaxNumOutputStreamsProcessedChecked() {
   1693         Integer maxNumStreams =
   1694                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
   1695         if (maxNumStreams == null)
   1696             return 0;
   1697         return maxNumStreams;
   1698     }
   1699 
   1700     /**
   1701      * Get max number of output stalling processed streams and do the basic sanity check.
   1702      *
   1703      * @return reported max number of stalling processed output stream
   1704      */
   1705     public int getMaxNumOutputStreamsProcessedStallChecked() {
   1706         Integer maxNumStreams =
   1707                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
   1708         if (maxNumStreams == null)
   1709             return 0;
   1710         return maxNumStreams;
   1711     }
   1712 
   1713     /**
   1714      * Get lens facing and do the sanity check
   1715      * @return lens facing, return default value (BACK) if value is unavailable.
   1716      */
   1717     public int getLensFacingChecked() {
   1718         Key<Integer> key =
   1719                 CameraCharacteristics.LENS_FACING;
   1720         Integer facing = getValueFromKeyNonNull(key);
   1721 
   1722         if (facing == null) {
   1723             return CameraCharacteristics.LENS_FACING_BACK;
   1724         }
   1725 
   1726         checkTrueForKey(key, " value is out of range ",
   1727                 facing >= CameraCharacteristics.LENS_FACING_FRONT &&
   1728                 facing <= CameraCharacteristics.LENS_FACING_BACK);
   1729         return facing;
   1730     }
   1731 
   1732     /**
   1733      * Get the scaler's cropping type (center only or freeform)
   1734      * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
   1735      */
   1736     public int getScalerCroppingTypeChecked() {
   1737         Key<Integer> key =
   1738                 CameraCharacteristics.SCALER_CROPPING_TYPE;
   1739         Integer value = getValueFromKeyNonNull(key);
   1740 
   1741         if (value == null) {
   1742             return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
   1743         }
   1744 
   1745         checkTrueForKey(key, " value is out of range ",
   1746                 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
   1747                 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
   1748 
   1749         return value;
   1750     }
   1751 
   1752     /**
   1753      * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
   1754      * supported, supported high speed fps ranges and sizes are valid).
   1755      *
   1756      * @return true if high speed video is supported.
   1757      */
   1758     public boolean isHighSpeedVideoSupported() {
   1759         List<Integer> sceneModes =
   1760                 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
   1761         if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
   1762             StreamConfigurationMap config =
   1763                     getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
   1764             if (config == null) {
   1765                 return false;
   1766             }
   1767             Size[] availableSizes = config.getHighSpeedVideoSizes();
   1768             if (availableSizes.length == 0) {
   1769                 return false;
   1770             }
   1771 
   1772             for (Size size : availableSizes) {
   1773                 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
   1774                 if (availableFpsRanges.length == 0) {
   1775                     return false;
   1776                 }
   1777             }
   1778 
   1779             return true;
   1780         } else {
   1781             return false;
   1782         }
   1783     }
   1784 
   1785     /**
   1786      * Get the value in index for a fixed-size array from a given key.
   1787      *
   1788      * <p>If the camera device is incorrectly reporting values, log a warning and return
   1789      * the default value instead.</p>
   1790      *
   1791      * @param key Key to fetch
   1792      * @param defaultValue Default value to return if camera device uses invalid values
   1793      * @param name Human-readable name for the array index (logging only)
   1794      * @param index Array index of the subelement
   1795      * @param size Expected fixed size of the array
   1796      *
   1797      * @return The value reported by the camera device, or the defaultValue otherwise.
   1798      */
   1799     private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
   1800             int size) {
   1801         T elementValue = getArrayElementCheckRangeNonNull(
   1802                 key,
   1803                 index,
   1804                 size);
   1805 
   1806         if (elementValue == null) {
   1807             failKeyCheck(key,
   1808                     "had no valid " + name + " value; using default of " + defaultValue);
   1809             elementValue = defaultValue;
   1810         }
   1811 
   1812         return elementValue;
   1813     }
   1814 
   1815     /**
   1816      * Fetch an array sub-element from an array value given by a key.
   1817      *
   1818      * <p>
   1819      * Prints a warning if the sub-element was null.
   1820      * </p>
   1821      *
   1822      * <p>Use for variable-size arrays since this does not check the array size.</p>
   1823      *
   1824      * @param key Metadata key to look up
   1825      * @param element A non-negative index value.
   1826      * @return The array sub-element, or null if the checking failed.
   1827      */
   1828     private <T> T getArrayElementNonNull(Key<?> key, int element) {
   1829         return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
   1830     }
   1831 
   1832     /**
   1833      * Fetch an array sub-element from an array value given by a key.
   1834      *
   1835      * <p>
   1836      * Prints a warning if the array size does not match the size, or if the sub-element was null.
   1837      * </p>
   1838      *
   1839      * @param key Metadata key to look up
   1840      * @param element The index in [0,size)
   1841      * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
   1842      * @return The array sub-element, or null if the checking failed.
   1843      */
   1844     private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
   1845         Object array = getValueFromKeyNonNull(key);
   1846 
   1847         if (array == null) {
   1848             // Warning already printed
   1849             return null;
   1850         }
   1851 
   1852         if (size != IGNORE_SIZE_CHECK) {
   1853             int actualLength = Array.getLength(array);
   1854             if (actualLength != size) {
   1855                 failKeyCheck(key,
   1856                         String.format("had the wrong number of elements (%d), expected (%d)",
   1857                                 actualLength, size));
   1858                 return null;
   1859             }
   1860         }
   1861 
   1862         @SuppressWarnings("unchecked")
   1863         T val = (T) Array.get(array, element);
   1864 
   1865         if (val == null) {
   1866             failKeyCheck(key, "had a null element at index" + element);
   1867             return null;
   1868         }
   1869 
   1870         return val;
   1871     }
   1872 
   1873     /**
   1874      * Gets the key, logging warnings for null values.
   1875      */
   1876     public <T> T getValueFromKeyNonNull(Key<T> key) {
   1877         if (key == null) {
   1878             throw new IllegalArgumentException("key was null");
   1879         }
   1880 
   1881         T value = mCharacteristics.get(key);
   1882 
   1883         if (value == null) {
   1884             failKeyCheck(key, "was null");
   1885         }
   1886 
   1887         return value;
   1888     }
   1889 
   1890     private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
   1891         for (int value : array) {
   1892             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
   1893                     value <= max && value >= min);
   1894         }
   1895     }
   1896 
   1897     private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
   1898         for (byte value : array) {
   1899             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
   1900                     value <= max && value >= min);
   1901         }
   1902     }
   1903 
   1904     /**
   1905      * Check the uniqueness of the values in a list.
   1906      *
   1907      * @param key The key to be checked
   1908      * @param list The list contains the value of the key
   1909      */
   1910     private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
   1911         // Each size must be distinct.
   1912         Set<T> sizeSet = new HashSet<T>(list);
   1913         checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
   1914     }
   1915 
   1916     private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
   1917         if (!condition) {
   1918             failKeyCheck(key, message);
   1919         }
   1920     }
   1921 
   1922     private <T> void failKeyCheck(Key<T> key, String message) {
   1923         // TODO: Consider only warning once per key/message combination if it's too spammy.
   1924         // TODO: Consider offering other options such as throwing an assertion exception
   1925         String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
   1926         switch (mLevel) {
   1927             case WARN:
   1928                 Log.w(TAG, failureCause);
   1929                 break;
   1930             case COLLECT:
   1931                 mCollector.addMessage(failureCause);
   1932                 break;
   1933             case ASSERT:
   1934                 Assert.fail(failureCause);
   1935             default:
   1936                 throw new UnsupportedOperationException("Unhandled level " + mLevel);
   1937         }
   1938     }
   1939 }
   1940