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