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