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