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