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