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