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