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