16d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim/*
26d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * Copyright 2016 The Android Open Source Project
36d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *
46d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * Licensed under the Apache License, Version 2.0 (the "License");
56d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * you may not use this file except in compliance with the License.
66d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * You may obtain a copy of the License at
76d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *
86d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *      http://www.apache.org/licenses/LICENSE-2.0
96d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *
106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * Unless required by applicable law or agreed to in writing, software
116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * distributed under the License is distributed on an "AS IS" BASIS,
126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * See the License for the specific language governing permissions and
146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * limitations under the License.
156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim */
166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimpackage com.android.mediaframeworktest.helpers;
186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport junit.framework.Assert;
206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.graphics.ImageFormat;
226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.graphics.Rect;
236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.CameraCharacteristics;
246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.CameraCharacteristics.Key;
256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.CameraMetadata;
266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.CaptureRequest;
276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.CaptureResult;
286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.hardware.camera2.params.StreamConfigurationMap;
296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.util.Log;
306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.util.Range;
316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.util.Rational;
326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport android.util.Size;
336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.lang.reflect.Array;
356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.ArrayList;
366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.Arrays;
376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.Collection;
386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.HashMap;
396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.HashSet;
406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.List;
416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport java.util.Set;
426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimimport static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim/**
466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * Helpers to get common static info out of the camera.
476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *
486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p>
496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim *
506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * <p>Attempt to be durable against the camera device having bad or missing metadata
516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * by providing reasonable defaults and logging warnings when that happens.</p>
526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim */
536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim/**
546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * (non-Javadoc)
556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim * @see android.hardware.camera2.cts.helpers.StaticMetadata
566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim */
576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kimpublic class StaticMetadata {
586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final String TAG = "StaticMetadata";
606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int IGNORE_SIZE_CHECK = -1;
616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800;
666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private static final int MAX_REPROCESS_MAX_CAPTURE_STALL = 4;
736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    // TODO: Consider making this work across any metadata object, not just camera characteristics
756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private final CameraCharacteristics mCharacteristics;
766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private final CheckLevel mLevel;
776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private final CameraErrorCollector mCollector;
786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    // Index with android.control.aeMode
806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public static final String[] AE_MODE_NAMES = new String[] {
816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_MODE_OFF",
826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_MODE_ON",
836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_MODE_ON_AUTO_FLASH",
846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_MODE_ON_ALWAYS_FLASH",
856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_MODE_ON_AUTO_FLASH_REDEYE"
866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    };
876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    // Index with android.control.afMode
896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public static final String[] AF_MODE_NAMES = new String[] {
906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_OFF",
916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_AUTO",
926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_MACRO",
936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_CONTINUOUS_VIDEO",
946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_CONTINUOUS_PICTURE",
956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_MODE_EDOF"
966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    };
976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    // Index with android.control.aeState
996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public static final String[] AE_STATE_NAMES = new String[] {
1006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_INACTIVE",
1016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_SEARCHING",
1026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_CONVERGED",
1036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_LOCKED",
1046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_FLASH_REQUIRED",
1056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AE_STATE_PRECAPTURE"
1066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    };
1076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    // Index with android.control.afState
1096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public static final String[] AF_STATE_NAMES = new String[] {
1106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_INACTIVE",
1116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_PASSIVE_SCAN",
1126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_PASSIVE_FOCUSED",
1136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_ACTIVE_SCAN",
1146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_FOCUSED_LOCKED",
1156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_NOT_FOCUSED_LOCKED",
1166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        "AF_STATE_PASSIVE_UNFOCUSED"
1176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    };
1186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public enum CheckLevel {
1206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /** Only log warnings for metadata check failures. Execution continues. */
1216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        WARN,
1226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /**
1236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         * Use ErrorCollector to collect the metadata check failures, Execution
1246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         * continues.
1256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         */
1266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        COLLECT,
1276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /** Assert the metadata check failures. Execution aborts. */
1286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        ASSERT
1296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
1306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
1326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Construct a new StaticMetadata object.
1336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *<p> Default constructor, only log warnings for the static metadata check failures</p>
1356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param characteristics static info for a camera
1376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @throws IllegalArgumentException if characteristics was null
1386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
1396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public StaticMetadata(CameraCharacteristics characteristics) {
1406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        this(characteristics, CheckLevel.WARN, /*collector*/null);
1416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
1426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
1446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Construct a new StaticMetadata object with {@link CameraErrorCollector}.
1456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
1466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
1476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * ignored, otherwise, it will be used to log the check failures.
1486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
1496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param characteristics static info for a camera
1516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
1526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @throws IllegalArgumentException if characteristics or collector was null.
1536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
1546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) {
1556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        this(characteristics, CheckLevel.COLLECT, collector);
1566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
1576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
1596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Construct a new StaticMetadata object with {@link CheckLevel} and
1606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * {@link CameraErrorCollector}.
1616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
1626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
1636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * ignored, otherwise, it will be used to log the check failures.
1646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
1656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param characteristics static info for a camera
1676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param level The {@link CheckLevel} of this StaticMetadata
1686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
1696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @throws IllegalArgumentException if characteristics was null or level was
1706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         {@link CheckLevel.COLLECT} but collector was null.
1716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
1726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level,
1736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            CameraErrorCollector collector) {
1746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (characteristics == null) {
1756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            throw new IllegalArgumentException("characteristics was null");
1766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
1776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (level == CheckLevel.COLLECT && collector == null) {
1786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            throw new IllegalArgumentException("collector must valid when COLLECT level is set");
1796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
1806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        mCharacteristics = characteristics;
1826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        mLevel = level;
1836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        mCollector = collector;
1846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
1856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
1876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the CameraCharacteristics associated with this StaticMetadata.
1886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return A non-null CameraCharacteristics object
1906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
1916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public CameraCharacteristics getCharacteristics() {
1926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return mCharacteristics;
1936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
1946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
1966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the hardware level reported by android.info.supportedHardwareLevel
1976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}.
1986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
1996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera device is not reporting the hardwareLevel, this
2006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * will cause the test to fail.</p>
2016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
2036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHardwareLevelFull() {
2056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
2066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the hardware level reported by android.info.supportedHardwareLevel
2106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Return the supported hardware level of the device, or fail if no value is reported.
2116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return the supported hardware level as a constant defined for
2136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *      {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
2146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getHardwareLevelChecked() {
2166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer hwLevel = getValueFromKeyNonNull(
2176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
2186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hwLevel == null) {
2196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            Assert.fail("No supported hardware level reported.");
2206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
2216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return hwLevel;
2226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the hardware level reported by android.info.supportedHardwareLevel
2266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}.
2276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera device is not reporting the hardwareLevel, this
2296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * will cause the test to fail.</p>
2306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
2326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHardwareLevelLegacy() {
2346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
2356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the per frame control is supported by the camera device.
2396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if per frame control is supported, {@code false} otherwise.
2416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isPerFrameControlSupported() {
2436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
2446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum number of frames to wait for a request settings being applied
2486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency
2506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control
2516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         a positive int otherwise
2526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSyncMaxLatency() {
2546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY);
2556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (value == null) {
2566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN;
2576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
2586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return value;
2596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the hardware level reported by android.info.supportedHardwareLevel
2636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
2646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera device is incorrectly reporting the hardwareLevel, this
2666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * will always return {@code true}.</p>
2676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise.
2696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHardwareLevelLimited() {
2716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
2726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
2756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel}
2766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
2776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera device is incorrectly reporting the hardwareLevel, this
2796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * will always return {@code false}.</p>
2806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
2816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return
2826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *          {@code true} if the device is {@code LIMITED} or {@code FULL},
2836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *          {@code false} otherwise (i.e. LEGACY).
2846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
2856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHardwareLevelLimitedOrBetter() {
2866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer hwLevel = getValueFromKeyNonNull(
2876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
2886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hwLevel == null) {
2906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return false;
2916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
2926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Normal. Device could be limited.
2946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int hwLevelInt = hwLevel;
2956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
2966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
2976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
2986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
2996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
3006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum number of partial result a request can expect
3016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
3026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return 1 if partial result is not supported.
3036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         a integer value larger than 1 if partial result is supported.
3046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
3056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getPartialResultCount() {
3066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
3076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (value == null) {
3086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Optional key. Default value is 1 if key is missing.
3096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 1;
3106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
3116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return value;
3126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
3136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
3156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the exposure time value and clamp to the range if needed.
3166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
3176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param exposure Input exposure time value to check.
3186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Exposure value in the legal range.
3196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
3206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getExposureClampToRange(long exposure) {
3216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE);
3226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE);
3236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) {
3246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
3256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format(
3266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "Min value %d is too large, set to maximal legal value %d",
3276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST));
3286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST;
3296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
3306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) {
3316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
3326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format(
3336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "Max value %d is too small, set to minimal legal value %d",
3346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST));
3356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST;
3366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
3376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return Math.max(minExposure, Math.min(maxExposure, exposure));
3396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
3406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
3426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if the camera device support focuser.
3436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
3446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return true if camera device support focuser, false otherwise.
3456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
3466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean hasFocuser() {
3476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
3486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
3496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return (getMinimumFocusDistanceChecked() > 0);
3506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        } else {
3516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Check available AF modes
3526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            int[] availableAfModes = mCharacteristics.get(
3536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
3546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (availableAfModes == null) {
3566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return false;
3576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
3586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
3606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            boolean hasFocuser = false;
3616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            loop: for (int mode : availableAfModes) {
3626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                switch (mode) {
3636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    case CameraMetadata.CONTROL_AF_MODE_AUTO:
3646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
3656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
3666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    case CameraMetadata.CONTROL_AF_MODE_MACRO:
3676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        hasFocuser = true;
3686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        break loop;
3696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                }
3706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
3716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return hasFocuser;
3736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
3746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
3756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
3776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if the camera device has flash unit.
3786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return true if flash unit is available, false otherwise.
3796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
3806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean hasFlash() {
3816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getFlashInfoChecked();
3826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
3836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
3856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get minimum focus distance.
3866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
3876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return minimum focus distance, 0 if minimum focus distance is invalid.
3886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
3896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public float getMinimumFocusDistanceChecked() {
3906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE;
3916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Float minFocusDistance;
3926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
3936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /**
3946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable
3956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         *   devices; optional for all other devices.
3966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         */
3976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelFull() || isCapabilitySupported(
3986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
3996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minFocusDistance = getValueFromKeyNonNull(key);
4006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        } else {
4016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minFocusDistance = mCharacteristics.get(key);
4026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (minFocusDistance == null) {
4056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0.0f;
4066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " minFocusDistance value shouldn't be negative",
4096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                minFocusDistance >= 0);
4106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (minFocusDistance < 0) {
4116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minFocusDistance = 0.0f;
4126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return minFocusDistance;
4156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
4166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
4186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get focusDistanceCalibration.
4196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
4206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return focusDistanceCalibration, UNCALIBRATED if value is invalid.
4216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
4226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getFocusDistanceCalibrationChecked() {
4236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
4246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer calibration = getValueFromKeyNonNull(key);
4256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (calibration == null) {
4276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
4286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " value is out of range" ,
4316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED &&
4326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED);
4336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return calibration;
4356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
4366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
4386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max AE regions and do sanity check.
4396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
4406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return AE max regions supported by the camera device
4416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
4426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getAeMaxRegionsChecked() {
4436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
4446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (regionCount == null) {
4456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
4466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return regionCount;
4486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
4496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
4516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max AWB regions and do sanity check.
4526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
4536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return AWB max regions supported by the camera device
4546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
4556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getAwbMaxRegionsChecked() {
4566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
4576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (regionCount == null) {
4586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
4596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return regionCount;
4616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
4626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
4646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max AF regions and do sanity check.
4656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
4666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return AF max regions supported by the camera device
4676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
4686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getAfMaxRegionsChecked() {
4696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
4706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (regionCount == null) {
4716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
4726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return regionCount;
4746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
4756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
4766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the available anti-banding modes.
4776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
4786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The array contains available anti-banding modes.
4796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
4806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAeAvailableAntiBandingModesChecked() {
4816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
4826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
4836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
4846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean foundAuto = false;
4856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean found50Hz = false;
4866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean found60Hz = false;
4876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int mode : modes) {
4886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, "mode value " + mode + " is out if range",
4896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF ||
4906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
4916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) {
4926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                foundAuto = true;
4936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ) {
4946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                found50Hz = true;
4956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ) {
4966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                found60Hz = true;
4976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
4986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
4996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Must contain AUTO mode or one of 50/60Hz mode.
5006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Either AUTO mode or both 50HZ/60HZ mode should present",
5016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                foundAuto || (found50Hz && found60Hz));
5026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
5046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
5076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if the antibanding OFF mode is supported.
5086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
5096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return true if antibanding OFF mode is supported, false otherwise.
5106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
5116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isAntiBandingOffModeSupported() {
5126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> antiBandingModes =
5136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
5146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
5166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Boolean getFlashInfoChecked() {
5196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
5206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Boolean hasFlash = getValueFromKeyNonNull(key);
5216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // In case the failOnKey only gives warning.
5236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hasFlash == null) {
5246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return false;
5256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
5266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return hasFlash;
5286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableTestPatternModesChecked() {
5316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
5326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
5336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
5346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
5366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
5376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
5386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF;
5406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer[] boxedModes = CameraTestUtils.toObject(modes);
5416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " value must contain OFF mode",
5426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Arrays.asList(boxedModes).contains(expectValue));
5436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
5456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
5486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available thumbnail sizes and do the sanity check.
5496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
5506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The array of available thumbnail sizes
5516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
5526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size[] getAvailableThumbnailSizesChecked() {
5536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES;
5546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size[] sizes = getValueFromKeyNonNull(key);
5556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        final List<Size> sizeList = Arrays.asList(sizes);
5566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Size must contain (0, 0).
5586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0)));
5596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Each size must be distinct.
5616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, sizeList);
5626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Must be sorted in ascending order by area, by width if areas are same.
5646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Size> orderedSizes =
5656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true);
5666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString()
5676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList));
5686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations
5706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // implementation see b/12958122.
5716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return sizes;
5736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
5766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available focal lengths and do the sanity check.
5776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
5786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The array of available focal lengths
5796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
5806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public float[] getAvailableFocalLengthsChecked() {
5816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
5826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        float[] focalLengths = getValueFromKeyNonNull(key);
5836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1);
5856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int i = 0; i < focalLengths.length; i++) {
5876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key,
5886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]),
5896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    focalLengths[i] > 0);
5906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
5916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths)));
5926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return focalLengths;
5946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
5956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
5966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
5976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available apertures and do the sanity check.
5986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
5996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The non-null array of available apertures
6006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
6016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public float[] getAvailableAperturesChecked() {
6026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES;
6036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        float[] apertures = getValueFromKeyNonNull(key);
6046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1);
6066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int i = 0; i < apertures.length; i++) {
6086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key,
6096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format("apertures[%d] %f should be positive.", i, apertures[i]),
6106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    apertures[i] > 0);
6116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures)));
6136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return apertures;
6156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
6166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
6186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check the available hot pixel map modes.
6196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
6206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return the available hot pixel map modes
6216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
6226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableHotPixelModesChecked() {
6236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
6246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
6256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
6276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
6286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
6316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelFull()) {
6326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
6336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
6346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
6376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // FAST and HIGH_QUALITY mode must be both present or both not present
6386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            List<Integer> coupledModes = Arrays.asList(new Integer[] {
6396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.HOT_PIXEL_MODE_FAST,
6406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY
6416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            });
6426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(
6436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
6446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    containsAllOrNone(modeList, coupledModes));
6456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, modeList);
6476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
6486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
6496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
6516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
6526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
6546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check available face detection modes.
6556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
6566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The non-null array of available face detection modes
6576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
6586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableFaceDetectModesChecked() {
6596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
6606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
6616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
6636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
6646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
6676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Array should contain OFF mode",
6686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF));
6696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, modeList);
6706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF,
6716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
6726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
6746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
6756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
6776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check max face detected count.
6786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
6796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return max number of faces that can be detected
6806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
6816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxFaceCountChecked() {
6826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT;
6836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer count = getValueFromKeyNonNull(key);
6846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (count == null) {
6866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
6876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
6886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> faceDetectModes =
6906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked()));
6916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) &&
6926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                faceDetectModes.size() == 1) {
6936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " value must be 0 if only OFF mode is supported in "
6946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + "availableFaceDetectionModes", count == 0);
6956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        } else {
6966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST;
6976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
6986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces.
6996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (isHardwareLevelLegacy()) {
7006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                maxFaceCountAtLeast = 1;
7016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
7026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE"
7036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + "or FULL is also supported in availableFaceDetectionModes",
7046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    count >= maxFaceCountAtLeast);
7056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return count;
7086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
7096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
7116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check the available tone map modes.
7126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
7136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return the available tone map modes
7146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
7156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableToneMapModesChecked() {
7166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES;
7176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
7186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
7206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
7216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
7246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " Camera devices must always support FAST mode",
7256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
7266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Qualification check for MANUAL_POSTPROCESSING capability is in
7276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // StaticMetadataTest#testCapabilities
7286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
7306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // FAST and HIGH_QUALITY mode must be both present or both not present
7316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            List<Integer> coupledModes = Arrays.asList(new Integer[] {
7326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.TONEMAP_MODE_FAST,
7336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.TONEMAP_MODE_HIGH_QUALITY
7346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            });
7356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(
7366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
7376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    containsAllOrNone(modeList, coupledModes));
7386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, modeList);
7406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
7416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.TONEMAP_MODE_PRESET_CURVE);
7426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
7446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
7456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
7476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check max tonemap curve point.
7486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
7496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Max tonemap curve points.
7506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
7516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxTonemapCurvePointChecked() {
7526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS;
7536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer count = getValueFromKeyNonNull(key);
7546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList =
7556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked()));
7566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean tonemapCurveOutputSupported =
7576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) ||
7586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.TONEMAP_MODE_GAMMA_VALUE) ||
7596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.TONEMAP_MODE_PRESET_CURVE);
7606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (count == null) {
7626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (tonemapCurveOutputSupported) {
7636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Assert.fail("Tonemap curve output is supported but MAX_CURVE_POINTS is null");
7646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
7656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
7666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (tonemapCurveOutputSupported) {
7696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, "Tonemap curve output supported camera device must support "
7706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + "maxCurvePoints >= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST,
7716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST);
7726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return count;
7756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
7766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
7786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check pixel array size.
7796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
7806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size getPixelArraySizeChecked() {
7816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE;
7826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size pixelArray = getValueFromKeyNonNull(key);
7836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (pixelArray == null) {
7846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new Size(0, 0);
7856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
7866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return pixelArray;
7886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
7896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
7916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check pre-correction active array size.
7926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
7936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Rect getPreCorrectedActiveArraySizeChecked() {
7946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Rect> key = CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE;
7956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Rect activeArray = getValueFromKeyNonNull(key);
7966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
7976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (activeArray == null) {
7986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new Rect(0, 0, 0, 0);
7996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
8006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size pixelArraySize = getPixelArraySizeChecked();
8026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
8036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "values width/height are invalid",
8046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                activeArray.width() <= pixelArraySize.getWidth() &&
8056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                activeArray.height() <= pixelArraySize.getHeight());
8066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return activeArray;
8086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
8096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
8116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check active array size.
8126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
8136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Rect getActiveArraySizeChecked() {
8146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE;
8156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Rect activeArray = getValueFromKeyNonNull(key);
8166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (activeArray == null) {
8186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new Rect(0, 0, 0, 0);
8196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
8206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size pixelArraySize = getPixelArraySizeChecked();
8226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
8236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "values width/height are invalid",
8246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                activeArray.width() <= pixelArraySize.getWidth() &&
8256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                activeArray.height() <= pixelArraySize.getHeight());
8266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return activeArray;
8286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
8296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
8316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the dimensions to use for RAW16 buffers.
8326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
8336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size getRawDimensChecked() throws Exception {
8346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size[] targetCaptureSizes = getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
8356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        StaticMetadata.StreamDirection.Output);
8366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Assert.assertTrue("No capture sizes available for RAW format!",
8376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                targetCaptureSizes.length != 0);
8386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Rect activeArray = getPreCorrectedActiveArraySizeChecked();
8396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size preCorrectionActiveArraySize =
8406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                new Size(activeArray.width(), activeArray.height());
8416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size pixelArraySize = getPixelArraySizeChecked();
8426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Assert.assertTrue("Missing pre-correction active array size", activeArray.width() > 0 &&
8436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                activeArray.height() > 0);
8446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Assert.assertTrue("Missing pixel array size", pixelArraySize.getWidth() > 0 &&
8456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                pixelArraySize.getHeight() > 0);
8466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size[] allowedArraySizes = new Size[] { preCorrectionActiveArraySize,
8476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                pixelArraySize };
8486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return assertArrayContainsAnyOf("Available sizes for RAW format" +
8496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                " must include either the pre-corrected active array size, or the full " +
8506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                "pixel array size", targetCaptureSizes, allowedArraySizes);
8516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
8526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
8546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the sensitivity value and clamp to the range if needed.
8556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
8566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param sensitivity Input sensitivity value to check.
8576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Sensitivity value in legal range.
8586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
8596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSensitivityClampToRange(int sensitivity) {
8606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE);
8616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE);
8626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) {
8636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
8646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format(
8656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "Min value %d is too large, set to maximal legal value %d",
8666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST));
8676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST;
8686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
8696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) {
8706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
8716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    String.format(
8726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "Max value %d is too small, set to minimal legal value %d",
8736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST));
8746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST;
8756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
8766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity));
8786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
8796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
8816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get maxAnalogSensitivity for a camera device.
8826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
8836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * This is only available for FULL capability device, return 0 if it is unavailable.
8846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
8856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
8866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return maxAnalogSensitivity, 0 if it is not available.
8876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
8886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxAnalogSensitivityChecked() {
8896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
8916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer maxAnalogsensitivity = mCharacteristics.get(key);
8926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxAnalogsensitivity == null) {
8936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (isHardwareLevelFull()) {
8946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Assert.fail("Full device should report max analog sensitivity");
8956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
8966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
8976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
8986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
8996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int minSensitivity = getSensitivityMinimumOrDefault();
9006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int maxSensitivity = getSensitivityMaximumOrDefault();
9016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
9026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                + " should be no larger than max sensitivity " + maxSensitivity,
9036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                maxAnalogsensitivity <= maxSensitivity);
9046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
9056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                + " should be larger than min sensitivity " + maxSensitivity,
9066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                maxAnalogsensitivity > minSensitivity);
9076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxAnalogsensitivity;
9096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
9106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
9126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get hyperfocalDistance and do the sanity check.
9136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
9146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Note that, this tag is optional, will return -1 if this tag is not
9156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * available.
9166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
9176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return hyperfocalDistance of this device, -1 if this tag is not available.
9196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
9206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public float getHyperfocalDistanceChecked() {
9216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
9226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Float hyperfocalDistance = getValueFromKeyNonNull(key);
9236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hyperfocalDistance == null) {
9246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return -1;
9256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
9266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hasFocuser()) {
9286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            float minFocusDistance = getMinimumFocusDistanceChecked();
9296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of"
9306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f,
9316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    minFocusDistance),
9326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance);
9336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
9346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return hyperfocalDistance;
9366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
9376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
9396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
9406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
9426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead, which is the largest minimum value required to be supported
9436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * by all camera devices.</p>
9446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
9466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
9476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSensitivityMinimumOrDefault() {
9486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST);
9496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
9506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
9526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
9536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
9556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead.</p>
9566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param defaultValue Value to return if no legal value is available
9586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
9596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
9606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSensitivityMinimumOrDefault(int defaultValue) {
9616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer> range = getValueFromKeyNonNull(
9626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
9636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (range == null) {
9646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
9656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "had no valid minimum value; using default of " + defaultValue);
9666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return defaultValue;
9676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
9686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return range.getLower();
9696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
9706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
9726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
9736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
9756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead, which is the smallest maximum value required to be supported
9766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * by all camera devices.</p>
9776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
9796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
9806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSensitivityMaximumOrDefault() {
9816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST);
9826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
9836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
9846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
9856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
9866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
9886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead.</p>
9896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
9906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param defaultValue Value to return if no legal value is available
9916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
9926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
9936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getSensitivityMaximumOrDefault(int defaultValue) {
9946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer> range = getValueFromKeyNonNull(
9956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
9966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (range == null) {
9976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
9986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "had no valid maximum value; using default of " + defaultValue);
9996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return defaultValue;
10006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
10016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return range.getUpper();
10026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
10036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
10056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
10066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
10086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead.</p>
10096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param defaultValue Value to return if no legal value is available
10116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
10126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
10136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getExposureMinimumOrDefault(long defaultValue) {
10146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Long> range = getValueFromKeyNonNull(
10156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
10166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (range == null) {
10176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
10186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "had no valid minimum value; using default of " + defaultValue);
10196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return defaultValue;
10206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
10216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return range.getLower();
10226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
10236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
10256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
10266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
10286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead, which is the largest minimum value required to be supported
10296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * by all camera devices.</p>
10306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
10326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
10336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getExposureMinimumOrDefault() {
10346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST);
10356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
10366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
10386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
10396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
10416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead.</p>
10426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param defaultValue Value to return if no legal value is available
10446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
10456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
10466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getExposureMaximumOrDefault(long defaultValue) {
10476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Long> range = getValueFromKeyNonNull(
10486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
10496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (range == null) {
10506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
10516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "had no valid maximum value; using default of " + defaultValue);
10526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return defaultValue;
10536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
10546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return range.getUpper();
10556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
10566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
10586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
10596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera is incorrectly reporting values, log a warning and return
10616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead, which is the smallest maximum value required to be supported
10626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * by all camera devices.</p>
10636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device or the defaultValue otherwise.
10656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
10666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getExposureMaximumOrDefault() {
10676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST);
10686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
10696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
10716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * get android.control.availableModes and do the sanity check.
10726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
10736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return available control modes.
10746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
10756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableControlModesChecked() {
10766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> modesKey = CameraCharacteristics.CONTROL_AVAILABLE_MODES;
10776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(modesKey);
10786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
10796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            modes = new int[0];
10806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
10816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
10836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
10846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // All camera device must support AUTO
10866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain AUTO mode",
10876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.CONTROL_MODE_AUTO));
10886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
10896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean isAeOffSupported =  Arrays.asList(
10906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.toObject(getAeAvailableModesChecked())).contains(
10916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        CameraMetadata.CONTROL_AE_MODE_OFF);
10926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean isAfOffSupported =  Arrays.asList(
10936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.toObject(getAfAvailableModesChecked())).contains(
10946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        CameraMetadata.CONTROL_AF_MODE_OFF);
10956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean isAwbOffSupported =  Arrays.asList(
10966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.toObject(getAwbAvailableModesChecked())).contains(
10976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        CameraMetadata.CONTROL_AWB_MODE_OFF);
10986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isAeOffSupported && isAfOffSupported && isAwbOffSupported) {
10996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // 3A OFF controls are supported, OFF mode must be supported here.
11006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain OFF mode",
11016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_MODE_OFF));
11026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isSceneModeSupported()) {
11056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain"
11066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + " USE_SCENE_MODE",
11076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_MODE_USE_SCENE_MODE));
11086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
11116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
11126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isSceneModeSupported() {
11146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> availableSceneModes = Arrays.asList(
11156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.toObject(getAvailableSceneModesChecked()));
11166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (availableSceneModes.isEmpty()) {
11186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return false;
11196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // If sceneMode is not supported, camera device will contain single entry: DISABLED.
11226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return availableSceneModes.size() > 1 ||
11236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                !availableSceneModes.contains(CameraMetadata.CONTROL_SCENE_MODE_DISABLED);
11246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
11256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
11276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get aeAvailableModes and do the sanity check.
11286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
11296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>Depending on the check level this class has, for WAR or COLLECT levels,
11306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
11316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * have to abort the execution even the aeMode list is invalid.</p>
11326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return AE available modes
11336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
11346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAeAvailableModesChecked() {
11356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
11366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(modesKey);
11376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
11386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            modes = new int[0];
11396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = new ArrayList<Integer>();
11416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int mode : modes) {
1142e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            // Skip vendor-added modes
1143e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            if (mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
1144e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He                modeList.add(mode);
1145e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            }
1146e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        }
1147e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
1148e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        modes = new int[modeList.size()];
1149e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        for (int i = 0; i < modeList.size(); i++) {
1150e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            modes[i] = modeList.get(i);
11516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
1152e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He
11536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
11546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // All camera device must support ON
11566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
11576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
11586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
11606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
11616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Boolean hasFlash = getValueFromKeyNonNull(flashKey);
11626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hasFlash == null) {
11636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            hasFlash = false;
11646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hasFlash) {
11666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            boolean flashModeConsistentWithFlash =
11676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
11686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
11696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(modesKey,
11706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and  when flash is" +
11716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "available", flashModeConsistentWithFlash);
11726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        } else {
11736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            boolean flashModeConsistentWithoutFlash =
11746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
11756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
11766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
11776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(modesKey,
11786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
11796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "ON_AUTO_FLASH_REDEYE when flash is unavailable",
11806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    flashModeConsistentWithoutFlash);
11816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // FULL mode camera devices always support OFF mode.
11846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        boolean condition =
11856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
11866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
11876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Boundary check.
11896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int mode : modes) {
11906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
11916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    mode >= CameraMetadata.CONTROL_AE_MODE_OFF
11926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
11936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
11946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
11966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
11976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
11986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
11996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available AWB modes and do the sanity check.
12006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
12016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return array that contains available AWB modes, empty array if awbAvailableModes is
12026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * unavailable.
12036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
12046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAwbAvailableModesChecked() {
12056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
12066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
12076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] awbModes = getValueFromKeyNonNull(key);
12086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (awbModes == null) {
12106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
12116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
12126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
12146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " All camera devices must support AUTO mode",
12156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
12166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelFull()) {
12176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " Full capability camera devices must support OFF mode",
12186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
12196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
12206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return awbModes;
12226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
12236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
12256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available AF modes and do the sanity check.
12266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
12276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return array that contains available AF modes, empty array if afAvailableModes is
12286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * unavailable.
12296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
12306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAfAvailableModesChecked() {
12316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
12326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
12336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] afModes = getValueFromKeyNonNull(key);
12346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (afModes == null) {
12366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
12376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
12386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1239e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        List<Integer> modesList = new ArrayList<Integer>();
1240e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        for (int afMode : afModes) {
1241e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            // Skip vendor-added AF modes
1242e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            if (afMode > CameraCharacteristics.CONTROL_AF_MODE_EDOF) continue;
1243e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            modesList.add(afMode);
1244e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        }
1245e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        afModes = new int[modesList.size()];
1246e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        for (int i = 0; i < modesList.size(); i++) {
1247e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            afModes[i] = modesList.get(i);
1248e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        }
1249e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He
12506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
12516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Some LEGACY mode devices do not support AF OFF
12526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " All camera devices must support OFF mode",
12536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
12546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
12556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (hasFocuser()) {
12566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
12576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
12586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
12596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return afModes;
12616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
12626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
12646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get supported raw output sizes and do the check.
12656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
12666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Empty size array if raw output is not supported
12676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
12686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size[] getRawOutputSizesChecked() {
12696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
12706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                StreamDirection.Output);
12716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
12726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
12746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get supported jpeg output sizes and do the check.
12756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
12766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Empty size array if jpeg output is not supported
12776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
12786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size[] getJpegOutputSizesChecked() {
12796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
12806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                StreamDirection.Output);
12816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
12826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
12846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Used to determine the stream direction for various helpers that look up
12856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * format or size information.
12866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
12876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public enum StreamDirection {
12886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
12896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Output,
12906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
12916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Input
12926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
12936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
12946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
12956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available formats for a given direction.
12966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
12976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param direction The stream direction, input or output.
12986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The formats of the given direction, empty array if no available format is found.
12996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
13006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableFormats(StreamDirection direction) {
13016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<StreamConfigurationMap> key =
13026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
13036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        StreamConfigurationMap config = getValueFromKeyNonNull(key);
13046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (config == null) {
13066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
13076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
13086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        switch (direction) {
13106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case Output:
13116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return config.getOutputFormats();
13126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case Input:
13136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return config.getInputFormats();
13146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            default:
13156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                throw new IllegalArgumentException("direction must be output or input");
13166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
13176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
13186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
13206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get valid output formats for a given input format.
13216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
13226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param inputFormat The input format used to produce the output images.
13236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The output formats for the given input format, empty array if
13246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         no available format is found.
13256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
13266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getValidOutputFormatsForInput(int inputFormat) {
13276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<StreamConfigurationMap> key =
13286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
13296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        StreamConfigurationMap config = getValueFromKeyNonNull(key);
13306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (config == null) {
13326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
13336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
13346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return config.getValidOutputFormatsForInput(inputFormat);
13366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
13376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
13396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available sizes for given format and direction.
13406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
13416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param format The format for the requested size array.
13426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param direction The stream direction, input or output.
13436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The sizes of the given format, empty array if no available size is found.
13446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
13456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
13466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getAvailableSizesForFormatChecked(format, direction,
13476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                /*fastSizes*/true, /*slowSizes*/true);
13486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
13496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
13516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available sizes for given format and direction, and whether to limit to slow or fast
13526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * resolutions.
13536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
13546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param format The format for the requested size array.
13556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param direction The stream direction, input or output.
13566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param fastSizes whether to include getOutputSizes() sizes (generally faster)
13576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower)
13586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The sizes of the given format, empty array if no available size is found.
13596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
13606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction,
13616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            boolean fastSizes, boolean slowSizes) {
13626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<StreamConfigurationMap> key =
13636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
13646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        StreamConfigurationMap config = getValueFromKeyNonNull(key);
13656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (config == null) {
13676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new Size[0];
13686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
13696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Size[] sizes = null;
13716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        switch (direction) {
13736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case Output:
13746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Size[] fastSizeList = null;
13756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Size[] slowSizeList = null;
13766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                if (fastSizes) {
13776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    fastSizeList = config.getOutputSizes(format);
13786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                }
13796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                if (slowSizes) {
13806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    slowSizeList = config.getHighResolutionOutputSizes(format);
13816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                }
13826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                if (fastSizeList != null && slowSizeList != null) {
13836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    sizes = new Size[slowSizeList.length + fastSizeList.length];
13846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length);
13856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length);
13866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                } else if (fastSizeList != null) {
13876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    sizes = fastSizeList;
13886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                } else if (slowSizeList != null) {
13896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    sizes = slowSizeList;
13906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                }
13916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                break;
13926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case Input:
13936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                sizes = config.getInputSizes(format);
13946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                break;
13956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            default:
13966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                throw new IllegalArgumentException("direction must be output or input");
13976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
13986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
13996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (sizes == null) {
14006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            sizes = new Size[0];
14016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return sizes;
14046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
14056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
14076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available AE target fps ranges.
14086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
14096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
14106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
14116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    @SuppressWarnings("raw")
14126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
14136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Range<Integer>[]> key =
14146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
14156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
14166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (fpsRanges == null) {
14186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new Range[0];
14196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
14226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // in case the above check fails.
14236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int fpsRangeLength = fpsRanges.length;
14246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int minFps, maxFps;
14256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        long maxFrameDuration = getMaxFrameDurationChecked();
14266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int i = 0; i < fpsRangeLength; i += 1) {
14276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            minFps = fpsRanges[i].getLower();
14286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            maxFps = fpsRanges[i].getUpper();
14296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " min fps must be no larger than max fps!",
14306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    minFps > 0 && maxFps >= minFps);
14316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            long maxDuration = (long) (1e9 / minFps);
14326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, String.format(
14336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
14346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
14356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return fpsRanges;
14376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
14386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
1439e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He    public static String getAeModeName(int aeMode) {
1440e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        return (aeMode >= AE_MODE_NAMES.length) ? String.format("VENDOR_AE_MODE_%d", aeMode) :
1441e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            AE_MODE_NAMES[aeMode];
1442e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He    }
1443e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He
1444e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He    public static String getAfModeName(int afMode) {
1445e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He        return (afMode >= AF_MODE_NAMES.length) ? String.format("VENDOR_AF_MODE_%d", afMode) :
1446e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He            AF_MODE_NAMES[afMode];
1447e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He    }
1448e256bc9f66c6812f02326432ed22f7adca47cc9cYuchen He
14496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
14506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the highest supported target FPS range.
14516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS.
14526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
14536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Range<Integer> getAeMaxTargetFpsRange() {
14546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer>[] fpsRanges = getAeAvailableTargetFpsRangesChecked();
14556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer> targetRange = fpsRanges[0];
14576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Assume unsorted list of target FPS ranges, so use two passes, first maximize min FPS
14586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (Range<Integer> candidateRange : fpsRanges) {
14596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (candidateRange.getLower() > targetRange.getLower()) {
14606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                targetRange = candidateRange;
14616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
14626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Then maximize max FPS while not lowering min FPS
14646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (Range<Integer> candidateRange : fpsRanges) {
14656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (candidateRange.getLower() >= targetRange.getLower() &&
14666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    candidateRange.getUpper() > targetRange.getUpper()) {
14676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                targetRange = candidateRange;
14686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
14696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return targetRange;
14716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
14726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
14746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max frame duration.
14756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
14766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return 0 if maxFrameDuration is null
14776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
14786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public long getMaxFrameDurationChecked() {
14796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Long> key =
14806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
14816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Long maxDuration = getValueFromKeyNonNull(key);
14826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxDuration == null) {
14846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
14856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
14866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxDuration;
14886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
14896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
14916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available minimal frame durations for a given format.
14926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
14936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param format One of the format from {@link ImageFormat}.
14946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return HashMap of minimal frame durations for different sizes, empty HashMap
14956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *         if availableMinFrameDurations is null.
14966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
14976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
14986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
14996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
15006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<StreamConfigurationMap> key =
15026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
15036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        StreamConfigurationMap config = getValueFromKeyNonNull(key);
15046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (config == null) {
15066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return minDurationMap;
15076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (Size size : getAvailableSizesForFormatChecked(format,
15106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                StreamDirection.Output)) {
15116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            long minFrameDuration = config.getOutputMinFrameDuration(format, size);
15126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (minFrameDuration != 0) {
15146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
15156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
15166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return minDurationMap;
15196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
15206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableEdgeModesChecked() {
15226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
15236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] edgeModes = getValueFromKeyNonNull(key);
15246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (edgeModes == null) {
15266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
15276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
15306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Full device should always include OFF and FAST
15316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelFull()) {
15326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
15336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
15346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.EDGE_MODE_FAST));
15356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
15386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // FAST and HIGH_QUALITY mode must be both present or both not present
15396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            List<Integer> coupledModes = Arrays.asList(new Integer[] {
15406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.EDGE_MODE_FAST,
15416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.EDGE_MODE_HIGH_QUALITY
15426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            });
15436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(
15446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
15456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    containsAllOrNone(modeList, coupledModes));
15466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return edgeModes;
15496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
15506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableNoiseReductionModesChecked() {
15526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
15536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
15546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] noiseReductionModes = getValueFromKeyNonNull(key);
15556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (noiseReductionModes == null) {
15576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
15586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
15616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Full device should always include OFF and FAST
15626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelFull()) {
15636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
15656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
15666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
15676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
15706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // FAST and HIGH_QUALITY mode must be both present or both not present
15716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            List<Integer> coupledModes = Arrays.asList(new Integer[] {
15726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.NOISE_REDUCTION_MODE_FAST,
15736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY
15746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            });
15756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(
15766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
15776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    containsAllOrNone(modeList, coupledModes));
15786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return noiseReductionModes;
15806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
15816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
15836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get value of key android.control.aeCompensationStep and do the sanity check.
15846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
15856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return default value if the value is null.
15866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
15876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Rational getAeCompensationStepChecked() {
15886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Rational> key =
15896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
15906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Rational compensationStep = getValueFromKeyNonNull(key);
15916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (compensationStep == null) {
15936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Return default step.
15946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
15956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
15966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
15976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Legacy devices don't have a minimum step requirement
15986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
15996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            float compensationStepF =
16006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    (float) compensationStep.getNumerator() / compensationStep.getDenominator();
16016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
16026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
16036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return compensationStep;
16056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
16066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
16086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get value of key android.control.aeCompensationRange and do the sanity check.
16096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
16106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return default value if the value is null or malformed.
16116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
16126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public Range<Integer> getAeCompensationRangeChecked() {
16136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Range<Integer>> key =
16146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
16156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Range<Integer> compensationRange = getValueFromKeyNonNull(key);
16166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Rational compensationStep = getAeCompensationStepChecked();
16176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        float compensationStepF = compensationStep.floatValue();
16186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        final Range<Integer> DEFAULT_RANGE = Range.create(
16196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF),
16206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
16216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        final Range<Integer> ZERO_RANGE = Range.create(0, 0);
16226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (compensationRange == null) {
16236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return ZERO_RANGE;
16246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
16256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Legacy devices don't have a minimum range requirement
16276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter() && !compensationRange.equals(ZERO_RANGE)) {
16286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
16296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    + ", actual " + compensationRange + ", compensation step " + compensationStep,
16306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                   compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
16316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                   compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
16326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
16336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return compensationRange;
16356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
16366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
16386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get availableVideoStabilizationModes and do the sanity check.
16396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
16406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return available video stabilization modes, empty array if it is unavailable.
16416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
16426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableVideoStabilizationModesChecked() {
16436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
16446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
16456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
16466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
16486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
16496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
16506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
16526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " All device should support OFF mode",
16536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
16546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes,
16556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
16566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
16576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
16596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
16606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isVideoStabilizationSupported() {
16626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer[] videoStabModes =
16636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked());
16646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return Arrays.asList(videoStabModes).contains(
16656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
16666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
16676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
16696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get availableOpticalStabilization and do the sanity check.
16706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
16716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return available optical stabilization modes, empty array if it is unavailable.
16726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
16736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableOpticalStabilizationChecked() {
16746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
16756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
16766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
16776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
16796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
16806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
16816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes,
16836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
16846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
16856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
16876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
16886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
16906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
16916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
16926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
16936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public float getAvailableMaxDigitalZoomChecked() {
16946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Float> key =
16956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
16966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
16976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Float maxZoom = getValueFromKeyNonNull(key);
16986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxZoom == null) {
16996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 1.0f;
17006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " max digital zoom should be no less than 1",
17036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
17046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxZoom;
17066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
17076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableSceneModesChecked() {
17096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
17106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
17116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
17126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
17146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
17156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
17186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // FACE_PRIORITY must be included if face detection is supported.
17196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
17206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                getMaxFaceCountChecked() > 0) {
17216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
17226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
17236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
17266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
17276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableEffectModesChecked() {
17296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
17306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
17316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
17326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
17346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
17356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
17386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // OFF must be included.
17396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " OFF must be included",
17406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
17416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
17436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
17446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
17466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get and check the available color aberration modes
17476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
17486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return the available color aberration modes
17496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
17506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int[] getAvailableColorAberrationModesChecked() {
17516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
17526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
17536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] modes = getValueFromKeyNonNull(key);
17546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (modes == null) {
17566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new int[0];
17576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
17606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode",
17616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) ||
17626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST));
17636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (isHardwareLevelLimitedOrBetter()) {
17656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // FAST and HIGH_QUALITY mode must be both present or both not present
17666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            List<Integer> coupledModes = Arrays.asList(new Integer[] {
17676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST,
17686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
17696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            });
17706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(
17716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    key, " FAST and HIGH_QUALITY mode must both present or both not present",
17726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    containsAllOrNone(modeList, coupledModes));
17736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkElementDistinct(key, modeList);
17756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkArrayValuesInRange(key, modes,
17766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
17776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
17786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return modes;
17806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
17816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
17836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max pipeline depth and do the sanity check.
17846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
17856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return max pipeline depth, default value if it is not available.
17866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
17876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public byte getPipelineMaxDepthChecked() {
17886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Byte> key =
17896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
17906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Byte maxDepth = getValueFromKeyNonNull(key);
17916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxDepth == null) {
17936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return REQUEST_PIPELINE_MAX_DEPTH_MAX;
17946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
17956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " max pipeline depth should be no larger than "
17976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
17986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
17996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxDepth;
18006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
18016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
18036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available lens shading modes.
18046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
18056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     public int[] getAvailableLensShadingModesChecked() {
18066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         Key<int[]> key =
18076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                 CameraCharacteristics.SHADING_AVAILABLE_MODES;
18086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         int[] modes = getValueFromKeyNonNull(key);
18096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         if (modes == null) {
18106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim             return new int[0];
18116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         }
18126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
18146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         // FAST must be included.
18156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         checkTrueForKey(key, " FAST must be included",
18166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                 modeList.contains(CameraMetadata.SHADING_MODE_FAST));
18176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         if (isCapabilitySupported(
18196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) {
18206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim             checkTrueForKey(key, " OFF must be included for MANUAL_POST_PROCESSING devices",
18216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                     modeList.contains(CameraMetadata.SHADING_MODE_OFF));
18226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         }
18236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim         return modes;
18246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     }
18256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     /**
18276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim      * Get available lens shading map modes.
18286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim      */
18296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim      public int[] getAvailableLensShadingMapModesChecked() {
18306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          Key<int[]> key =
18316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                  CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
18326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          int[] modes = getValueFromKeyNonNull(key);
18336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          if (modes == null) {
18346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim              return new int[0];
18356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          }
18366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
18386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          if (isCapabilitySupported(
18406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                  CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
18416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim              checkTrueForKey(key, " ON must be included for RAW capability devices",
18426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                      modeList.contains(CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON));
18436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          }
18446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim          return modes;
18456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim      }
18466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
18496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get available capabilities and do the sanity check.
18506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return reported available capabilities list, empty list if the value is unavailable.
18526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
18536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public List<Integer> getAvailableCapabilitiesChecked() {
18546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<int[]> key =
18556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
18566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        int[] availableCaps = getValueFromKeyNonNull(key);
18576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> capList;
18586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (availableCaps == null) {
18606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return new ArrayList<Integer>();
18616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
18626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
18646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return capList;
18656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
18666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
18686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether the current device supports a capability or not.
18696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param capability (non-negative)
18716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if the capability is supported, {@code false} otherwise.
18736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @throws IllegalArgumentException if {@code capability} was negative
18756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
18776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
18786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isCapabilitySupported(int capability) {
18796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (capability < 0) {
18806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            throw new IllegalArgumentException("capability must be non-negative");
18816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
18826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
18846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return availableCapabilities.contains(capability);
18866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
18876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
18886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
18896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available characteristics keys
18906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getKeys}.
18916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then querying for this key from a characteristics
18936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * object will always return a non-{@code null} value.</p>
18946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
18956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys collection of camera characteristics keys
18966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all characteristics keys are available
18976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
18986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areCharacteristicsKeysAvailable(
18996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            Collection<Key<?>> keys) {
19006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return mCharacteristics.getKeys().containsAll(keys);
19016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
19046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available result keys
19056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
19066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then querying for this key from a result
19086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * object will almost always return a non-{@code null} value.</p>
19096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>In some cases (e.g. lens shading map), the request must have additional settings
19116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * configured in order for the key to correspond to a value.</p>
19126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys collection of capture result keys
19146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all result keys are available
19156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
19176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
19186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
19216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available request keys
19226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
19236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then setting this key in the request builder
19256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * may have some effect (and if it's {@code false}, then the camera device will
19266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * definitely ignore it).</p>
19276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
19296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * in order for a key to take effect (e.g. control.mode set to OFF).</p>
19306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys collection of capture request keys
19326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all result keys are available
19336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
19356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
19366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
19396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available characteristics keys
19406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getKeys}.
19416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then querying for this key from a characteristics
19436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * object will always return a non-{@code null} value.</p>
19446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys one or more camera characteristic keys
19466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all characteristics keys are available
19476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    @SafeVarargs
19496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areKeysAvailable(Key<?>... keys) {
19506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areCharacteristicsKeysAvailable(Arrays.asList(keys));
19516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
19546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available result keys
19556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
19566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then querying for this key from a result
19586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * object will almost always return a non-{@code null} value.</p>
19596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>In some cases (e.g. lens shading map), the request must have additional settings
19616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * configured in order for the key to correspond to a value.</p>
19626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys one or more capture result keys
19646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all result keys are available
19656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    @SafeVarargs
19676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
19686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areResultKeysAvailable(Arrays.asList(keys));
19696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
19726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine whether or not all the {@code keys} are available request keys
19736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
19746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If this returns {@code true}, then setting this key in the request builder
19766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * may have some effect (and if it's {@code false}, then the camera device will
19776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * definitely ignore it).</p>
19786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
19806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * in order for a key to take effect (e.g. control.mode set to OFF).</p>
19816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param keys one or more capture request keys
19836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return whether or not all result keys are available
19846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    @SafeVarargs
19866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
19876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areRequestKeysAvailable(Arrays.asList(keys));
19886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /*
19916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support AE lock control
19926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
19936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if AE lock control is supported
19946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
19956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isAeLockSupported() {
19966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
19976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
19986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
19996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /*
20006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support AWB lock control
20016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if AWB lock control is supported
20036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isAwbLockSupported() {
20056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
20066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /*
20106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support manual lens shading map control
20116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if manual lens shading map control is supported
20136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isManualLensShadingMapSupported() {
20156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.SHADING_MODE);
20166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support manual color correction control
20206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if manual color correction control is supported
20226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isColorCorrectionSupported() {
20246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
20256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support manual tone mapping control
20296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if manual tone mapping control is supported
20316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isManualToneMapSupported() {
20336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
20346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support manual color aberration control
20386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if manual color aberration control is supported
20406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isManualColorAberrationControlSupported() {
20426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
20436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support edge mode control
20476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if edge mode control is supported
20496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isEdgeModeControlSupported() {
20516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.EDGE_MODE);
20526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support hot pixel mode control
20566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if hot pixel mode control is supported
20586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHotPixelMapModeControlSupported() {
20606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
20616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Determine if camera device support noise reduction mode control
20656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return {@code true} if noise reduction mode control is supported
20676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isNoiseReductionModeControlSupported() {
20696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
20706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max number of output raw streams and do the basic sanity check.
20746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return reported max number of raw output stream
20766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxNumOutputStreamsRawChecked() {
20786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer maxNumStreams =
20796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
20806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxNumStreams == null)
20816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
20826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxNumStreams;
20836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max number of output processed streams and do the basic sanity check.
20876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
20886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return reported max number of processed output stream
20896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
20906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxNumOutputStreamsProcessedChecked() {
20916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer maxNumStreams =
20926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
20936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxNumStreams == null)
20946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
20956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxNumStreams;
20966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
20976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
20986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
20996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get max number of output stalling processed streams and do the basic sanity check.
21006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
21016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return reported max number of stalling processed output stream
21026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxNumOutputStreamsProcessedStallChecked() {
21046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer maxNumStreams =
21056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
21066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (maxNumStreams == null)
21076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return 0;
21086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return maxNumStreams;
21096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
21106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
21126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get lens facing and do the sanity check
21136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return lens facing, return default value (BACK) if value is unavailable.
21146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getLensFacingChecked() {
21166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key =
21176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.LENS_FACING;
21186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer facing = getValueFromKeyNonNull(key);
21196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (facing == null) {
21216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return CameraCharacteristics.LENS_FACING_BACK;
21226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
21236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " value is out of range ",
21256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                facing >= CameraCharacteristics.LENS_FACING_FRONT &&
21266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                facing <= CameraCharacteristics.LENS_FACING_BACK);
21276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return facing;
21286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
21296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
21316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get maxCaptureStall frames or default value (if value doesn't exist)
21326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return maxCaptureStall frames or default value.
21336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getMaxCaptureStallOrDefault() {
21356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key =
21366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL;
21376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer value = getValueFromKeyNonNull(key);
21386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (value == null) {
21406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return MAX_REPROCESS_MAX_CAPTURE_STALL;
21416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
21426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " value is out of range ",
21446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                value >= 0 &&
21456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                value <= MAX_REPROCESS_MAX_CAPTURE_STALL);
21466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return value;
21486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
21496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
21516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the scaler's cropping type (center only or freeform)
21526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
21536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public int getScalerCroppingTypeChecked() {
21556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Key<Integer> key =
21566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.SCALER_CROPPING_TYPE;
21576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Integer value = getValueFromKeyNonNull(key);
21586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (value == null) {
21606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
21616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
21626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, " value is out of range ",
21646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
21656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
21666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return value;
21686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
21696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
21716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if the constrained high speed video is supported by the camera device.
21726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * The high speed FPS ranges and sizes are sanitized in
21736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * ExtendedCameraCharacteristicsTest#testConstrainedHighSpeedCapability.
21746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
21756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return true if the constrained high speed video is supported, false otherwise.
21766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isConstrainedHighSpeedVideoSupported() {
21786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
21796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return (availableCapabilities.contains(
21806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO));
21816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
21826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
21836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
21846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
21856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * supported, supported high speed fps ranges and sizes are valid).
21866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
21876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return true if high speed video is supported.
21886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
21896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isHighSpeedVideoSupported() {
21906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        List<Integer> sceneModes =
21916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
21926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
21936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            StreamConfigurationMap config =
21946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
21956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (config == null) {
21966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return false;
21976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
21986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            Size[] availableSizes = config.getHighSpeedVideoSizes();
21996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (availableSizes.length == 0) {
22006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return false;
22016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
22026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            for (Size size : availableSizes) {
22046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
22056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                if (availableFpsRanges.length == 0) {
22066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    return false;
22076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                }
22086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
22096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return true;
22116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        } else {
22126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return false;
22136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
22146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if depth output is supported, based on the depth capability
22186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isDepthOutputSupported() {
22206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return isCapabilitySupported(
22216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
22226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the
22266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * backwards-compatible capability
22276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isColorOutputSupported() {
22296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return isCapabilitySupported(
22306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
22316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if optical black regions key is supported.
22356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isOpticalBlackRegionSupported() {
22376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
22386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check if the dynamic black level is supported.
22426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
22446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Note that: This also indicates if the white level is supported, as dynamic black and white
22456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * level must be all supported or none of them is supported.
22466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
22476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public boolean isDynamicBlackLevelSupported() {
22496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
22506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Get the value in index for a fixed-size array from a given key.
22546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>If the camera device is incorrectly reporting values, log a warning and return
22566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * the default value instead.</p>
22576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param key Key to fetch
22596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param defaultValue Default value to return if camera device uses invalid values
22606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param name Human-readable name for the array index (logging only)
22616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param index Array index of the subelement
22626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param size Expected fixed size of the array
22636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The value reported by the camera device, or the defaultValue otherwise.
22656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
22676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            int size) {
22686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        T elementValue = getArrayElementCheckRangeNonNull(
22696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                key,
22706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                index,
22716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                size);
22726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (elementValue == null) {
22746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(key,
22756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    "had no valid " + name + " value; using default of " + defaultValue);
22766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            elementValue = defaultValue;
22776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
22786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return elementValue;
22806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
22836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Fetch an array sub-element from an array value given by a key.
22846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
22866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Prints a warning if the sub-element was null.
22876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
22886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>Use for variable-size arrays since this does not check the array size.</p>
22906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
22916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param key Metadata key to look up
22926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param element A non-negative index value.
22936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The array sub-element, or null if the checking failed.
22946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
22956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> T getArrayElementNonNull(Key<?> key, int element) {
22966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
22976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
22986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
22996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
23006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Fetch an array sub-element from an array value given by a key.
23016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
23026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * <p>
23036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Prints a warning if the array size does not match the size, or if the sub-element was null.
23046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * </p>
23056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
23066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param key Metadata key to look up
23076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param element The index in [0,size)
23086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
23096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @return The array sub-element, or null if the checking failed.
23106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
23116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
23126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Object array = getValueFromKeyNonNull(key);
23136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (array == null) {
23156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            // Warning already printed
23166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return null;
23176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (size != IGNORE_SIZE_CHECK) {
23206d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            int actualLength = Array.getLength(array);
23216d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (actualLength != size) {
23226d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                failKeyCheck(key,
23236d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                        String.format("had the wrong number of elements (%d), expected (%d)",
23246d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                                actualLength, size));
23256d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return null;
23266d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
23276d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23286d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23296d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        @SuppressWarnings("unchecked")
23306d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        T val = (T) Array.get(array, element);
23316d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23326d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (val == null) {
23336d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(key, "had a null element at index" + element);
23346d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return null;
23356d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23366d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23376d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return val;
23386d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23396d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23406d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
23416d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Gets the key, logging warnings for null values.
23426d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
23436d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    public <T> T getValueFromKeyNonNull(Key<T> key) {
23446d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (key == null) {
23456d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            throw new IllegalArgumentException("key was null");
23466d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23476d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23486d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        T value = mCharacteristics.get(key);
23496d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23506d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (value == null) {
23516d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(key, "was null");
23526d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23536d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23546d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return value;
23556d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23566d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23576d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
23586d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (int value : array) {
23596d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
23606d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    value <= max && value >= min);
23616d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23626d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23636d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23646d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
23656d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (byte value : array) {
23666d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
23676d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                    value <= max && value >= min);
23686d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23696d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23706d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23716d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /**
23726d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * Check the uniqueness of the values in a list.
23736d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     *
23746d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param key The key to be checked
23756d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     * @param list The list contains the value of the key
23766d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim     */
23776d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
23786d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // Each size must be distinct.
23796d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        Set<T> sizeSet = new HashSet<T>(list);
23806d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
23816d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23826d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23836d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
23846d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (!condition) {
23856d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            failKeyCheck(key, message);
23866d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23876d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
23886d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
23896d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    /* Helper function to check if the coupled modes are either all present or all non-present */
23906d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) {
23916d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        if (observedModes.containsAll(coupledModes)) {
23926d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            return true;
23936d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23946d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        for (T mode : coupledModes) {
23956d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            if (observedModes.contains(mode)) {
23966d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                return false;
23976d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            }
23986d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
23996d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        return true;
24006d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
24016d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim
24026d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    private <T> void failKeyCheck(Key<T> key, String message) {
24036d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // TODO: Consider only warning once per key/message combination if it's too spammy.
24046d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        // TODO: Consider offering other options such as throwing an assertion exception
24056d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
24066d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        switch (mLevel) {
24076d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case WARN:
24086d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Log.w(TAG, failureCause);
24096d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                break;
24106d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case COLLECT:
24116d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                mCollector.addMessage(failureCause);
24126d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                break;
24136d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            case ASSERT:
24146d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                Assert.fail(failureCause);
24156d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim            default:
24166d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim                throw new UnsupportedOperationException("Unhandled level " + mLevel);
24176d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim        }
24186d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim    }
24196d8fd0a23fdc01b9414202c3de9bba41222583e6Hyungtae Tim Kim}
2420