• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.cts.helpers;
18 
19 import android.graphics.Rect;
20 import android.graphics.ImageFormat;
21 import android.hardware.camera2.CameraCharacteristics;
22 import android.hardware.camera2.CameraCharacteristics.Key;
23 import android.hardware.camera2.CameraMetadata;
24 import android.hardware.camera2.CaptureRequest;
25 import android.hardware.camera2.CaptureResult;
26 import android.hardware.camera2.cts.CameraTestUtils;
27 import android.hardware.camera2.params.StreamConfigurationMap;
28 import android.util.Range;
29 import android.util.Size;
30 import android.util.Log;
31 import android.util.Rational;
32 
33 import junit.framework.Assert;
34 
35 import java.lang.reflect.Array;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Set;
43 
44 /**
45  * Helpers to get common static info out of the camera.
46  *
47  * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p>
48  *
49  * <p>Attempt to be durable against the camera device having bad or missing metadata
50  * by providing reasonable defaults and logging warnings when that happens.</p>
51  */
52 public class StaticMetadata {
53 
54     private static final String TAG = "StaticMetadata";
55     private static final int IGNORE_SIZE_CHECK = -1;
56 
57     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
58     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
59     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
60     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800;
61     private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
62     private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
63     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
64     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
65     private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
66     private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
67 
68     // TODO: Consider making this work across any metadata object, not just camera characteristics
69     private final CameraCharacteristics mCharacteristics;
70     private final CheckLevel mLevel;
71     private final CameraErrorCollector mCollector;
72 
73     public enum CheckLevel {
74         /** Only log warnings for metadata check failures. Execution continues. */
75         WARN,
76         /**
77          * Use ErrorCollector to collect the metadata check failures, Execution
78          * continues.
79          */
80         COLLECT,
81         /** Assert the metadata check failures. Execution aborts. */
82         ASSERT
83     }
84 
85     /**
86      * Construct a new StaticMetadata object.
87      *
88      *<p> Default constructor, only log warnings for the static metadata check failures</p>
89      *
90      * @param characteristics static info for a camera
91      * @throws IllegalArgumentException if characteristics was null
92      */
StaticMetadata(CameraCharacteristics characteristics)93     public StaticMetadata(CameraCharacteristics characteristics) {
94         this(characteristics, CheckLevel.WARN, /*collector*/null);
95     }
96 
97     /**
98      * Construct a new StaticMetadata object with {@link CameraErrorCollector}.
99      * <p>
100      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
101      * ignored, otherwise, it will be used to log the check failures.
102      * </p>
103      *
104      * @param characteristics static info for a camera
105      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
106      * @throws IllegalArgumentException if characteristics or collector was null.
107      */
StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector)108     public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) {
109         this(characteristics, CheckLevel.COLLECT, collector);
110     }
111 
112     /**
113      * Construct a new StaticMetadata object with {@link CheckLevel} and
114      * {@link CameraErrorCollector}.
115      * <p>
116      * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
117      * ignored, otherwise, it will be used to log the check failures.
118      * </p>
119      *
120      * @param characteristics static info for a camera
121      * @param level The {@link CheckLevel} of this StaticMetadata
122      * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
123      * @throws IllegalArgumentException if characteristics was null or level was
124      *         {@link CheckLevel.COLLECT} but collector was null.
125      */
StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, CameraErrorCollector collector)126     public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level,
127             CameraErrorCollector collector) {
128         if (characteristics == null) {
129             throw new IllegalArgumentException("characteristics was null");
130         }
131         if (level == CheckLevel.COLLECT && collector == null) {
132             throw new IllegalArgumentException("collector must valid when COLLECT level is set");
133         }
134 
135         mCharacteristics = characteristics;
136         mLevel = level;
137         mCollector = collector;
138     }
139 
140     /**
141      * Get the CameraCharacteristics associated with this StaticMetadata.
142      *
143      * @return A non-null CameraCharacteristics object
144      */
getCharacteristics()145     public CameraCharacteristics getCharacteristics() {
146         return mCharacteristics;
147     }
148 
149     /**
150      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
151      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}.
152      *
153      * <p>If the camera device is not reporting the hardwareLevel, this
154      * will cause the test to fail.</p>
155      *
156      * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
157      */
isHardwareLevelFull()158     public boolean isHardwareLevelFull() {
159         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
160     }
161 
162     /**
163      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
164      * Return the supported hardware level of the device, or fail if no value is reported.
165      *
166      * @return the supported hardware level as a constant defined for
167      *      {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
168      */
getHardwareLevelChecked()169     public int getHardwareLevelChecked() {
170         Integer hwLevel = getValueFromKeyNonNull(
171                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
172         if (hwLevel == null) {
173             Assert.fail("No supported hardware level reported.");
174         }
175         return hwLevel;
176     }
177 
178     /**
179      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
180      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}.
181      *
182      * <p>If the camera device is not reporting the hardwareLevel, this
183      * will cause the test to fail.</p>
184      *
185      * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
186      */
isHardwareLevelLegacy()187     public boolean isHardwareLevelLegacy() {
188         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
189     }
190 
191     /**
192      * Whether or not the per frame control is supported by the camera device.
193      *
194      * @return {@code true} if per frame control is supported, {@code false} otherwise.
195      */
isPerFrameControlSupported()196     public boolean isPerFrameControlSupported() {
197         return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
198     }
199 
200     /**
201      * Get the maximum number of frames to wait for a request settings being applied
202      *
203      * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency
204      *         CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control
205      *         a positive int otherwise
206      */
getSyncMaxLatency()207     public int getSyncMaxLatency() {
208         Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY);
209         if (value == null) {
210             return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN;
211         }
212         return value;
213     }
214 
215     /**
216      * Whether or not the hardware level reported by android.info.supportedHardwareLevel
217      * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
218      *
219      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
220      * will always return {@code true}.</p>
221      *
222      * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise.
223      */
isHardwareLevelLimited()224     public boolean isHardwareLevelLimited() {
225         return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
226     }
227 
228     /**
229      * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel}
230      * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
231      *
232      * <p>If the camera device is incorrectly reporting the hardwareLevel, this
233      * will always return {@code false}.</p>
234      *
235      * @return
236      *          {@code true} if the device is {@code LIMITED} or {@code FULL},
237      *          {@code false} otherwise (i.e. LEGACY).
238      */
isHardwareLevelLimitedOrBetter()239     public boolean isHardwareLevelLimitedOrBetter() {
240         Integer hwLevel = getValueFromKeyNonNull(
241                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
242 
243         if (hwLevel == null) {
244             return false;
245         }
246 
247         // Normal. Device could be limited.
248         int hwLevelInt = hwLevel;
249         return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
250                 hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
251     }
252 
253     /**
254      * Get the maximum number of partial result a request can expect
255      *
256      * @return 1 if partial result is not supported.
257      *         a integer value larger than 1 if partial result is supported.
258      */
getPartialResultCount()259     public int getPartialResultCount() {
260         Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
261         if (value == null) {
262             // Optional key. Default value is 1 if key is missing.
263             return 1;
264         }
265         return value;
266     }
267 
268     /**
269      * Get the exposure time value and clamp to the range if needed.
270      *
271      * @param exposure Input exposure time value to check.
272      * @return Exposure value in the legal range.
273      */
getExposureClampToRange(long exposure)274     public long getExposureClampToRange(long exposure) {
275         long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE);
276         long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE);
277         if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) {
278             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
279                     String.format(
280                     "Min value %d is too large, set to maximal legal value %d",
281                     minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST));
282             minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST;
283         }
284         if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) {
285             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
286                     String.format(
287                     "Max value %d is too small, set to minimal legal value %d",
288                     maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST));
289             maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST;
290         }
291 
292         return Math.max(minExposure, Math.min(maxExposure, exposure));
293     }
294 
295     /**
296      * Check if the camera device support focuser.
297      *
298      * @return true if camera device support focuser, false otherwise.
299      */
hasFocuser()300     public boolean hasFocuser() {
301         if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
302             // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
303             return (getMinimumFocusDistanceChecked() > 0);
304         } else {
305             // Check available AF modes
306             int[] availableAfModes = mCharacteristics.get(
307                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
308 
309             if (availableAfModes == null) {
310                 return false;
311             }
312 
313             // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
314             boolean hasFocuser = false;
315             loop: for (int mode : availableAfModes) {
316                 switch (mode) {
317                     case CameraMetadata.CONTROL_AF_MODE_AUTO:
318                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
319                     case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
320                     case CameraMetadata.CONTROL_AF_MODE_MACRO:
321                         hasFocuser = true;
322                         break loop;
323                 }
324             }
325 
326             return hasFocuser;
327         }
328     }
329 
330     /**
331      * Check if the camera device has flash unit.
332      * @return true if flash unit is available, false otherwise.
333      */
hasFlash()334     public boolean hasFlash() {
335         return getFlashInfoChecked();
336     }
337 
338     /**
339      * Get minimum focus distance.
340      *
341      * @return minimum focus distance, 0 if minimum focus distance is invalid.
342      */
getMinimumFocusDistanceChecked()343     public float getMinimumFocusDistanceChecked() {
344         Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE;
345         Float minFocusDistance;
346 
347         /**
348          * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable
349          *   devices; optional for all other devices.
350          */
351         if (isHardwareLevelFull() || isCapabilitySupported(
352                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
353             minFocusDistance = getValueFromKeyNonNull(key);
354         } else {
355             minFocusDistance = mCharacteristics.get(key);
356         }
357 
358         if (minFocusDistance == null) {
359             return 0.0f;
360         }
361 
362         checkTrueForKey(key, " minFocusDistance value shouldn't be negative",
363                 minFocusDistance >= 0);
364         if (minFocusDistance < 0) {
365             minFocusDistance = 0.0f;
366         }
367 
368         return minFocusDistance;
369     }
370 
371     /**
372      * Get focusDistanceCalibration.
373      *
374      * @return focusDistanceCalibration, UNCALIBRATED if value is invalid.
375      */
getFocusDistanceCalibrationChecked()376     public int getFocusDistanceCalibrationChecked() {
377         Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
378         Integer calibration = getValueFromKeyNonNull(key);
379 
380         if (calibration == null) {
381             return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
382         }
383 
384         checkTrueForKey(key, " value is out of range" ,
385                 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED &&
386                 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED);
387 
388         return calibration;
389     }
390 
391     /**
392      * Get max AE regions and do sanity check.
393      *
394      * @return AE max regions supported by the camera device
395      */
getAeMaxRegionsChecked()396     public int getAeMaxRegionsChecked() {
397         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
398         if (regionCount == null) {
399             return 0;
400         }
401         return regionCount;
402     }
403 
404     /**
405      * Get max AWB regions and do sanity check.
406      *
407      * @return AWB max regions supported by the camera device
408      */
getAwbMaxRegionsChecked()409     public int getAwbMaxRegionsChecked() {
410         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
411         if (regionCount == null) {
412             return 0;
413         }
414         return regionCount;
415     }
416 
417     /**
418      * Get max AF regions and do sanity check.
419      *
420      * @return AF max regions supported by the camera device
421      */
getAfMaxRegionsChecked()422     public int getAfMaxRegionsChecked() {
423         Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
424         if (regionCount == null) {
425             return 0;
426         }
427         return regionCount;
428     }
429     /**
430      * Get the available anti-banding modes.
431      *
432      * @return The array contains available anti-banding modes.
433      */
getAeAvailableAntiBandingModesChecked()434     public int[] getAeAvailableAntiBandingModesChecked() {
435         Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
436         int[] modes = getValueFromKeyNonNull(key);
437 
438         boolean foundAuto = false;
439         for (int mode : modes) {
440             checkTrueForKey(key, "mode value " + mode + " is out if range",
441                     mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF ||
442                     mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
443             if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) {
444                 foundAuto = true;
445                 return modes;
446             }
447         }
448         // Must contain AUTO mode.
449         checkTrueForKey(key, "AUTO mode is missing", foundAuto);
450 
451         return modes;
452     }
453 
454     /**
455      * Check if the antibanding OFF mode is supported.
456      *
457      * @return true if antibanding OFF mode is supported, false otherwise.
458      */
isAntiBandingOffModeSupported()459     public boolean isAntiBandingOffModeSupported() {
460         List<Integer> antiBandingModes =
461                 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
462 
463         return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
464     }
465 
getFlashInfoChecked()466     public Boolean getFlashInfoChecked() {
467         Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
468         Boolean hasFlash = getValueFromKeyNonNull(key);
469 
470         // In case the failOnKey only gives warning.
471         if (hasFlash == null) {
472             return false;
473         }
474 
475         return hasFlash;
476     }
477 
getAvailableTestPatternModesChecked()478     public int[] getAvailableTestPatternModesChecked() {
479         Key<int[]> key =
480                 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
481         int[] modes = getValueFromKeyNonNull(key);
482 
483         if (modes == null) {
484             return new int[0];
485         }
486 
487         int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF;
488         Integer[] boxedModes = CameraTestUtils.toObject(modes);
489         checkTrueForKey(key, " value must contain OFF mode",
490                 Arrays.asList(boxedModes).contains(expectValue));
491 
492         return modes;
493     }
494 
495     /**
496      * Get available thumbnail sizes and do the sanity check.
497      *
498      * @return The array of available thumbnail sizes
499      */
getAvailableThumbnailSizesChecked()500     public Size[] getAvailableThumbnailSizesChecked() {
501         Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES;
502         Size[] sizes = getValueFromKeyNonNull(key);
503         final List<Size> sizeList = Arrays.asList(sizes);
504 
505         // Size must contain (0, 0).
506         checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0)));
507 
508         // Each size must be distinct.
509         checkElementDistinct(key, sizeList);
510 
511         // Must be sorted in ascending order by area, by width if areas are same.
512         List<Size> orderedSizes =
513                 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true);
514         checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString()
515                 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList));
516 
517         // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations
518         // implementation see b/12958122.
519 
520         return sizes;
521     }
522 
523     /**
524      * Get available focal lengths and do the sanity check.
525      *
526      * @return The array of available focal lengths
527      */
getAvailableFocalLengthsChecked()528     public float[] getAvailableFocalLengthsChecked() {
529         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
530         float[] focalLengths = getValueFromKeyNonNull(key);
531 
532         checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1);
533 
534         for (int i = 0; i < focalLengths.length; i++) {
535             checkTrueForKey(key,
536                     String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]),
537                     focalLengths[i] > 0);
538         }
539         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths)));
540 
541         return focalLengths;
542     }
543 
544     /**
545      * Get available apertures and do the sanity check.
546      *
547      * @return The non-null array of available apertures
548      */
getAvailableAperturesChecked()549     public float[] getAvailableAperturesChecked() {
550         Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES;
551         float[] apertures = getValueFromKeyNonNull(key);
552 
553         checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1);
554 
555         for (int i = 0; i < apertures.length; i++) {
556             checkTrueForKey(key,
557                     String.format("apertures[%d] %f should be positive.", i, apertures[i]),
558                     apertures[i] > 0);
559         }
560         checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures)));
561 
562         return apertures;
563     }
564 
565     /**
566      * Get and check the available hot pixel map modes.
567      *
568      * @return the available hot pixel map modes
569      */
getAvailableHotPixelModesChecked()570     public int[] getAvailableHotPixelModesChecked() {
571         Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
572         int[] modes = getValueFromKeyNonNull(key);
573 
574         if (modes == null) {
575             return new int[0];
576         }
577 
578         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
579         if (isHardwareLevelFull()) {
580             checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
581                     modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
582         }
583         checkElementDistinct(key, modeList);
584         checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
585                 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
586 
587         return modes;
588     }
589 
590     /**
591      * Get and check available face detection modes.
592      *
593      * @return The non-null array of available face detection modes
594      */
getAvailableFaceDetectModesChecked()595     public int[] getAvailableFaceDetectModesChecked() {
596         Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
597         int[] modes = getValueFromKeyNonNull(key);
598 
599         if (modes == null) {
600             return new int[0];
601         }
602 
603         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
604         checkTrueForKey(key, "Array should contain OFF mode",
605                 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF));
606         checkElementDistinct(key, modeList);
607         checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF,
608                 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
609 
610         return modes;
611     }
612 
613     /**
614      * Get and check max face detected count.
615      *
616      * @return max number of faces that can be detected
617      */
getMaxFaceCountChecked()618     public int getMaxFaceCountChecked() {
619         Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT;
620         Integer count = getValueFromKeyNonNull(key);
621 
622         if (count == null) {
623             return 0;
624         }
625 
626         List<Integer> faceDetectModes =
627                 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked()));
628         if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) &&
629                 faceDetectModes.size() == 1) {
630             checkTrueForKey(key, " value must be 0 if only OFF mode is supported in "
631                     + "availableFaceDetectionModes", count == 0);
632         } else {
633             int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST;
634 
635             // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces.
636             if (isHardwareLevelLegacy()) {
637                 maxFaceCountAtLeast = 1;
638             }
639             checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE"
640                     + "or FULL is also supported in availableFaceDetectionModes",
641                     count >= maxFaceCountAtLeast);
642         }
643 
644         return count;
645     }
646 
647     /**
648      * Get and check the available tone map modes.
649      *
650      * @return the available tone map modes
651      */
getAvailableToneMapModesChecked()652     public int[] getAvailableToneMapModesChecked() {
653         Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES;
654         int[] modes = getValueFromKeyNonNull(key);
655 
656         if (modes == null) {
657             return new int[0];
658         }
659 
660         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
661         checkTrueForKey(key, " Camera devices must always support FAST mode",
662                 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
663         if (isHardwareLevelFull()) {
664             checkTrueForKey(key, "Full-capability camera devices must support"
665                     + "CONTRAST_CURVE mode",
666                     modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) &&
667                     modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
668         }
669         checkElementDistinct(key, modeList);
670         checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
671                 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY);
672 
673         return modes;
674     }
675 
676     /**
677      * Get and check max tonemap curve point.
678      *
679      * @return Max tonemap curve points.
680      */
getMaxTonemapCurvePointChecked()681     public int getMaxTonemapCurvePointChecked() {
682         Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS;
683         Integer count = getValueFromKeyNonNull(key);
684 
685         if (count == null) {
686             return 0;
687         }
688 
689         List<Integer> modeList =
690                 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked()));
691         if (modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE)) {
692             checkTrueForKey(key, "Full-capability camera device must support maxCurvePoints "
693                     + ">= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST,
694                     count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST);
695         }
696 
697         return count;
698     }
699 
700     /**
701      * Get and check pixel array size.
702      */
getPixelArraySizeChecked()703     public Size getPixelArraySizeChecked() {
704         Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE;
705         Size pixelArray = getValueFromKeyNonNull(key);
706         if (pixelArray == null) {
707             return new Size(0, 0);
708         }
709 
710         return pixelArray;
711     }
712 
713     /**
714      * Get and check active array size.
715      */
getActiveArraySizeChecked()716     public Rect getActiveArraySizeChecked() {
717         Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE;
718         Rect activeArray = getValueFromKeyNonNull(key);
719 
720         if (activeArray == null) {
721             return new Rect(0, 0, 0, 0);
722         }
723 
724         Size pixelArraySize = getPixelArraySizeChecked();
725         checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
726         checkTrueForKey(key, "values width/height are invalid",
727                 activeArray.width() <= pixelArraySize.getWidth() &&
728                 activeArray.height() <= pixelArraySize.getHeight());
729 
730         return activeArray;
731     }
732 
733     /**
734      * Get the sensitivity value and clamp to the range if needed.
735      *
736      * @param sensitivity Input sensitivity value to check.
737      * @return Sensitivity value in legal range.
738      */
getSensitivityClampToRange(int sensitivity)739     public int getSensitivityClampToRange(int sensitivity) {
740         int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE);
741         int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE);
742         if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) {
743             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
744                     String.format(
745                     "Min value %d is too large, set to maximal legal value %d",
746                     minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST));
747             minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST;
748         }
749         if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) {
750             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
751                     String.format(
752                     "Max value %d is too small, set to minimal legal value %d",
753                     maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST));
754             maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST;
755         }
756 
757         return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity));
758     }
759 
760     /**
761      * Get maxAnalogSensitivity for a camera device.
762      * <p>
763      * This is only available for FULL capability device, return 0 if it is unavailable.
764      * </p>
765      *
766      * @return maxAnalogSensitivity, 0 if it is not available.
767      */
getMaxAnalogSensitivityChecked()768     public int getMaxAnalogSensitivityChecked() {
769 
770         Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
771         Integer maxAnalogsensitivity = mCharacteristics.get(key);
772         if (maxAnalogsensitivity == null) {
773             if (isHardwareLevelFull()) {
774                 Assert.fail("Full device should report max analog sensitivity");
775             }
776             return 0;
777         }
778 
779         int minSensitivity = getSensitivityMinimumOrDefault();
780         int maxSensitivity = getSensitivityMaximumOrDefault();
781         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
782                 + " should be no larger than max sensitivity " + maxSensitivity,
783                 maxAnalogsensitivity <= maxSensitivity);
784         checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
785                 + " should be larger than min sensitivity " + maxSensitivity,
786                 maxAnalogsensitivity > minSensitivity);
787 
788         return maxAnalogsensitivity;
789     }
790 
791     /**
792      * Get hyperfocalDistance and do the sanity check.
793      * <p>
794      * Note that, this tag is optional, will return -1 if this tag is not
795      * available.
796      * </p>
797      *
798      * @return hyperfocalDistance of this device, -1 if this tag is not available.
799      */
getHyperfocalDistanceChecked()800     public float getHyperfocalDistanceChecked() {
801         Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
802         Float hyperfocalDistance = getValueFromKeyNonNull(key);
803         if (hyperfocalDistance == null) {
804             return -1;
805         }
806 
807         if (hasFocuser()) {
808             float minFocusDistance = getMinimumFocusDistanceChecked();
809             checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of"
810                     + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f,
811                     minFocusDistance),
812                     hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance);
813         }
814 
815         return hyperfocalDistance;
816     }
817 
818     /**
819      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
820      *
821      * <p>If the camera is incorrectly reporting values, log a warning and return
822      * the default value instead, which is the largest minimum value required to be supported
823      * by all camera devices.</p>
824      *
825      * @return The value reported by the camera device or the defaultValue otherwise.
826      */
getSensitivityMinimumOrDefault()827     public int getSensitivityMinimumOrDefault() {
828         return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST);
829     }
830 
831     /**
832      * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
833      *
834      * <p>If the camera is incorrectly reporting values, log a warning and return
835      * the default value instead.</p>
836      *
837      * @param defaultValue Value to return if no legal value is available
838      * @return The value reported by the camera device or the defaultValue otherwise.
839      */
getSensitivityMinimumOrDefault(int defaultValue)840     public int getSensitivityMinimumOrDefault(int defaultValue) {
841         Range<Integer> range = getValueFromKeyNonNull(
842                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
843         if (range == null) {
844             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
845                     "had no valid minimum value; using default of " + defaultValue);
846             return defaultValue;
847         }
848         return range.getLower();
849     }
850 
851     /**
852      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
853      *
854      * <p>If the camera is incorrectly reporting values, log a warning and return
855      * the default value instead, which is the smallest maximum value required to be supported
856      * by all camera devices.</p>
857      *
858      * @return The value reported by the camera device or the defaultValue otherwise.
859      */
getSensitivityMaximumOrDefault()860     public int getSensitivityMaximumOrDefault() {
861         return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST);
862     }
863 
864     /**
865      * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
866      *
867      * <p>If the camera is incorrectly reporting values, log a warning and return
868      * the default value instead.</p>
869      *
870      * @param defaultValue Value to return if no legal value is available
871      * @return The value reported by the camera device or the defaultValue otherwise.
872      */
getSensitivityMaximumOrDefault(int defaultValue)873     public int getSensitivityMaximumOrDefault(int defaultValue) {
874         Range<Integer> range = getValueFromKeyNonNull(
875                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
876         if (range == null) {
877             failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
878                     "had no valid maximum value; using default of " + defaultValue);
879             return defaultValue;
880         }
881         return range.getUpper();
882     }
883 
884     /**
885      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
886      *
887      * <p>If the camera is incorrectly reporting values, log a warning and return
888      * the default value instead.</p>
889      *
890      * @param defaultValue Value to return if no legal value is available
891      * @return The value reported by the camera device or the defaultValue otherwise.
892      */
getExposureMinimumOrDefault(long defaultValue)893     public long getExposureMinimumOrDefault(long defaultValue) {
894         Range<Long> range = getValueFromKeyNonNull(
895                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
896         if (range == null) {
897             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
898                     "had no valid minimum value; using default of " + defaultValue);
899             return defaultValue;
900         }
901         return range.getLower();
902     }
903 
904     /**
905      * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
906      *
907      * <p>If the camera is incorrectly reporting values, log a warning and return
908      * the default value instead, which is the largest minimum value required to be supported
909      * by all camera devices.</p>
910      *
911      * @return The value reported by the camera device or the defaultValue otherwise.
912      */
getExposureMinimumOrDefault()913     public long getExposureMinimumOrDefault() {
914         return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST);
915     }
916 
917     /**
918      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
919      *
920      * <p>If the camera is incorrectly reporting values, log a warning and return
921      * the default value instead.</p>
922      *
923      * @param defaultValue Value to return if no legal value is available
924      * @return The value reported by the camera device or the defaultValue otherwise.
925      */
getExposureMaximumOrDefault(long defaultValue)926     public long getExposureMaximumOrDefault(long defaultValue) {
927         Range<Long> range = getValueFromKeyNonNull(
928                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
929         if (range == null) {
930             failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
931                     "had no valid maximum value; using default of " + defaultValue);
932             return defaultValue;
933         }
934         return range.getUpper();
935     }
936 
937     /**
938      * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
939      *
940      * <p>If the camera is incorrectly reporting values, log a warning and return
941      * the default value instead, which is the smallest maximum value required to be supported
942      * by all camera devices.</p>
943      *
944      * @return The value reported by the camera device or the defaultValue otherwise.
945      */
getExposureMaximumOrDefault()946     public long getExposureMaximumOrDefault() {
947         return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST);
948     }
949 
950     /**
951      * Get aeAvailableModes and do the sanity check.
952      *
953      * <p>Depending on the check level this class has, for WAR or COLLECT levels,
954      * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
955      * have to abort the execution even the aeMode list is invalid.</p>
956      * @return AE available modes
957      */
getAeAvailableModesChecked()958     public int[] getAeAvailableModesChecked() {
959         Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
960         int[] modes = getValueFromKeyNonNull(modesKey);
961         if (modes == null) {
962             modes = new int[0];
963         }
964         List<Integer> modeList = new ArrayList<Integer>();
965         for (int mode : modes) {
966             modeList.add(mode);
967         }
968         checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
969 
970         // All camera device must support ON
971         checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
972                 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
973 
974         // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
975         Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
976         Boolean hasFlash = getValueFromKeyNonNull(flashKey);
977         if (hasFlash == null) {
978             hasFlash = false;
979         }
980         if (hasFlash) {
981             boolean flashModeConsistentWithFlash =
982                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
983                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
984             checkTrueForKey(modesKey,
985                     "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and  when flash is" +
986                     "available", flashModeConsistentWithFlash);
987         } else {
988             boolean flashModeConsistentWithoutFlash =
989                     !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
990                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
991                     modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
992             checkTrueForKey(modesKey,
993                     "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
994                     "ON_AUTO_FLASH_REDEYE when flash is unavailable",
995                     flashModeConsistentWithoutFlash);
996         }
997 
998         // FULL mode camera devices always support OFF mode.
999         boolean condition =
1000                 !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
1001         checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
1002 
1003         // Boundary check.
1004         for (int mode : modes) {
1005             checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
1006                     mode >= CameraMetadata.CONTROL_AE_MODE_OFF
1007                     && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
1008         }
1009 
1010         return modes;
1011     }
1012 
1013     /**
1014      * Get available AWB modes and do the sanity check.
1015      *
1016      * @return array that contains available AWB modes, empty array if awbAvailableModes is
1017      * unavailable.
1018      */
getAwbAvailableModesChecked()1019     public int[] getAwbAvailableModesChecked() {
1020         Key<int[]> key =
1021                 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
1022         int[] awbModes = getValueFromKeyNonNull(key);
1023 
1024         if (awbModes == null) {
1025             return new int[0];
1026         }
1027 
1028         List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
1029         checkTrueForKey(key, " All camera devices must support AUTO mode",
1030                 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
1031         if (isHardwareLevelFull()) {
1032             checkTrueForKey(key, " Full capability camera devices must support OFF mode",
1033                     modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
1034         }
1035 
1036         return awbModes;
1037     }
1038 
1039     /**
1040      * Get available AF modes and do the sanity check.
1041      *
1042      * @return array that contains available AF modes, empty array if afAvailableModes is
1043      * unavailable.
1044      */
getAfAvailableModesChecked()1045     public int[] getAfAvailableModesChecked() {
1046         Key<int[]> key =
1047                 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
1048         int[] afModes = getValueFromKeyNonNull(key);
1049 
1050         if (afModes == null) {
1051             return new int[0];
1052         }
1053 
1054         List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes));
1055         if (isHardwareLevelLimitedOrBetter()) {
1056             // Some LEGACY mode devices do not support AF OFF
1057             checkTrueForKey(key, " All camera devices must support OFF mode",
1058                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
1059         }
1060         if (hasFocuser()) {
1061             checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
1062                     modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
1063         }
1064 
1065         return afModes;
1066     }
1067 
1068     /**
1069      * Get supported raw output sizes and do the check.
1070      *
1071      * @return Empty size array if raw output is not supported
1072      */
getRawOutputSizesChecked()1073     public Size[] getRawOutputSizesChecked() {
1074         return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
1075                 StreamDirection.Output);
1076     }
1077 
1078     /**
1079      * Get supported jpeg output sizes and do the check.
1080      *
1081      * @return Empty size array if jpeg output is not supported
1082      */
getJpegOutputSizeChecked()1083     public Size[] getJpegOutputSizeChecked() {
1084         return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
1085                 StreamDirection.Output);
1086     }
1087 
1088     /**
1089      * Used to determine the stream direction for various helpers that look up
1090      * format or size information.
1091      */
1092     public enum StreamDirection {
1093         /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
1094         Output,
1095         /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
1096         Input
1097     }
1098 
1099     /**
1100      * Get available sizes for given user-defined format.
1101      *
1102      * <p><strong>Does not</strong> work with implementation-defined format.</p>
1103      *
1104      * @param format The format for the requested size array.
1105      * @param direction The stream direction, input or output.
1106      * @return The sizes of the given format, empty array if no available size is found.
1107      */
getAvailableSizesForFormatChecked(int format, StreamDirection direction)1108     public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
1109         Key<StreamConfigurationMap> key =
1110                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1111         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1112 
1113         if (config == null) {
1114             return new Size[0];
1115         }
1116 
1117         android.util.Size[] utilSizes;
1118 
1119         switch (direction) {
1120             case Output:
1121                 utilSizes = config.getOutputSizes(format);
1122                 break;
1123             case Input:
1124                 utilSizes = null;
1125                 break;
1126             default:
1127                 throw new IllegalArgumentException("direction must be output or input");
1128         }
1129 
1130         // TODO: Get rid of android.util.Size
1131         if (utilSizes == null) {
1132             Log.i(TAG, "This camera doesn't support format " + format + " for " + direction);
1133             return new Size[0];
1134         }
1135 
1136         Size[] sizes = new Size[utilSizes.length];
1137         for (int i = 0; i < utilSizes.length; ++i) {
1138             sizes[i] = new Size(utilSizes[i].getWidth(), utilSizes[i].getHeight());
1139         }
1140 
1141         return sizes;
1142     }
1143 
1144     /**
1145      * Get available AE target fps ranges.
1146      *
1147      * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
1148      */
1149     @SuppressWarnings("raw")
getAeAvailableTargetFpsRangesChecked()1150     public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
1151         Key<Range<Integer>[]> key =
1152                 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
1153         Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
1154 
1155         if (fpsRanges == null) {
1156             return new Range[0];
1157         }
1158 
1159         // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
1160         // in case the above check fails.
1161         int fpsRangeLength = fpsRanges.length;
1162         int minFps, maxFps;
1163         long maxFrameDuration = getMaxFrameDurationChecked();
1164         for (int i = 0; i < fpsRangeLength; i += 1) {
1165             minFps = fpsRanges[i].getLower();
1166             maxFps = fpsRanges[i].getUpper();
1167             checkTrueForKey(key, " min fps must be no larger than max fps!",
1168                     minFps > 0 && maxFps >= minFps);
1169             long maxDuration = (long) (1e9 / minFps);
1170             checkTrueForKey(key, String.format(
1171                     " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
1172                     maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
1173         }
1174 
1175         return fpsRanges;
1176     }
1177 
1178     /**
1179      * Get max frame duration.
1180      *
1181      * @return 0 if maxFrameDuration is null
1182      */
getMaxFrameDurationChecked()1183     public long getMaxFrameDurationChecked() {
1184         Key<Long> key =
1185                 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
1186         Long maxDuration = getValueFromKeyNonNull(key);
1187 
1188         if (maxDuration == null) {
1189             return 0;
1190         }
1191 
1192         return maxDuration;
1193     }
1194 
1195     /**
1196      * Get available minimal frame durations for a given user-defined format.
1197      *
1198      * <p><strong>Does not</strong> work with implementation-defined format.</p>
1199      *
1200      * @param format One of the format from {@link ImageFormat}.
1201      * @return HashMap of minimal frame durations for different sizes, empty HashMap
1202      *         if availableMinFrameDurations is null.
1203      */
getAvailableMinFrameDurationsForFormatChecked(int format)1204     public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
1205 
1206         HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
1207 
1208         Key<StreamConfigurationMap> key =
1209                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1210         StreamConfigurationMap config = getValueFromKeyNonNull(key);
1211 
1212         if (config == null) {
1213             return minDurationMap;
1214         }
1215 
1216         for (android.util.Size size : config.getOutputSizes(format)) {
1217             long minFrameDuration = config.getOutputMinFrameDuration(format, size);
1218 
1219             if (minFrameDuration != 0) {
1220                 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
1221             }
1222         }
1223 
1224         return minDurationMap;
1225     }
1226 
getAvailableEdgeModesChecked()1227     public int[] getAvailableEdgeModesChecked() {
1228         Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
1229         int[] edgeModes = getValueFromKeyNonNull(key);
1230 
1231         if (edgeModes == null) {
1232             return new int[0];
1233         }
1234 
1235         // Full device should always include OFF and FAST
1236         if (isHardwareLevelFull()) {
1237             List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
1238             checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
1239                     modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
1240                     modeList.contains(CameraMetadata.EDGE_MODE_FAST));
1241         }
1242 
1243         return edgeModes;
1244     }
1245 
getAvailableNoiseReductionModesChecked()1246     public int[] getAvailableNoiseReductionModesChecked() {
1247         Key<int[]> key =
1248                 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
1249         int[] noiseReductionModes = getValueFromKeyNonNull(key);
1250 
1251         if (noiseReductionModes == null) {
1252             return new int[0];
1253         }
1254 
1255         // Full device should always include OFF and FAST
1256         if (isHardwareLevelFull()) {
1257             List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
1258             checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
1259                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
1260                     modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
1261         }
1262 
1263         return noiseReductionModes;
1264     }
1265 
1266     /**
1267      * Get value of key android.control.aeCompensationStep and do the sanity check.
1268      *
1269      * @return default value if the value is null.
1270      */
getAeCompensationStepChecked()1271     public Rational getAeCompensationStepChecked() {
1272         Key<Rational> key =
1273                 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
1274         Rational compensationStep = getValueFromKeyNonNull(key);
1275 
1276         if (compensationStep == null) {
1277             // Return default step.
1278             return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
1279         }
1280 
1281         // Legacy devices don't have a minimum step requirement
1282         if (isHardwareLevelLimitedOrBetter()) {
1283             float compensationStepF =
1284                     (float) compensationStep.getNumerator() / compensationStep.getDenominator();
1285             checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
1286         }
1287 
1288         return compensationStep;
1289     }
1290 
1291     /**
1292      * Get value of key android.control.aeCompensationRange and do the sanity check.
1293      *
1294      * @return default value if the value is null or malformed.
1295      */
getAeCompensationRangeChecked()1296     public Range<Integer> getAeCompensationRangeChecked() {
1297         Key<Range<Integer>> key =
1298                 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
1299         Range<Integer> compensationRange = getValueFromKeyNonNull(key);
1300         Rational compensationStep = getAeCompensationStepChecked();
1301         float compensationStepF = compensationStep.floatValue();
1302         final Range<Integer> DEFAULT_RANGE = Range.create(
1303                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF),
1304                 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
1305         if (compensationRange == null) {
1306             return DEFAULT_RANGE;
1307         }
1308 
1309         // Legacy devices don't have a minimum range requirement
1310         if (isHardwareLevelLimitedOrBetter()) {
1311             checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
1312                     + ", actual " + compensationRange + ", compensation step " + compensationStep,
1313                    compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
1314                    compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
1315         }
1316 
1317         return compensationRange;
1318     }
1319 
1320     /**
1321      * Get availableVideoStabilizationModes and do the sanity check.
1322      *
1323      * @return available video stabilization modes, empty array if it is unavailable.
1324      */
getAvailableVideoStabilizationModesChecked()1325     public int[] getAvailableVideoStabilizationModesChecked() {
1326         Key<int[]> key =
1327                 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
1328         int[] modes = getValueFromKeyNonNull(key);
1329 
1330         if (modes == null) {
1331             return new int[0];
1332         }
1333 
1334         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1335         checkTrueForKey(key, " All device should support OFF mode",
1336                 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
1337         checkArrayValuesInRange(key, modes,
1338                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
1339                 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
1340 
1341         return modes;
1342     }
1343 
1344     /**
1345      * Get availableOpticalStabilization and do the sanity check.
1346      *
1347      * @return available optical stabilization modes, empty array if it is unavailable.
1348      */
getAvailableOpticalStabilizationChecked()1349     public int[] getAvailableOpticalStabilizationChecked() {
1350         Key<int[]> key =
1351                 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
1352         int[] modes = getValueFromKeyNonNull(key);
1353 
1354         if (modes == null) {
1355             return new int[0];
1356         }
1357 
1358         checkArrayValuesInRange(key, modes,
1359                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
1360                 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
1361 
1362         return modes;
1363     }
1364 
1365     /**
1366      * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
1367      * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
1368      */
getAvailableMaxDigitalZoomChecked()1369     public float getAvailableMaxDigitalZoomChecked() {
1370         Key<Float> key =
1371                 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
1372 
1373         Float maxZoom = getValueFromKeyNonNull(key);
1374         if (maxZoom == null) {
1375             return 1.0f;
1376         }
1377 
1378         checkTrueForKey(key, " max digital zoom should be no less than 1",
1379                 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
1380 
1381         return maxZoom;
1382     }
1383 
getAvailableSceneModesChecked()1384     public int[] getAvailableSceneModesChecked() {
1385         Key<int[]> key =
1386                 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
1387         int[] modes = getValueFromKeyNonNull(key);
1388 
1389         if (modes == null) {
1390             return new int[0];
1391         }
1392 
1393         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1394         // FACE_PRIORITY must be included if face detection is supported.
1395         if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
1396                 getMaxFaceCountChecked() > 0) {
1397             checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
1398                     modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
1399         }
1400 
1401         return modes;
1402     }
1403 
getAvailableEffectModesChecked()1404     public int[] getAvailableEffectModesChecked() {
1405         Key<int[]> key =
1406                 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
1407         int[] modes = getValueFromKeyNonNull(key);
1408 
1409         if (modes == null) {
1410             return new int[0];
1411         }
1412 
1413         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1414         // OFF must be included.
1415         checkTrueForKey(key, " OFF must be included",
1416                 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
1417 
1418         return modes;
1419     }
1420 
1421     /**
1422      * Get and check the available color aberration modes
1423      *
1424      * @return the available color aberration modes
1425      */
getAvailableColorAberrationModesChecked()1426     public int[] getAvailableColorAberrationModesChecked() {
1427         Key<int[]> key =
1428                 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
1429         int[] modes = getValueFromKeyNonNull(key);
1430 
1431         if (modes == null) {
1432             return new int[0];
1433         }
1434 
1435         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1436         checkTrueForKey(key, " Camera devices must always support OFF mode",
1437                 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF));
1438         checkElementDistinct(key, modeList);
1439         checkArrayValuesInRange(key, modes,
1440                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
1441                 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
1442 
1443         return modes;
1444     }
1445 
1446     /**
1447      * Get max pipeline depth and do the sanity check.
1448      *
1449      * @return max pipeline depth, default value if it is not available.
1450      */
getPipelineMaxDepthChecked()1451     public byte getPipelineMaxDepthChecked() {
1452         Key<Byte> key =
1453                 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
1454         Byte maxDepth = getValueFromKeyNonNull(key);
1455 
1456         if (maxDepth == null) {
1457             return REQUEST_PIPELINE_MAX_DEPTH_MAX;
1458         }
1459 
1460         checkTrueForKey(key, " max pipeline depth should be no larger than "
1461                 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
1462 
1463         return maxDepth;
1464     }
1465 
1466     /**
1467      * Get available capabilities and do the sanity check.
1468      *
1469      * @return reported available capabilities list, empty list if the value is unavailable.
1470      */
getAvailableCapabilitiesChecked()1471     public List<Integer> getAvailableCapabilitiesChecked() {
1472         Key<int[]> key =
1473                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
1474         int[] availableCaps = getValueFromKeyNonNull(key);
1475         List<Integer> capList;
1476 
1477         if (availableCaps == null) {
1478             return new ArrayList<Integer>();
1479         }
1480 
1481         checkArrayValuesInRange(key, availableCaps,
1482                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
1483                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW);
1484         capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
1485         return capList;
1486     }
1487 
1488     /**
1489      * Determine whether the current device supports a capability or not.
1490      *
1491      * @param capability (non-negative)
1492      *
1493      * @return {@code true} if the capability is supported, {@code false} otherwise.
1494      *
1495      * @throws IllegalArgumentException if {@code capability} was negative
1496      *
1497      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
1498      */
isCapabilitySupported(int capability)1499     public boolean isCapabilitySupported(int capability) {
1500         if (capability < 0) {
1501             throw new IllegalArgumentException("capability must be non-negative");
1502         }
1503 
1504         List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
1505 
1506         return availableCapabilities.contains(capability);
1507     }
1508 
1509     /**
1510      * Determine whether or not all the {@code keys} are available characteristics keys
1511      * (as in {@link CameraCharacteristics#getKeys}.
1512      *
1513      * <p>If this returns {@code true}, then querying for this key from a characteristics
1514      * object will always return a non-{@code null} value.</p>
1515      *
1516      * @param keys collection of camera characteristics keys
1517      * @return whether or not all characteristics keys are available
1518      */
areCharacteristicsKeysAvailable( Collection<CameraCharacteristics.Key<?>> keys)1519     public final boolean areCharacteristicsKeysAvailable(
1520             Collection<CameraCharacteristics.Key<?>> keys) {
1521         return mCharacteristics.getKeys().containsAll(keys);
1522     }
1523 
1524     /**
1525      * Determine whether or not all the {@code keys} are available result keys
1526      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1527      *
1528      * <p>If this returns {@code true}, then querying for this key from a result
1529      * object will almost always return a non-{@code null} value.</p>
1530      *
1531      * <p>In some cases (e.g. lens shading map), the request must have additional settings
1532      * configured in order for the key to correspond to a value.</p>
1533      *
1534      * @param keys collection of capture result keys
1535      * @return whether or not all result keys are available
1536      */
areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys)1537     public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
1538         return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
1539     }
1540 
1541     /**
1542      * Determine whether or not all the {@code keys} are available request keys
1543      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1544      *
1545      * <p>If this returns {@code true}, then setting this key in the request builder
1546      * may have some effect (and if it's {@code false}, then the camera device will
1547      * definitely ignore it).</p>
1548      *
1549      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1550      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1551      *
1552      * @param keys collection of capture request keys
1553      * @return whether or not all result keys are available
1554      */
areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys)1555     public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
1556         return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
1557     }
1558 
1559     /**
1560      * Determine whether or not all the {@code keys} are available characteristics keys
1561      * (as in {@link CameraCharacteristics#getKeys}.
1562      *
1563      * <p>If this returns {@code true}, then querying for this key from a characteristics
1564      * object will always return a non-{@code null} value.</p>
1565      *
1566      * @param keys one or more camera characteristic keys
1567      * @return whether or not all characteristics keys are available
1568      */
1569     @SafeVarargs
areKeysAvailable(CameraCharacteristics.Key<?>.... keys)1570     public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) {
1571         return areCharacteristicsKeysAvailable(Arrays.asList(keys));
1572     }
1573 
1574     /**
1575      * Determine whether or not all the {@code keys} are available result keys
1576      * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1577      *
1578      * <p>If this returns {@code true}, then querying for this key from a result
1579      * object will almost always return a non-{@code null} value.</p>
1580      *
1581      * <p>In some cases (e.g. lens shading map), the request must have additional settings
1582      * configured in order for the key to correspond to a value.</p>
1583      *
1584      * @param keys one or more capture result keys
1585      * @return whether or not all result keys are available
1586      */
1587     @SafeVarargs
areKeysAvailable(CaptureResult.Key<?>.... keys)1588     public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
1589         return areResultKeysAvailable(Arrays.asList(keys));
1590     }
1591 
1592     /**
1593      * Determine whether or not all the {@code keys} are available request keys
1594      * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1595      *
1596      * <p>If this returns {@code true}, then setting this key in the request builder
1597      * may have some effect (and if it's {@code false}, then the camera device will
1598      * definitely ignore it).</p>
1599      *
1600      * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1601      * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1602      *
1603      * @param keys one or more capture request keys
1604      * @return whether or not all result keys are available
1605      */
1606     @SafeVarargs
areKeysAvailable(CaptureRequest.Key<?>.... keys)1607     public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
1608         return areRequestKeysAvailable(Arrays.asList(keys));
1609     }
1610 
1611     /*
1612      * Determine if camera device support manual lens shading map control
1613      *
1614      * @return {@code true} if manual lens shading map control is supported
1615      */
isManualLensShadingMapSupported()1616     public boolean isManualLensShadingMapSupported() {
1617         return areKeysAvailable(CaptureRequest.SHADING_MODE);
1618     }
1619 
1620     /**
1621      * Determine if camera device support manual color correction control
1622      *
1623      * @return {@code true} if manual color correction control is supported
1624      */
isManualColorCorrectionSupported()1625     public boolean isManualColorCorrectionSupported() {
1626         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
1627     }
1628 
1629     /**
1630      * Determine if camera device support manual tone mapping control
1631      *
1632      * @return {@code true} if manual tone mapping control is supported
1633      */
isManualToneMapSupported()1634     public boolean isManualToneMapSupported() {
1635         return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
1636     }
1637 
1638     /**
1639      * Determine if camera device support manual color aberration control
1640      *
1641      * @return {@code true} if manual color aberration control is supported
1642      */
isManualColorAberrationControlSupported()1643     public boolean isManualColorAberrationControlSupported() {
1644         return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
1645     }
1646 
1647     /**
1648      * Determine if camera device support edge mode control
1649      *
1650      * @return {@code true} if edge mode control is supported
1651      */
isEdgeModeControlSupported()1652     public boolean isEdgeModeControlSupported() {
1653         return areKeysAvailable(CaptureRequest.EDGE_MODE);
1654     }
1655 
1656     /**
1657      * Determine if camera device support hot pixel mode control
1658      *
1659      * @return {@code true} if hot pixel mode control is supported
1660      */
isHotPixelMapModeControlSupported()1661     public boolean isHotPixelMapModeControlSupported() {
1662         return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
1663     }
1664 
1665     /**
1666      * Determine if camera device support noise reduction mode control
1667      *
1668      * @return {@code true} if noise reduction mode control is supported
1669      */
isNoiseReductionModeControlSupported()1670     public boolean isNoiseReductionModeControlSupported() {
1671         return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
1672     }
1673 
1674     /**
1675      * Get max number of output raw streams and do the basic sanity check.
1676      *
1677      * @return reported max number of raw output stream
1678      */
getMaxNumOutputStreamsRawChecked()1679     public int getMaxNumOutputStreamsRawChecked() {
1680         Integer maxNumStreams =
1681                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
1682         if (maxNumStreams == null)
1683             return 0;
1684         return maxNumStreams;
1685     }
1686 
1687     /**
1688      * Get max number of output processed streams and do the basic sanity check.
1689      *
1690      * @return reported max number of processed output stream
1691      */
getMaxNumOutputStreamsProcessedChecked()1692     public int getMaxNumOutputStreamsProcessedChecked() {
1693         Integer maxNumStreams =
1694                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
1695         if (maxNumStreams == null)
1696             return 0;
1697         return maxNumStreams;
1698     }
1699 
1700     /**
1701      * Get max number of output stalling processed streams and do the basic sanity check.
1702      *
1703      * @return reported max number of stalling processed output stream
1704      */
getMaxNumOutputStreamsProcessedStallChecked()1705     public int getMaxNumOutputStreamsProcessedStallChecked() {
1706         Integer maxNumStreams =
1707                 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
1708         if (maxNumStreams == null)
1709             return 0;
1710         return maxNumStreams;
1711     }
1712 
1713     /**
1714      * Get lens facing and do the sanity check
1715      * @return lens facing, return default value (BACK) if value is unavailable.
1716      */
getLensFacingChecked()1717     public int getLensFacingChecked() {
1718         Key<Integer> key =
1719                 CameraCharacteristics.LENS_FACING;
1720         Integer facing = getValueFromKeyNonNull(key);
1721 
1722         if (facing == null) {
1723             return CameraCharacteristics.LENS_FACING_BACK;
1724         }
1725 
1726         checkTrueForKey(key, " value is out of range ",
1727                 facing >= CameraCharacteristics.LENS_FACING_FRONT &&
1728                 facing <= CameraCharacteristics.LENS_FACING_BACK);
1729         return facing;
1730     }
1731 
1732     /**
1733      * Get the scaler's cropping type (center only or freeform)
1734      * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
1735      */
getScalerCroppingTypeChecked()1736     public int getScalerCroppingTypeChecked() {
1737         Key<Integer> key =
1738                 CameraCharacteristics.SCALER_CROPPING_TYPE;
1739         Integer value = getValueFromKeyNonNull(key);
1740 
1741         if (value == null) {
1742             return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
1743         }
1744 
1745         checkTrueForKey(key, " value is out of range ",
1746                 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
1747                 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
1748 
1749         return value;
1750     }
1751 
1752     /**
1753      * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
1754      * supported, supported high speed fps ranges and sizes are valid).
1755      *
1756      * @return true if high speed video is supported.
1757      */
isHighSpeedVideoSupported()1758     public boolean isHighSpeedVideoSupported() {
1759         List<Integer> sceneModes =
1760                 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
1761         if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
1762             StreamConfigurationMap config =
1763                     getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1764             if (config == null) {
1765                 return false;
1766             }
1767             Size[] availableSizes = config.getHighSpeedVideoSizes();
1768             if (availableSizes.length == 0) {
1769                 return false;
1770             }
1771 
1772             for (Size size : availableSizes) {
1773                 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
1774                 if (availableFpsRanges.length == 0) {
1775                     return false;
1776                 }
1777             }
1778 
1779             return true;
1780         } else {
1781             return false;
1782         }
1783     }
1784 
1785     /**
1786      * Get the value in index for a fixed-size array from a given key.
1787      *
1788      * <p>If the camera device is incorrectly reporting values, log a warning and return
1789      * the default value instead.</p>
1790      *
1791      * @param key Key to fetch
1792      * @param defaultValue Default value to return if camera device uses invalid values
1793      * @param name Human-readable name for the array index (logging only)
1794      * @param index Array index of the subelement
1795      * @param size Expected fixed size of the array
1796      *
1797      * @return The value reported by the camera device, or the defaultValue otherwise.
1798      */
getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, int size)1799     private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
1800             int size) {
1801         T elementValue = getArrayElementCheckRangeNonNull(
1802                 key,
1803                 index,
1804                 size);
1805 
1806         if (elementValue == null) {
1807             failKeyCheck(key,
1808                     "had no valid " + name + " value; using default of " + defaultValue);
1809             elementValue = defaultValue;
1810         }
1811 
1812         return elementValue;
1813     }
1814 
1815     /**
1816      * Fetch an array sub-element from an array value given by a key.
1817      *
1818      * <p>
1819      * Prints a warning if the sub-element was null.
1820      * </p>
1821      *
1822      * <p>Use for variable-size arrays since this does not check the array size.</p>
1823      *
1824      * @param key Metadata key to look up
1825      * @param element A non-negative index value.
1826      * @return The array sub-element, or null if the checking failed.
1827      */
getArrayElementNonNull(Key<?> key, int element)1828     private <T> T getArrayElementNonNull(Key<?> key, int element) {
1829         return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
1830     }
1831 
1832     /**
1833      * Fetch an array sub-element from an array value given by a key.
1834      *
1835      * <p>
1836      * Prints a warning if the array size does not match the size, or if the sub-element was null.
1837      * </p>
1838      *
1839      * @param key Metadata key to look up
1840      * @param element The index in [0,size)
1841      * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
1842      * @return The array sub-element, or null if the checking failed.
1843      */
getArrayElementCheckRangeNonNull(Key<?> key, int element, int size)1844     private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
1845         Object array = getValueFromKeyNonNull(key);
1846 
1847         if (array == null) {
1848             // Warning already printed
1849             return null;
1850         }
1851 
1852         if (size != IGNORE_SIZE_CHECK) {
1853             int actualLength = Array.getLength(array);
1854             if (actualLength != size) {
1855                 failKeyCheck(key,
1856                         String.format("had the wrong number of elements (%d), expected (%d)",
1857                                 actualLength, size));
1858                 return null;
1859             }
1860         }
1861 
1862         @SuppressWarnings("unchecked")
1863         T val = (T) Array.get(array, element);
1864 
1865         if (val == null) {
1866             failKeyCheck(key, "had a null element at index" + element);
1867             return null;
1868         }
1869 
1870         return val;
1871     }
1872 
1873     /**
1874      * Gets the key, logging warnings for null values.
1875      */
getValueFromKeyNonNull(Key<T> key)1876     public <T> T getValueFromKeyNonNull(Key<T> key) {
1877         if (key == null) {
1878             throw new IllegalArgumentException("key was null");
1879         }
1880 
1881         T value = mCharacteristics.get(key);
1882 
1883         if (value == null) {
1884             failKeyCheck(key, "was null");
1885         }
1886 
1887         return value;
1888     }
1889 
checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max)1890     private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
1891         for (int value : array) {
1892             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
1893                     value <= max && value >= min);
1894         }
1895     }
1896 
checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max)1897     private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
1898         for (byte value : array) {
1899             checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
1900                     value <= max && value >= min);
1901         }
1902     }
1903 
1904     /**
1905      * Check the uniqueness of the values in a list.
1906      *
1907      * @param key The key to be checked
1908      * @param list The list contains the value of the key
1909      */
checkElementDistinct(Key<U> key, List<T> list)1910     private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
1911         // Each size must be distinct.
1912         Set<T> sizeSet = new HashSet<T>(list);
1913         checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
1914     }
1915 
checkTrueForKey(Key<T> key, String message, boolean condition)1916     private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
1917         if (!condition) {
1918             failKeyCheck(key, message);
1919         }
1920     }
1921 
failKeyCheck(Key<T> key, String message)1922     private <T> void failKeyCheck(Key<T> key, String message) {
1923         // TODO: Consider only warning once per key/message combination if it's too spammy.
1924         // TODO: Consider offering other options such as throwing an assertion exception
1925         String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
1926         switch (mLevel) {
1927             case WARN:
1928                 Log.w(TAG, failureCause);
1929                 break;
1930             case COLLECT:
1931                 mCollector.addMessage(failureCause);
1932                 break;
1933             case ASSERT:
1934                 Assert.fail(failureCause);
1935             default:
1936                 throw new UnsupportedOperationException("Unhandled level " + mLevel);
1937         }
1938     }
1939 }
1940