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