camera2: Fix afRegions test

- Also adds helpers for available key checks

Change-Id: I104c8243fa525622cb4ab7b5535cbca8588862f3
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index 64df952..de4396b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -333,7 +333,7 @@
     public void testAfRegions() throws Exception {
         for (String id : mCameraIds) {
             try {
-                Log.i(TAG, "Testing AE regions for Camera " + id);
+                Log.i(TAG, "Testing AF regions for Camera " + id);
                 openDevice(id);
 
                 boolean afRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
index 517e780..4ae89ae 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
@@ -51,7 +51,7 @@
     private final AutoFocusListener mAutoFocusListener;
     private final CameraDevice mCamera;
     private final Surface mRequestSurface;
-    private final CameraCharacteristics mStaticInfo;
+    private final StaticMetadata mStaticInfo;
 
     private int mAfRun = 0;
     private MeteringRectangle[] mAfRegions;
@@ -104,17 +104,18 @@
         if (staticInfo == null) {
             throw new IllegalArgumentException("staticInfo must not be null");
         }
-        Float minFocusDist = staticInfo.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
-        if (minFocusDist == null || minFocusDist == 0) {
-            throw new IllegalArgumentException("this camera doesn't have a focuser");
-        }
 
         mCamera = camera;
         mRequestSurface = requestSurface;
         mAutoFocusListener = listener;
-        mStaticInfo = staticInfo;
+        mStaticInfo = new StaticMetadata(staticInfo,
+                StaticMetadata.CheckLevel.ASSERT, /*collector*/null);
         mHandler = handler;
 
+        if (!mStaticInfo.hasFocuser()) {
+            throw new IllegalArgumentException("this camera doesn't have a focuser");
+        }
+
         /**
          * Begin by always being in passive auto focus.
          */
@@ -318,15 +319,10 @@
      * Set default AF region to full active array size.
      */
     private void setDefaultAfRegions() {
-        Rect activeArraySize = mStaticInfo.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-        if (activeArraySize == null) {
-            throw new AssertionError("Active array size shouldn't be null");
-        }
-
         // Initialize AF regions with all zeros, meaning that it is up to camera device to device
         // the regions used by AF.
         mAfRegions = new MeteringRectangle[] {
-                new MeteringRectangle(0, 0, 0, 0, 0)};
+                new MeteringRectangle(0, 0, 0, 0, MeteringRectangle.METERING_WEIGHT_DONT_CARE)};
     }
     private CaptureListener createCaptureListener() {
 
@@ -365,7 +361,7 @@
                 int afRun;
                 synchronized (Camera2Focuser.this) {
                     // In case of partial results, don't send AF update twice
-                    int frameCount = result.get(CaptureResult.REQUEST_FRAME_COUNT);
+                    int frameCount = result.getFrameNumber();
                     if (frameCount <= mLatestFrameCount) return;
                     mLatestFrameCount = frameCount;
 
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 04e3330..57d355d 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
@@ -21,6 +21,8 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraCharacteristics.Key;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
 import android.util.Range;
 import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils;
@@ -287,7 +289,33 @@
      * @return true if camera device support focuser, false otherwise.
      */
     public boolean hasFocuser() {
-        return (getMinimumFocusDistanceChecked() > 0);
+        if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
+            // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
+            return (getMinimumFocusDistanceChecked() > 0);
+        } else {
+            // Check available AF modes
+            int[] availableAfModes = mCharacteristics.get(
+                    CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+
+            if (availableAfModes == null) {
+                return false;
+            }
+
+            // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
+            boolean hasFocuser = false;
+            loop: for (int mode : availableAfModes) {
+                switch (mode) {
+                    case CameraMetadata.CONTROL_AF_MODE_AUTO:
+                    case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+                    case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+                    case CameraMetadata.CONTROL_AF_MODE_MACRO:
+                        hasFocuser = true;
+                        break loop;
+                }
+            }
+
+            return hasFocuser;
+        }
     }
 
     /**
@@ -1412,6 +1440,58 @@
     }
 
     /**
+     * Determine whether or not all the {@code keys} are available characteristics keys
+     * (as in {@link CameraCharacteristics#getKeys}.
+     *
+     * <p>If this returns {@code true}, then querying for this key from a characteristics
+     * object will always return a non-{@code null} value.</p>
+     *
+     * @param keys one or more camera characteristic keys
+     * @return whether or not all characteristics keys are available
+     */
+    @SafeVarargs
+    public final <T> boolean areKeysAvailable(CameraCharacteristics.Key<T>... keys) {
+        return mCharacteristics.getKeys().containsAll(Arrays.asList(keys));
+    }
+
+    /**
+     * Determine whether or not all the {@code keys} are available result keys
+     * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
+     *
+     * <p>If this returns {@code true}, then querying for this key from a result
+     * object will almost always return a non-{@code null} value.</p>
+     *
+     * <p>In some cases (e.g. lens shading map), the request must have additional settings
+     * configured in order for the key to correspond to a value.</p>
+     *
+     * @param keys one or more capture result keys
+     * @return whether or not all result keys are available
+     */
+    @SafeVarargs
+    public final <T> boolean areKeysAvailable(CaptureResult.Key<T>... keys) {
+        return mCharacteristics.getAvailableCaptureResultKeys().containsAll(Arrays.asList(keys));
+    }
+
+    /**
+     * Determine whether or not all the {@code keys} are available request keys
+     * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
+     *
+     * <p>If this returns {@code true}, then setting this key in the request builder
+     * may have some effect (and if it's {@code false}, then the camera device will
+     * definitely ignore it).</p>
+     *
+     * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
+     * in order for a key to take effect (e.g. control.mode set to OFF).</p>
+     *
+     * @param keys one or more capture request keys
+     * @return whether or not all result keys are available
+     */
+    @SafeVarargs
+    public final <T> boolean areKeysAvailable(CaptureRequest.Key<T>... keys) {
+        return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(Arrays.asList(keys));
+    }
+
+    /**
      * Get max number of output raw streams and do the basic sanity check.
      *
      * @return reported max number of raw output stream