Camera2: Add some static metadata tests

Bug: 15315521
Change-Id: Ife23527f8a915e9ead607868041996d3a82b11dc
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
new file mode 100644
index 0000000..3a0ae09
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import static android.hardware.camera2.CameraCharacteristics.*;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
+import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
+import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
+import android.util.Log;
+import android.util.Size;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <p>
+ * This class covers the {@link CameraCharacteristics} tests that are not
+ * covered by {@link CaptureRequestTest} and {@link CameraCharacteristicsTest}
+ * (auto-generated tests that only do the non-null checks).
+ * </p>
+ * <p>
+ * Note that most of the tests in this class don't require camera open.
+ * </p>
+ */
+public class StaticMetadataTest extends Camera2AndroidTestCase {
+    private static final String TAG = "StaticMetadataTest";
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final float MIN_FPS_FOR_FULL_DEVICE = 20.0f;
+    private static final int RAW_STREAM_IDX = 0;
+    private static final int PROCESSED_NON_STALLING_STREAM_IDX = 1;
+    private static final int PROCESSED_STALLING_STREAM_IDX = 2;
+
+
+    /**
+     * Test the available capability for different hardware support level devices.
+     */
+    public void testHwSupportedLevel() throws Exception {
+        for (String id : mCameraIds) {
+            initStaticMetadata(id);
+            List<Integer> availabeCaps = mStaticInfo.getAvailableCapabilitiesChecked();
+
+            mCollector.expectTrue("All device must contains BACKWARD_COMPATIBLE capability",
+                    availabeCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE));
+
+            if (mStaticInfo.isHardwareLevelFull()) {
+                // Capability advertisement must be right.
+                mCollector.expectTrue("Full device must contains MANUAL_SENSOR capability",
+                        availabeCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR));
+                mCollector.expectTrue("Full device must contains MANUAL_POST_PROCESSING capability",
+                        availabeCaps.contains(
+                                REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING));
+
+                // Max resolution fps must be >= 20.
+                mCollector.expectTrue("Full device must support at least 20fps for max resolution",
+                        getFpsForMaxSize(id) >= MIN_FPS_FOR_FULL_DEVICE);
+
+                // Need support per frame control
+                mCollector.expectTrue("Full device must support per frame control",
+                        mStaticInfo.isPerFrameControlSupported());
+            }
+
+            // TODO: test all the keys mandatory for all capability devices.
+        }
+    }
+
+    /**
+     * Test max number of output stream reported by device
+     */
+    public void testMaxNumOutputStreams() throws Exception {
+        for (String id : mCameraIds) {
+            initStaticMetadata(id);
+            int[] maxNumStreams = mStaticInfo.getMaxNumOutputStreamsChecked();
+            assertTrue("max number of streams must be a 3 element array",
+                    maxNumStreams.length == 3);
+
+            mCollector.expectTrue("max number of raw output streams must be a non negative number",
+                    maxNumStreams[RAW_STREAM_IDX] >= 0);
+            mCollector.expectTrue("max number of processed (stalling) output streams must be >= 1",
+                    maxNumStreams[PROCESSED_STALLING_STREAM_IDX] >= 1);
+
+            if (mStaticInfo.isHardwareLevelFull()) {
+                mCollector.expectTrue("max number of processed (non-stalling) output streams" +
+                        "must be >= 3 for FULL device",
+                        maxNumStreams[PROCESSED_NON_STALLING_STREAM_IDX] >= 3);
+            } else {
+                mCollector.expectTrue("max number of processed (non-stalling) output streams" +
+                        "must be >= 2 for LIMITED device",
+                        maxNumStreams[PROCESSED_NON_STALLING_STREAM_IDX] >= 2);
+            }
+        }
+
+    }
+
+    /**
+     * Test lens facing.
+     */
+    public void testLensFacing() throws Exception {
+        for (String id : mCameraIds) {
+            initStaticMetadata(id);
+            mStaticInfo.getLensFacingChecked();
+        }
+    }
+
+    private float getFpsForMaxSize(String cameraId) throws Exception {
+        HashMap<Size, Long> minFrameDurationMap =
+                mStaticInfo.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.YUV_420_888);
+
+        Size[] sizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.YUV_420_888,
+                cameraId, mCameraManager);
+        Size maxSize = CameraTestUtils.getMaxSize(sizes);
+        Long minDuration = minFrameDurationMap.get(maxSize);
+        if (VERBOSE) {
+            Log.v(TAG, "min frame duration for size " + maxSize + " is " + minDuration);
+        }
+        assertTrue("min duration for max size must be postive number",
+                minDuration != null && minDuration > 0);
+
+        return 1e9f / minDuration;
+    }
+
+    /**
+     * Initialize static metadata for a given camera id.
+     */
+    private void initStaticMetadata(String cameraId) throws Exception {
+        mCollector.setCameraId(cameraId);
+        mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
+                CheckLevel.COLLECT, /* collector */mCollector);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 76f79f7..bca554e 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -26,7 +26,6 @@
 import android.hardware.camera2.cts.CameraTestUtils;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.util.Log;
-import android.util.Range;
 import android.util.Rational;
 
 import junit.framework.Assert;
@@ -161,11 +160,9 @@
      * @return true if the device is FULL, false otherwise.
      */
     public boolean isHardwareLevelFull() {
-        // TODO: Make this key non-optional for all HAL3.2+ devices
         Integer hwLevel = getValueFromKeyNonNull(
                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
 
-        // Bad. Missing metadata. Warning is logged.
         if (hwLevel == null) {
             return false;
         }
@@ -1273,6 +1270,64 @@
     }
 
     /**
+     * Get available capabilities and do the sanity check.
+     *
+     * @return reported available capabilities list, empty list if the value is unavailable.
+     */
+    public List<Integer> getAvailableCapabilitiesChecked() {
+        Key<int[]> key =
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
+        int[] availableCaps = getValueFromKeyNonNull(key);
+        List<Integer> capList;
+
+        if (availableCaps == null) {
+            return new ArrayList<Integer>();
+        }
+
+        checkArrayValuesInRange(key, availableCaps,
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DNG);
+        capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
+        return capList;
+    }
+
+    /**
+     * Get max number of output streams and do the basic sanity check.
+     *
+     * @return reported max number of output stream array, empty array if the value is unavailable.
+     */
+    public int[] getMaxNumOutputStreamsChecked() {
+        Key<int[]> key =
+                CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS;
+        int[] maxNumStreams = getValueFromKeyNonNull(key);
+
+        if (maxNumStreams == null) {
+            return new int[0];
+        }
+
+        return maxNumStreams;
+    }
+
+    /**
+     * Get lens facing and do the sanity check
+     * @return lens facing, return default value (BACK) if value is unavailable.
+     */
+    public int getLensFacingChecked() {
+        Key<Integer> key =
+                CameraCharacteristics.LENS_FACING;
+        Integer facing = getValueFromKeyNonNull(key);
+
+        if (facing == null) {
+            return CameraCharacteristics.LENS_FACING_BACK;
+        }
+
+        checkTrueForKey(key, " value is out of range ",
+                facing >= CameraCharacteristics.LENS_FACING_FRONT &&
+                facing <= CameraCharacteristics.LENS_FACING_BACK);
+        return facing;
+    }
+
+    /**
      * Get the value in index for a fixed-size array from a given key.
      *
      * <p>If the camera device is incorrectly reporting values, log a warning and return