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
17package com.android.mediaframeworktest.helpers;
18
19import junit.framework.Assert;
20
21import android.graphics.ImageFormat;
22import android.graphics.Rect;
23import android.hardware.camera2.CameraCharacteristics;
24import android.hardware.camera2.CameraCharacteristics.Key;
25import android.hardware.camera2.CameraMetadata;
26import android.hardware.camera2.CaptureRequest;
27import android.hardware.camera2.CaptureResult;
28import android.hardware.camera2.params.StreamConfigurationMap;
29import android.util.Log;
30import android.util.Range;
31import android.util.Rational;
32import android.util.Size;
33
34import java.lang.reflect.Array;
35import java.util.ArrayList;
36import java.util.Arrays;
37import java.util.Collection;
38import java.util.HashMap;
39import java.util.HashSet;
40import java.util.List;
41import java.util.Set;
42
43import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
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 */
57public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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 sanity check.
439     *
440     * @return AE max regions supported by the camera device
441     */
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 sanity check.
452     *
453     * @return AWB max regions supported by the camera device
454     */
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 sanity check.
465     *
466     * @return AF max regions supported by the camera device
467     */
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     */
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     */
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
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
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 sanity check.
549     *
550     * @return The array of available thumbnail sizes
551     */
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 sanity check.
577     *
578     * @return The array of available focal lengths
579     */
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 sanity check.
598     *
599     * @return The non-null array of available apertures
600     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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 sanity 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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 sanity check.
1072     *
1073     * @return available control modes.
1074     */
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
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 sanity 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     */
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            modeList.add(mode);
1143        }
1144        checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
1145
1146        // All camera device must support ON
1147        checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
1148                modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
1149
1150        // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
1151        Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
1152        Boolean hasFlash = getValueFromKeyNonNull(flashKey);
1153        if (hasFlash == null) {
1154            hasFlash = false;
1155        }
1156        if (hasFlash) {
1157            boolean flashModeConsistentWithFlash =
1158                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
1159                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
1160            checkTrueForKey(modesKey,
1161                    "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and  when flash is" +
1162                    "available", flashModeConsistentWithFlash);
1163        } else {
1164            boolean flashModeConsistentWithoutFlash =
1165                    !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
1166                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
1167                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
1168            checkTrueForKey(modesKey,
1169                    "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
1170                    "ON_AUTO_FLASH_REDEYE when flash is unavailable",
1171                    flashModeConsistentWithoutFlash);
1172        }
1173
1174        // FULL mode camera devices always support OFF mode.
1175        boolean condition =
1176                !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
1177        checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
1178
1179        // Boundary check.
1180        for (int mode : modes) {
1181            checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
1182                    mode >= CameraMetadata.CONTROL_AE_MODE_OFF
1183                    && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
1184        }
1185
1186        return modes;
1187    }
1188
1189    /**
1190     * Get available AWB modes and do the sanity check.
1191     *
1192     * @return array that contains available AWB modes, empty array if awbAvailableModes is
1193     * unavailable.
1194     */
1195    public int[] getAwbAvailableModesChecked() {
1196        Key<int[]> key =
1197                CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
1198        int[] awbModes = getValueFromKeyNonNull(key);
1199
1200        if (awbModes == null) {
1201            return new int[0];
1202        }
1203
1204        List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
1205        checkTrueForKey(key, " All camera devices must support AUTO mode",
1206                modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
1207        if (isHardwareLevelFull()) {
1208            checkTrueForKey(key, " Full capability camera devices must support OFF mode",
1209                    modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
1210        }
1211
1212        return awbModes;
1213    }
1214
1215    /**
1216     * Get available AF modes and do the sanity check.
1217     *
1218     * @return array that contains available AF modes, empty array if afAvailableModes is
1219     * unavailable.
1220     */
1221    public int[] getAfAvailableModesChecked() {
1222        Key<int[]> key =
1223                CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
1224        int[] afModes = getValueFromKeyNonNull(key);
1225
1226        if (afModes == null) {
1227            return new int[0];
1228        }
1229
1230        List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes));
1231        if (isHardwareLevelLimitedOrBetter()) {
1232            // Some LEGACY mode devices do not support AF OFF
1233            checkTrueForKey(key, " All camera devices must support OFF mode",
1234                    modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
1235        }
1236        if (hasFocuser()) {
1237            checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
1238                    modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
1239        }
1240
1241        return afModes;
1242    }
1243
1244    /**
1245     * Get supported raw output sizes and do the check.
1246     *
1247     * @return Empty size array if raw output is not supported
1248     */
1249    public Size[] getRawOutputSizesChecked() {
1250        return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
1251                StreamDirection.Output);
1252    }
1253
1254    /**
1255     * Get supported jpeg output sizes and do the check.
1256     *
1257     * @return Empty size array if jpeg output is not supported
1258     */
1259    public Size[] getJpegOutputSizesChecked() {
1260        return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
1261                StreamDirection.Output);
1262    }
1263
1264    /**
1265     * Used to determine the stream direction for various helpers that look up
1266     * format or size information.
1267     */
1268    public enum StreamDirection {
1269        /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
1270        Output,
1271        /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
1272        Input
1273    }
1274
1275    /**
1276     * Get available formats for a given direction.
1277     *
1278     * @param direction The stream direction, input or output.
1279     * @return The formats of the given direction, empty array if no available format is found.
1280     */
1281    public int[] getAvailableFormats(StreamDirection direction) {
1282        Key<StreamConfigurationMap> key =
1283                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1284        StreamConfigurationMap config = getValueFromKeyNonNull(key);
1285
1286        if (config == null) {
1287            return new int[0];
1288        }
1289
1290        switch (direction) {
1291            case Output:
1292                return config.getOutputFormats();
1293            case Input:
1294                return config.getInputFormats();
1295            default:
1296                throw new IllegalArgumentException("direction must be output or input");
1297        }
1298    }
1299
1300    /**
1301     * Get valid output formats for a given input format.
1302     *
1303     * @param inputFormat The input format used to produce the output images.
1304     * @return The output formats for the given input format, empty array if
1305     *         no available format is found.
1306     */
1307    public int[] getValidOutputFormatsForInput(int inputFormat) {
1308        Key<StreamConfigurationMap> key =
1309                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1310        StreamConfigurationMap config = getValueFromKeyNonNull(key);
1311
1312        if (config == null) {
1313            return new int[0];
1314        }
1315
1316        return config.getValidOutputFormatsForInput(inputFormat);
1317    }
1318
1319    /**
1320     * Get available sizes for given format and direction.
1321     *
1322     * @param format The format for the requested size array.
1323     * @param direction The stream direction, input or output.
1324     * @return The sizes of the given format, empty array if no available size is found.
1325     */
1326    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
1327        return getAvailableSizesForFormatChecked(format, direction,
1328                /*fastSizes*/true, /*slowSizes*/true);
1329    }
1330
1331    /**
1332     * Get available sizes for given format and direction, and whether to limit to slow or fast
1333     * resolutions.
1334     *
1335     * @param format The format for the requested size array.
1336     * @param direction The stream direction, input or output.
1337     * @param fastSizes whether to include getOutputSizes() sizes (generally faster)
1338     * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower)
1339     * @return The sizes of the given format, empty array if no available size is found.
1340     */
1341    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction,
1342            boolean fastSizes, boolean slowSizes) {
1343        Key<StreamConfigurationMap> key =
1344                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1345        StreamConfigurationMap config = getValueFromKeyNonNull(key);
1346
1347        if (config == null) {
1348            return new Size[0];
1349        }
1350
1351        Size[] sizes = null;
1352
1353        switch (direction) {
1354            case Output:
1355                Size[] fastSizeList = null;
1356                Size[] slowSizeList = null;
1357                if (fastSizes) {
1358                    fastSizeList = config.getOutputSizes(format);
1359                }
1360                if (slowSizes) {
1361                    slowSizeList = config.getHighResolutionOutputSizes(format);
1362                }
1363                if (fastSizeList != null && slowSizeList != null) {
1364                    sizes = new Size[slowSizeList.length + fastSizeList.length];
1365                    System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length);
1366                    System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length);
1367                } else if (fastSizeList != null) {
1368                    sizes = fastSizeList;
1369                } else if (slowSizeList != null) {
1370                    sizes = slowSizeList;
1371                }
1372                break;
1373            case Input:
1374                sizes = config.getInputSizes(format);
1375                break;
1376            default:
1377                throw new IllegalArgumentException("direction must be output or input");
1378        }
1379
1380        if (sizes == null) {
1381            sizes = new Size[0];
1382        }
1383
1384        return sizes;
1385    }
1386
1387    /**
1388     * Get available AE target fps ranges.
1389     *
1390     * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
1391     */
1392    @SuppressWarnings("raw")
1393    public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
1394        Key<Range<Integer>[]> key =
1395                CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
1396        Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
1397
1398        if (fpsRanges == null) {
1399            return new Range[0];
1400        }
1401
1402        // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
1403        // in case the above check fails.
1404        int fpsRangeLength = fpsRanges.length;
1405        int minFps, maxFps;
1406        long maxFrameDuration = getMaxFrameDurationChecked();
1407        for (int i = 0; i < fpsRangeLength; i += 1) {
1408            minFps = fpsRanges[i].getLower();
1409            maxFps = fpsRanges[i].getUpper();
1410            checkTrueForKey(key, " min fps must be no larger than max fps!",
1411                    minFps > 0 && maxFps >= minFps);
1412            long maxDuration = (long) (1e9 / minFps);
1413            checkTrueForKey(key, String.format(
1414                    " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
1415                    maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
1416        }
1417        return fpsRanges;
1418    }
1419
1420    /**
1421     * Get the highest supported target FPS range.
1422     * Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS.
1423     */
1424    public Range<Integer> getAeMaxTargetFpsRange() {
1425        Range<Integer>[] fpsRanges = getAeAvailableTargetFpsRangesChecked();
1426
1427        Range<Integer> targetRange = fpsRanges[0];
1428        // Assume unsorted list of target FPS ranges, so use two passes, first maximize min FPS
1429        for (Range<Integer> candidateRange : fpsRanges) {
1430            if (candidateRange.getLower() > targetRange.getLower()) {
1431                targetRange = candidateRange;
1432            }
1433        }
1434        // Then maximize max FPS while not lowering min FPS
1435        for (Range<Integer> candidateRange : fpsRanges) {
1436            if (candidateRange.getLower() >= targetRange.getLower() &&
1437                    candidateRange.getUpper() > targetRange.getUpper()) {
1438                targetRange = candidateRange;
1439            }
1440        }
1441        return targetRange;
1442    }
1443
1444    /**
1445     * Get max frame duration.
1446     *
1447     * @return 0 if maxFrameDuration is null
1448     */
1449    public long getMaxFrameDurationChecked() {
1450        Key<Long> key =
1451                CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
1452        Long maxDuration = getValueFromKeyNonNull(key);
1453
1454        if (maxDuration == null) {
1455            return 0;
1456        }
1457
1458        return maxDuration;
1459    }
1460
1461    /**
1462     * Get available minimal frame durations for a given format.
1463     *
1464     * @param format One of the format from {@link ImageFormat}.
1465     * @return HashMap of minimal frame durations for different sizes, empty HashMap
1466     *         if availableMinFrameDurations is null.
1467     */
1468    public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
1469
1470        HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
1471
1472        Key<StreamConfigurationMap> key =
1473                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1474        StreamConfigurationMap config = getValueFromKeyNonNull(key);
1475
1476        if (config == null) {
1477            return minDurationMap;
1478        }
1479
1480        for (Size size : getAvailableSizesForFormatChecked(format,
1481                StreamDirection.Output)) {
1482            long minFrameDuration = config.getOutputMinFrameDuration(format, size);
1483
1484            if (minFrameDuration != 0) {
1485                minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
1486            }
1487        }
1488
1489        return minDurationMap;
1490    }
1491
1492    public int[] getAvailableEdgeModesChecked() {
1493        Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
1494        int[] edgeModes = getValueFromKeyNonNull(key);
1495
1496        if (edgeModes == null) {
1497            return new int[0];
1498        }
1499
1500        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
1501        // Full device should always include OFF and FAST
1502        if (isHardwareLevelFull()) {
1503            checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
1504                    modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
1505                    modeList.contains(CameraMetadata.EDGE_MODE_FAST));
1506        }
1507
1508        if (isHardwareLevelLimitedOrBetter()) {
1509            // FAST and HIGH_QUALITY mode must be both present or both not present
1510            List<Integer> coupledModes = Arrays.asList(new Integer[] {
1511                    CameraMetadata.EDGE_MODE_FAST,
1512                    CameraMetadata.EDGE_MODE_HIGH_QUALITY
1513            });
1514            checkTrueForKey(
1515                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
1516                    containsAllOrNone(modeList, coupledModes));
1517        }
1518
1519        return edgeModes;
1520    }
1521
1522    public int[] getAvailableNoiseReductionModesChecked() {
1523        Key<int[]> key =
1524                CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
1525        int[] noiseReductionModes = getValueFromKeyNonNull(key);
1526
1527        if (noiseReductionModes == null) {
1528            return new int[0];
1529        }
1530
1531        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
1532        // Full device should always include OFF and FAST
1533        if (isHardwareLevelFull()) {
1534
1535            checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
1536                    modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
1537                    modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
1538        }
1539
1540        if (isHardwareLevelLimitedOrBetter()) {
1541            // FAST and HIGH_QUALITY mode must be both present or both not present
1542            List<Integer> coupledModes = Arrays.asList(new Integer[] {
1543                    CameraMetadata.NOISE_REDUCTION_MODE_FAST,
1544                    CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY
1545            });
1546            checkTrueForKey(
1547                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
1548                    containsAllOrNone(modeList, coupledModes));
1549        }
1550        return noiseReductionModes;
1551    }
1552
1553    /**
1554     * Get value of key android.control.aeCompensationStep and do the sanity check.
1555     *
1556     * @return default value if the value is null.
1557     */
1558    public Rational getAeCompensationStepChecked() {
1559        Key<Rational> key =
1560                CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
1561        Rational compensationStep = getValueFromKeyNonNull(key);
1562
1563        if (compensationStep == null) {
1564            // Return default step.
1565            return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
1566        }
1567
1568        // Legacy devices don't have a minimum step requirement
1569        if (isHardwareLevelLimitedOrBetter()) {
1570            float compensationStepF =
1571                    (float) compensationStep.getNumerator() / compensationStep.getDenominator();
1572            checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
1573        }
1574
1575        return compensationStep;
1576    }
1577
1578    /**
1579     * Get value of key android.control.aeCompensationRange and do the sanity check.
1580     *
1581     * @return default value if the value is null or malformed.
1582     */
1583    public Range<Integer> getAeCompensationRangeChecked() {
1584        Key<Range<Integer>> key =
1585                CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
1586        Range<Integer> compensationRange = getValueFromKeyNonNull(key);
1587        Rational compensationStep = getAeCompensationStepChecked();
1588        float compensationStepF = compensationStep.floatValue();
1589        final Range<Integer> DEFAULT_RANGE = Range.create(
1590                (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF),
1591                (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
1592        final Range<Integer> ZERO_RANGE = Range.create(0, 0);
1593        if (compensationRange == null) {
1594            return ZERO_RANGE;
1595        }
1596
1597        // Legacy devices don't have a minimum range requirement
1598        if (isHardwareLevelLimitedOrBetter() && !compensationRange.equals(ZERO_RANGE)) {
1599            checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
1600                    + ", actual " + compensationRange + ", compensation step " + compensationStep,
1601                   compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
1602                   compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
1603        }
1604
1605        return compensationRange;
1606    }
1607
1608    /**
1609     * Get availableVideoStabilizationModes and do the sanity check.
1610     *
1611     * @return available video stabilization modes, empty array if it is unavailable.
1612     */
1613    public int[] getAvailableVideoStabilizationModesChecked() {
1614        Key<int[]> key =
1615                CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
1616        int[] modes = getValueFromKeyNonNull(key);
1617
1618        if (modes == null) {
1619            return new int[0];
1620        }
1621
1622        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1623        checkTrueForKey(key, " All device should support OFF mode",
1624                modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
1625        checkArrayValuesInRange(key, modes,
1626                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
1627                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
1628
1629        return modes;
1630    }
1631
1632    public boolean isVideoStabilizationSupported() {
1633        Integer[] videoStabModes =
1634                CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked());
1635        return Arrays.asList(videoStabModes).contains(
1636                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
1637    }
1638
1639    /**
1640     * Get availableOpticalStabilization and do the sanity check.
1641     *
1642     * @return available optical stabilization modes, empty array if it is unavailable.
1643     */
1644    public int[] getAvailableOpticalStabilizationChecked() {
1645        Key<int[]> key =
1646                CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
1647        int[] modes = getValueFromKeyNonNull(key);
1648
1649        if (modes == null) {
1650            return new int[0];
1651        }
1652
1653        checkArrayValuesInRange(key, modes,
1654                CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
1655                CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
1656
1657        return modes;
1658    }
1659
1660    /**
1661     * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
1662     * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
1663     */
1664    public float getAvailableMaxDigitalZoomChecked() {
1665        Key<Float> key =
1666                CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
1667
1668        Float maxZoom = getValueFromKeyNonNull(key);
1669        if (maxZoom == null) {
1670            return 1.0f;
1671        }
1672
1673        checkTrueForKey(key, " max digital zoom should be no less than 1",
1674                maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
1675
1676        return maxZoom;
1677    }
1678
1679    public int[] getAvailableSceneModesChecked() {
1680        Key<int[]> key =
1681                CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
1682        int[] modes = getValueFromKeyNonNull(key);
1683
1684        if (modes == null) {
1685            return new int[0];
1686        }
1687
1688        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1689        // FACE_PRIORITY must be included if face detection is supported.
1690        if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
1691                getMaxFaceCountChecked() > 0) {
1692            checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
1693                    modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
1694        }
1695
1696        return modes;
1697    }
1698
1699    public int[] getAvailableEffectModesChecked() {
1700        Key<int[]> key =
1701                CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
1702        int[] modes = getValueFromKeyNonNull(key);
1703
1704        if (modes == null) {
1705            return new int[0];
1706        }
1707
1708        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1709        // OFF must be included.
1710        checkTrueForKey(key, " OFF must be included",
1711                modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
1712
1713        return modes;
1714    }
1715
1716    /**
1717     * Get and check the available color aberration modes
1718     *
1719     * @return the available color aberration modes
1720     */
1721    public int[] getAvailableColorAberrationModesChecked() {
1722        Key<int[]> key =
1723                CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
1724        int[] modes = getValueFromKeyNonNull(key);
1725
1726        if (modes == null) {
1727            return new int[0];
1728        }
1729
1730        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1731        checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode",
1732                modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) ||
1733                modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST));
1734
1735        if (isHardwareLevelLimitedOrBetter()) {
1736            // FAST and HIGH_QUALITY mode must be both present or both not present
1737            List<Integer> coupledModes = Arrays.asList(new Integer[] {
1738                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST,
1739                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
1740            });
1741            checkTrueForKey(
1742                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
1743                    containsAllOrNone(modeList, coupledModes));
1744        }
1745        checkElementDistinct(key, modeList);
1746        checkArrayValuesInRange(key, modes,
1747                CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
1748                CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
1749
1750        return modes;
1751    }
1752
1753    /**
1754     * Get max pipeline depth and do the sanity check.
1755     *
1756     * @return max pipeline depth, default value if it is not available.
1757     */
1758    public byte getPipelineMaxDepthChecked() {
1759        Key<Byte> key =
1760                CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
1761        Byte maxDepth = getValueFromKeyNonNull(key);
1762
1763        if (maxDepth == null) {
1764            return REQUEST_PIPELINE_MAX_DEPTH_MAX;
1765        }
1766
1767        checkTrueForKey(key, " max pipeline depth should be no larger than "
1768                + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
1769
1770        return maxDepth;
1771    }
1772
1773    /**
1774     * Get available lens shading modes.
1775     */
1776     public int[] getAvailableLensShadingModesChecked() {
1777         Key<int[]> key =
1778                 CameraCharacteristics.SHADING_AVAILABLE_MODES;
1779         int[] modes = getValueFromKeyNonNull(key);
1780         if (modes == null) {
1781             return new int[0];
1782         }
1783
1784         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1785         // FAST must be included.
1786         checkTrueForKey(key, " FAST must be included",
1787                 modeList.contains(CameraMetadata.SHADING_MODE_FAST));
1788
1789         if (isCapabilitySupported(
1790                 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) {
1791             checkTrueForKey(key, " OFF must be included for MANUAL_POST_PROCESSING devices",
1792                     modeList.contains(CameraMetadata.SHADING_MODE_OFF));
1793         }
1794         return modes;
1795     }
1796
1797     /**
1798      * Get available lens shading map modes.
1799      */
1800      public int[] getAvailableLensShadingMapModesChecked() {
1801          Key<int[]> key =
1802                  CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
1803          int[] modes = getValueFromKeyNonNull(key);
1804          if (modes == null) {
1805              return new int[0];
1806          }
1807
1808          List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
1809
1810          if (isCapabilitySupported(
1811                  CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
1812              checkTrueForKey(key, " ON must be included for RAW capability devices",
1813                      modeList.contains(CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON));
1814          }
1815          return modes;
1816      }
1817
1818
1819    /**
1820     * Get available capabilities and do the sanity check.
1821     *
1822     * @return reported available capabilities list, empty list if the value is unavailable.
1823     */
1824    public List<Integer> getAvailableCapabilitiesChecked() {
1825        Key<int[]> key =
1826                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
1827        int[] availableCaps = getValueFromKeyNonNull(key);
1828        List<Integer> capList;
1829
1830        if (availableCaps == null) {
1831            return new ArrayList<Integer>();
1832        }
1833
1834        checkArrayValuesInRange(key, availableCaps,
1835                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
1836                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO);
1837        capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
1838        return capList;
1839    }
1840
1841    /**
1842     * Determine whether the current device supports a capability or not.
1843     *
1844     * @param capability (non-negative)
1845     *
1846     * @return {@code true} if the capability is supported, {@code false} otherwise.
1847     *
1848     * @throws IllegalArgumentException if {@code capability} was negative
1849     *
1850     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
1851     */
1852    public boolean isCapabilitySupported(int capability) {
1853        if (capability < 0) {
1854            throw new IllegalArgumentException("capability must be non-negative");
1855        }
1856
1857        List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
1858
1859        return availableCapabilities.contains(capability);
1860    }
1861
1862    /**
1863     * Determine whether or not all the {@code keys} are available characteristics keys
1864     * (as in {@link CameraCharacteristics#getKeys}.
1865     *
1866     * <p>If this returns {@code true}, then querying for this key from a characteristics
1867     * object will always return a non-{@code null} value.</p>
1868     *
1869     * @param keys collection of camera characteristics keys
1870     * @return whether or not all characteristics keys are available
1871     */
1872    public final boolean areCharacteristicsKeysAvailable(
1873            Collection<Key<?>> keys) {
1874        return mCharacteristics.getKeys().containsAll(keys);
1875    }
1876
1877    /**
1878     * Determine whether or not all the {@code keys} are available result keys
1879     * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1880     *
1881     * <p>If this returns {@code true}, then querying for this key from a result
1882     * object will almost always return a non-{@code null} value.</p>
1883     *
1884     * <p>In some cases (e.g. lens shading map), the request must have additional settings
1885     * configured in order for the key to correspond to a value.</p>
1886     *
1887     * @param keys collection of capture result keys
1888     * @return whether or not all result keys are available
1889     */
1890    public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
1891        return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
1892    }
1893
1894    /**
1895     * Determine whether or not all the {@code keys} are available request keys
1896     * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1897     *
1898     * <p>If this returns {@code true}, then setting this key in the request builder
1899     * may have some effect (and if it's {@code false}, then the camera device will
1900     * definitely ignore it).</p>
1901     *
1902     * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1903     * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1904     *
1905     * @param keys collection of capture request keys
1906     * @return whether or not all result keys are available
1907     */
1908    public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
1909        return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
1910    }
1911
1912    /**
1913     * Determine whether or not all the {@code keys} are available characteristics keys
1914     * (as in {@link CameraCharacteristics#getKeys}.
1915     *
1916     * <p>If this returns {@code true}, then querying for this key from a characteristics
1917     * object will always return a non-{@code null} value.</p>
1918     *
1919     * @param keys one or more camera characteristic keys
1920     * @return whether or not all characteristics keys are available
1921     */
1922    @SafeVarargs
1923    public final boolean areKeysAvailable(Key<?>... keys) {
1924        return areCharacteristicsKeysAvailable(Arrays.asList(keys));
1925    }
1926
1927    /**
1928     * Determine whether or not all the {@code keys} are available result keys
1929     * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1930     *
1931     * <p>If this returns {@code true}, then querying for this key from a result
1932     * object will almost always return a non-{@code null} value.</p>
1933     *
1934     * <p>In some cases (e.g. lens shading map), the request must have additional settings
1935     * configured in order for the key to correspond to a value.</p>
1936     *
1937     * @param keys one or more capture result keys
1938     * @return whether or not all result keys are available
1939     */
1940    @SafeVarargs
1941    public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
1942        return areResultKeysAvailable(Arrays.asList(keys));
1943    }
1944
1945    /**
1946     * Determine whether or not all the {@code keys} are available request keys
1947     * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1948     *
1949     * <p>If this returns {@code true}, then setting this key in the request builder
1950     * may have some effect (and if it's {@code false}, then the camera device will
1951     * definitely ignore it).</p>
1952     *
1953     * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1954     * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1955     *
1956     * @param keys one or more capture request keys
1957     * @return whether or not all result keys are available
1958     */
1959    @SafeVarargs
1960    public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
1961        return areRequestKeysAvailable(Arrays.asList(keys));
1962    }
1963
1964    /*
1965     * Determine if camera device support AE lock control
1966     *
1967     * @return {@code true} if AE lock control is supported
1968     */
1969    public boolean isAeLockSupported() {
1970        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
1971    }
1972
1973    /*
1974     * Determine if camera device support AWB lock control
1975     *
1976     * @return {@code true} if AWB lock control is supported
1977     */
1978    public boolean isAwbLockSupported() {
1979        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
1980    }
1981
1982
1983    /*
1984     * Determine if camera device support manual lens shading map control
1985     *
1986     * @return {@code true} if manual lens shading map control is supported
1987     */
1988    public boolean isManualLensShadingMapSupported() {
1989        return areKeysAvailable(CaptureRequest.SHADING_MODE);
1990    }
1991
1992    /**
1993     * Determine if camera device support manual color correction control
1994     *
1995     * @return {@code true} if manual color correction control is supported
1996     */
1997    public boolean isColorCorrectionSupported() {
1998        return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
1999    }
2000
2001    /**
2002     * Determine if camera device support manual tone mapping control
2003     *
2004     * @return {@code true} if manual tone mapping control is supported
2005     */
2006    public boolean isManualToneMapSupported() {
2007        return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
2008    }
2009
2010    /**
2011     * Determine if camera device support manual color aberration control
2012     *
2013     * @return {@code true} if manual color aberration control is supported
2014     */
2015    public boolean isManualColorAberrationControlSupported() {
2016        return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
2017    }
2018
2019    /**
2020     * Determine if camera device support edge mode control
2021     *
2022     * @return {@code true} if edge mode control is supported
2023     */
2024    public boolean isEdgeModeControlSupported() {
2025        return areKeysAvailable(CaptureRequest.EDGE_MODE);
2026    }
2027
2028    /**
2029     * Determine if camera device support hot pixel mode control
2030     *
2031     * @return {@code true} if hot pixel mode control is supported
2032     */
2033    public boolean isHotPixelMapModeControlSupported() {
2034        return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
2035    }
2036
2037    /**
2038     * Determine if camera device support noise reduction mode control
2039     *
2040     * @return {@code true} if noise reduction mode control is supported
2041     */
2042    public boolean isNoiseReductionModeControlSupported() {
2043        return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
2044    }
2045
2046    /**
2047     * Get max number of output raw streams and do the basic sanity check.
2048     *
2049     * @return reported max number of raw output stream
2050     */
2051    public int getMaxNumOutputStreamsRawChecked() {
2052        Integer maxNumStreams =
2053                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
2054        if (maxNumStreams == null)
2055            return 0;
2056        return maxNumStreams;
2057    }
2058
2059    /**
2060     * Get max number of output processed streams and do the basic sanity check.
2061     *
2062     * @return reported max number of processed output stream
2063     */
2064    public int getMaxNumOutputStreamsProcessedChecked() {
2065        Integer maxNumStreams =
2066                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
2067        if (maxNumStreams == null)
2068            return 0;
2069        return maxNumStreams;
2070    }
2071
2072    /**
2073     * Get max number of output stalling processed streams and do the basic sanity check.
2074     *
2075     * @return reported max number of stalling processed output stream
2076     */
2077    public int getMaxNumOutputStreamsProcessedStallChecked() {
2078        Integer maxNumStreams =
2079                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
2080        if (maxNumStreams == null)
2081            return 0;
2082        return maxNumStreams;
2083    }
2084
2085    /**
2086     * Get lens facing and do the sanity check
2087     * @return lens facing, return default value (BACK) if value is unavailable.
2088     */
2089    public int getLensFacingChecked() {
2090        Key<Integer> key =
2091                CameraCharacteristics.LENS_FACING;
2092        Integer facing = getValueFromKeyNonNull(key);
2093
2094        if (facing == null) {
2095            return CameraCharacteristics.LENS_FACING_BACK;
2096        }
2097
2098        checkTrueForKey(key, " value is out of range ",
2099                facing >= CameraCharacteristics.LENS_FACING_FRONT &&
2100                facing <= CameraCharacteristics.LENS_FACING_BACK);
2101        return facing;
2102    }
2103
2104    /**
2105     * Get maxCaptureStall frames or default value (if value doesn't exist)
2106     * @return maxCaptureStall frames or default value.
2107     */
2108    public int getMaxCaptureStallOrDefault() {
2109        Key<Integer> key =
2110                CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL;
2111        Integer value = getValueFromKeyNonNull(key);
2112
2113        if (value == null) {
2114            return MAX_REPROCESS_MAX_CAPTURE_STALL;
2115        }
2116
2117        checkTrueForKey(key, " value is out of range ",
2118                value >= 0 &&
2119                value <= MAX_REPROCESS_MAX_CAPTURE_STALL);
2120
2121        return value;
2122    }
2123
2124    /**
2125     * Get the scaler's cropping type (center only or freeform)
2126     * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
2127     */
2128    public int getScalerCroppingTypeChecked() {
2129        Key<Integer> key =
2130                CameraCharacteristics.SCALER_CROPPING_TYPE;
2131        Integer value = getValueFromKeyNonNull(key);
2132
2133        if (value == null) {
2134            return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
2135        }
2136
2137        checkTrueForKey(key, " value is out of range ",
2138                value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
2139                value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
2140
2141        return value;
2142    }
2143
2144    /**
2145     * Check if the constrained high speed video is supported by the camera device.
2146     * The high speed FPS ranges and sizes are sanitized in
2147     * ExtendedCameraCharacteristicsTest#testConstrainedHighSpeedCapability.
2148     *
2149     * @return true if the constrained high speed video is supported, false otherwise.
2150     */
2151    public boolean isConstrainedHighSpeedVideoSupported() {
2152        List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
2153        return (availableCapabilities.contains(
2154                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO));
2155    }
2156
2157    /**
2158     * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
2159     * supported, supported high speed fps ranges and sizes are valid).
2160     *
2161     * @return true if high speed video is supported.
2162     */
2163    public boolean isHighSpeedVideoSupported() {
2164        List<Integer> sceneModes =
2165                Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
2166        if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
2167            StreamConfigurationMap config =
2168                    getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
2169            if (config == null) {
2170                return false;
2171            }
2172            Size[] availableSizes = config.getHighSpeedVideoSizes();
2173            if (availableSizes.length == 0) {
2174                return false;
2175            }
2176
2177            for (Size size : availableSizes) {
2178                Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
2179                if (availableFpsRanges.length == 0) {
2180                    return false;
2181                }
2182            }
2183
2184            return true;
2185        } else {
2186            return false;
2187        }
2188    }
2189
2190    /**
2191     * Check if depth output is supported, based on the depth capability
2192     */
2193    public boolean isDepthOutputSupported() {
2194        return isCapabilitySupported(
2195                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
2196    }
2197
2198    /**
2199     * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the
2200     * backwards-compatible capability
2201     */
2202    public boolean isColorOutputSupported() {
2203        return isCapabilitySupported(
2204                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
2205    }
2206
2207    /**
2208     * Check if optical black regions key is supported.
2209     */
2210    public boolean isOpticalBlackRegionSupported() {
2211        return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
2212    }
2213
2214    /**
2215     * Check if the dynamic black level is supported.
2216     *
2217     * <p>
2218     * Note that: This also indicates if the white level is supported, as dynamic black and white
2219     * level must be all supported or none of them is supported.
2220     * </p>
2221     */
2222    public boolean isDynamicBlackLevelSupported() {
2223        return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
2224    }
2225
2226    /**
2227     * Get the value in index for a fixed-size array from a given key.
2228     *
2229     * <p>If the camera device is incorrectly reporting values, log a warning and return
2230     * the default value instead.</p>
2231     *
2232     * @param key Key to fetch
2233     * @param defaultValue Default value to return if camera device uses invalid values
2234     * @param name Human-readable name for the array index (logging only)
2235     * @param index Array index of the subelement
2236     * @param size Expected fixed size of the array
2237     *
2238     * @return The value reported by the camera device, or the defaultValue otherwise.
2239     */
2240    private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
2241            int size) {
2242        T elementValue = getArrayElementCheckRangeNonNull(
2243                key,
2244                index,
2245                size);
2246
2247        if (elementValue == null) {
2248            failKeyCheck(key,
2249                    "had no valid " + name + " value; using default of " + defaultValue);
2250            elementValue = defaultValue;
2251        }
2252
2253        return elementValue;
2254    }
2255
2256    /**
2257     * Fetch an array sub-element from an array value given by a key.
2258     *
2259     * <p>
2260     * Prints a warning if the sub-element was null.
2261     * </p>
2262     *
2263     * <p>Use for variable-size arrays since this does not check the array size.</p>
2264     *
2265     * @param key Metadata key to look up
2266     * @param element A non-negative index value.
2267     * @return The array sub-element, or null if the checking failed.
2268     */
2269    private <T> T getArrayElementNonNull(Key<?> key, int element) {
2270        return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
2271    }
2272
2273    /**
2274     * Fetch an array sub-element from an array value given by a key.
2275     *
2276     * <p>
2277     * Prints a warning if the array size does not match the size, or if the sub-element was null.
2278     * </p>
2279     *
2280     * @param key Metadata key to look up
2281     * @param element The index in [0,size)
2282     * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
2283     * @return The array sub-element, or null if the checking failed.
2284     */
2285    private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
2286        Object array = getValueFromKeyNonNull(key);
2287
2288        if (array == null) {
2289            // Warning already printed
2290            return null;
2291        }
2292
2293        if (size != IGNORE_SIZE_CHECK) {
2294            int actualLength = Array.getLength(array);
2295            if (actualLength != size) {
2296                failKeyCheck(key,
2297                        String.format("had the wrong number of elements (%d), expected (%d)",
2298                                actualLength, size));
2299                return null;
2300            }
2301        }
2302
2303        @SuppressWarnings("unchecked")
2304        T val = (T) Array.get(array, element);
2305
2306        if (val == null) {
2307            failKeyCheck(key, "had a null element at index" + element);
2308            return null;
2309        }
2310
2311        return val;
2312    }
2313
2314    /**
2315     * Gets the key, logging warnings for null values.
2316     */
2317    public <T> T getValueFromKeyNonNull(Key<T> key) {
2318        if (key == null) {
2319            throw new IllegalArgumentException("key was null");
2320        }
2321
2322        T value = mCharacteristics.get(key);
2323
2324        if (value == null) {
2325            failKeyCheck(key, "was null");
2326        }
2327
2328        return value;
2329    }
2330
2331    private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
2332        for (int value : array) {
2333            checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
2334                    value <= max && value >= min);
2335        }
2336    }
2337
2338    private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
2339        for (byte value : array) {
2340            checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
2341                    value <= max && value >= min);
2342        }
2343    }
2344
2345    /**
2346     * Check the uniqueness of the values in a list.
2347     *
2348     * @param key The key to be checked
2349     * @param list The list contains the value of the key
2350     */
2351    private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
2352        // Each size must be distinct.
2353        Set<T> sizeSet = new HashSet<T>(list);
2354        checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
2355    }
2356
2357    private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
2358        if (!condition) {
2359            failKeyCheck(key, message);
2360        }
2361    }
2362
2363    /* Helper function to check if the coupled modes are either all present or all non-present */
2364    private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) {
2365        if (observedModes.containsAll(coupledModes)) {
2366            return true;
2367        }
2368        for (T mode : coupledModes) {
2369            if (observedModes.contains(mode)) {
2370                return false;
2371            }
2372        }
2373        return true;
2374    }
2375
2376    private <T> void failKeyCheck(Key<T> key, String message) {
2377        // TODO: Consider only warning once per key/message combination if it's too spammy.
2378        // TODO: Consider offering other options such as throwing an assertion exception
2379        String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
2380        switch (mLevel) {
2381            case WARN:
2382                Log.w(TAG, failureCause);
2383                break;
2384            case COLLECT:
2385                mCollector.addMessage(failureCause);
2386                break;
2387            case ASSERT:
2388                Assert.fail(failureCause);
2389            default:
2390                throw new UnsupportedOperationException("Unhandled level " + mLevel);
2391        }
2392    }
2393}
2394