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