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