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