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