Camera: check AE/AWB lock availability before using it
Bug: 20039760
Change-Id: I8adb4decad94f6f0e48578fb07eca99ecd5b8754
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index 24f4e75..b97091b 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -222,6 +222,30 @@
return props.has_key("android.control.aeCompensationRange") and \
props["android.control.aeCompensationRange"] != [0, 0]
+def ae_lock(props):
+ """Returns whether a device supports AE lock
+
+ Args:
+ props: Camera properties object.
+
+ Return:
+ Boolean.
+ """
+ return props.has_key("android.control.aeLockAvailable") and \
+ props["android.control.aeLockAvailable"] == 1
+
+def awb_lock(props):
+ """Returns whether a device supports AWB lock
+
+ Args:
+ props: Camera properties object.
+
+ Return:
+ Boolean.
+ """
+ return props.has_key("android.control.awbLockAvailable") and \
+ props["android.control.awbLockAvailable"] == 1
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
index 87500c7..6629df8 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_auto.py
@@ -39,7 +39,8 @@
# Capture at the smallest resolution.
props = cam.get_camera_properties()
- its.caps.skip_unless(its.caps.manual_sensor(props))
+ its.caps.skip_unless(its.caps.manual_sensor(props) and
+ its.caps.awb_lock(props))
_, fmt = its.objects.get_fastest_manual_capture_settings(props)
w,h = fmt["width"], fmt["height"]
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
index 932c051..fa37174 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
@@ -15,6 +15,7 @@
import its.image
import its.device
import its.objects
+import its.caps
import os.path
import numpy
import pylab
@@ -41,6 +42,8 @@
# Capture at full resolution.
props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.manual_sensor(props) and
+ its.caps.awb_lock(props))
w,h = its.objects.get_available_output_sizes("yuv", props)[0]
# Converge 3A prior to capture.
diff --git a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
index d09f2fd..e3755eb 100644
--- a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
@@ -29,7 +29,8 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
- its.caps.skip_unless(its.caps.ev_compensation(props))
+ its.caps.skip_unless(its.caps.ev_compensation(props) and
+ its.caps.ae_lock(props))
ev_per_step = its.objects.rational_to_float(
props['android.control.aeCompensationStep'])
diff --git a/apps/CameraITS/tests/scene1/test_locked_burst.py b/apps/CameraITS/tests/scene1/test_locked_burst.py
index 90662db..1dfe15f 100644
--- a/apps/CameraITS/tests/scene1/test_locked_burst.py
+++ b/apps/CameraITS/tests/scene1/test_locked_burst.py
@@ -15,6 +15,7 @@
import its.image
import its.device
import its.objects
+import its.caps
import os.path
import numpy
import pylab
@@ -36,6 +37,8 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.ae_lock(props) and
+ its.caps.awb_lock(props))
# Converge 3A prior to capture.
cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index e1e89f2..ea851b7 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -16,6 +16,7 @@
import its.device
import its.objects
import its.image
+import its.caps
def main():
"""capture a yuv image and save it to argv[1]
@@ -39,8 +40,10 @@
cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
props = cam.get_camera_properties()
req = its.objects.fastest_auto_capture_request(props)
- req["android.control.awbLock"] = True
- req["android.control.aeLock"] = True
+ if its.caps.ae_lock(props):
+ req["android.control.awbLock"] = True
+ if its.caps.awb_lock(props):
+ req["android.control.aeLock"] = True
while True:
print "Capture an image to check the test scene"
cap = cam.do_capture(req)
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 29c7362..b3bfd64 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -1089,16 +1089,22 @@
mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
- mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
+ // if AE lock is not supported, expect the control key to be non-exist or false
+ if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
+ mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
+ }
mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
CaptureRequest.CONTROL_AWB_MODE_AUTO);
- mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
+ // if AWB lock is not supported, expect the control key to be non-exist or false
+ if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
+ mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
+ }
// Check 3A regions.
if (VERBOSE) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 1f2792c..f3a0cc0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -1046,7 +1046,9 @@
private void aeAutoModeTestLock(int mode) throws Exception {
CaptureRequest.Builder requestBuilder =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
- requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ if (mStaticInfo.isAeLockSupported()) {
+ requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ }
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mode);
configurePreviewOutput(requestBuilder);
@@ -1077,9 +1079,12 @@
SimpleCaptureCallback listener = new SimpleCaptureCallback();
CaptureResult[] resultsDuringLock = new CaptureResult[numCapturesDuringLock];
+ boolean canSetAeLock = mStaticInfo.isAeLockSupported();
// Reset the AE lock to OFF, since we are reusing this builder many times
- requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ if (canSetAeLock) {
+ requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ }
// Just send several captures with auto AE, lock off.
CaptureRequest request = requestBuilder.build();
@@ -1088,6 +1093,11 @@
}
waitForNumResults(listener, NUM_CAPTURES_BEFORE_LOCK);
+ if (!canSetAeLock) {
+ // Without AE lock, the remaining tests items won't work
+ return;
+ }
+
// Then fire several capture to lock the AE.
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
@@ -1112,7 +1122,7 @@
// Can't read manual sensor/exposure settings without manual sensor
if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
int sensitivityLocked =
getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_SENSITIVITY);
long expTimeLocked =
@@ -1475,6 +1485,7 @@
private void awbModeAndLockTestByCamera() throws Exception {
int[] awbModes = mStaticInfo.getAwbAvailableModesChecked();
Size maxPreviewSize = mOrderedPreviewSizes.get(0);
+ boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
CaptureRequest.Builder requestBuilder =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
startPreview(requestBuilder, maxPreviewSize, /*listener*/null);
@@ -1490,7 +1501,7 @@
verifyCaptureResultForKey(CaptureResult.CONTROL_AWB_MODE, mode, listener,
NUM_FRAMES_VERIFIED);
- if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO) {
+ if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO && canSetAwbLock) {
// Verify color correction transform and gains stay unchanged after a lock.
requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
listener = new SimpleCaptureCallback();
@@ -1503,7 +1514,10 @@
}
}
- verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED);
+ // Don't verify auto mode result if AWB lock is not supported
+ if (mode != CameraMetadata.CONTROL_AWB_MODE_AUTO || canSetAwbLock) {
+ verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED);
+ }
}
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 03e8a26..06561d4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -388,6 +388,10 @@
maxYuvSize.getHeight() <= sensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
maxYuvSize.getHeight() >= sensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
+ // No need to do null check since framework will generate the key if HAL don't supply
+ boolean haveAeLock = c.get(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
+ boolean haveAwbLock = c.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
+
// Ensure that YUV output is fast enough - needs to be at least 20 fps
long maxYuvRate =
@@ -443,14 +447,25 @@
mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND),
haveFastSyncLatency);
assertTrue(
- "Active array size and max YUV size should be similar",
+ String.format("BURST-capable camera device %s max YUV size %s should be" +
+ "close to active array size %s",
+ mIds[counter], maxYuvSize.toString(), sensorSize.toString()),
maxYuvMatchSensor);
+ assertTrue(
+ String.format("BURST-capable camera device %s does not support AE lock",
+ mIds[counter]),
+ haveAeLock);
+ assertTrue(
+ String.format("BURST-capable camera device %s does not support AWB lock",
+ mIds[counter]),
+ haveAwbLock);
} else {
assertTrue(
String.format("Camera device %s has all the requirements for BURST" +
" capability but does not report it!", mIds[counter]),
!(haveMaxYuv && haveMaxYuvRate && haveFastAeTargetFps &&
- haveFastSyncLatency && maxYuvMatchSensor));
+ haveFastSyncLatency && maxYuvMatchSensor &&
+ haveAeLock && haveAwbLock));
}
counter++;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
index ceb30b5..3076d09 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -268,12 +268,10 @@
capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE";
requestKeys.add(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE);
requestKeys.add(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION);
- requestKeys.add(CaptureRequest.CONTROL_AE_LOCK);
requestKeys.add(CaptureRequest.CONTROL_AE_MODE);
requestKeys.add(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
requestKeys.add(CaptureRequest.CONTROL_AF_MODE);
requestKeys.add(CaptureRequest.CONTROL_AF_TRIGGER);
- requestKeys.add(CaptureRequest.CONTROL_AWB_LOCK);
requestKeys.add(CaptureRequest.CONTROL_AWB_MODE);
requestKeys.add(CaptureRequest.CONTROL_CAPTURE_INTENT);
requestKeys.add(CaptureRequest.CONTROL_EFFECT_MODE);
@@ -319,6 +317,7 @@
requestKeys.add(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE);
requestKeys.add(CaptureRequest.TONEMAP_CURVE);
requestKeys.add(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
+ requestKeys.add(CaptureRequest.CONTROL_AWB_LOCK);
// Legacy mode always doesn't support these requirements
Boolean contrastCurveModeSupported = false;
@@ -342,9 +341,12 @@
"Tonemap mode must include CONTRAST_CURVE", contrastCurveModeSupported));
additionalRequirements.add(new Pair<String, Boolean>(
"Color aberration mode must include OFF", offColorAberrationModeSupported));
+ additionalRequirements.add(new Pair<String, Boolean>(
+ "Must support AWB lock", mStaticInfo.isAwbLockSupported()));
break;
case REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR";
+ requestKeys.add(CaptureRequest.CONTROL_AE_LOCK);
requestKeys.add(CaptureRequest.SENSOR_FRAME_DURATION);
requestKeys.add(CaptureRequest.SENSOR_EXPOSURE_TIME);
requestKeys.add(CaptureRequest.SENSOR_SENSITIVITY);
@@ -355,6 +357,8 @@
requestKeys.add(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE);
}
requestKeys.add(CaptureRequest.BLACK_LEVEL_LOCK);
+ additionalRequirements.add(new Pair<String, Boolean>(
+ "Must support AE lock", mStaticInfo.isAeLockSupported()));
break;
case REQUEST_AVAILABLE_CAPABILITIES_RAW:
// RAW_CAPABILITY needs to check for not just capture request keys
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 b40b350..c3cf8d0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -523,7 +523,10 @@
// LEGACY Devices don't have the AWB_STATE reported in results, so just wait
waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
}
- previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+ boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
+ if (canSetAwbLock) {
+ previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+ }
mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
// Validate the next result immediately for region and mode.
result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
@@ -1281,7 +1284,12 @@
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
CaptureRequest.Builder stillRequest =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
- stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ boolean canSetAeLock = mStaticInfo.isAeLockSupported();
+
+ if (canSetAeLock) {
+ stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ }
+
CaptureResult normalResult;
CaptureResult compensatedResult;
@@ -1291,7 +1299,7 @@
long maxExposureValuePreview = -1;
long maxExposureValueStill = -1;
if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
// Minimum exposure settings is mostly static while maximum exposure setting depends on
// frame rate range which in term depends on capture request.
minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() *
@@ -1319,7 +1327,7 @@
long normalExposureValue = -1;
if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
// get and check if current exposure value is valid
normalExposureValue = getExposureValue(normalResult);
mCollector.expectInRange("Exposure setting out of bound", normalExposureValue,
@@ -1343,9 +1351,15 @@
// frames to go back to locked state
previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
exposureCompensation);
- previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ if (canSetAeLock) {
+ previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ }
mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
- waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+ if (canSetAeLock) {
+ waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+ } else {
+ waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+ }
// Issue still capture
if (VERBOSE) {
@@ -1361,7 +1375,7 @@
request, WAIT_FOR_RESULT_TIMEOUT_MS);
if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
// Verify the exposure value compensates as requested
long compensatedExposureValue = getExposureValue(compensatedResult);
mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue,
@@ -1388,8 +1402,10 @@
mCollector.expectEquals("Exposure compensation result should match requested value.",
exposureCompensation,
compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION));
- mCollector.expectTrue("Exposure lock should be set",
- compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
+ if (canSetAeLock) {
+ mCollector.expectTrue("Exposure lock should be set",
+ compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
+ }
Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateJpegCapture(image, maxStillSz);
@@ -1397,7 +1413,9 @@
// Recover AE compensation and lock
previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
- previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ if (canSetAeLock) {
+ previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
+ }
mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
}
}
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 6ecdd56..6fc78dd 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
@@ -1673,6 +1673,25 @@
}
/*
+ * Determine if camera device support AE lock control
+ *
+ * @return {@code true} if AE lock control is supported
+ */
+ public boolean isAeLockSupported() {
+ return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
+ }
+
+ /*
+ * Determine if camera device support AWB lock control
+ *
+ * @return {@code true} if AWB lock control is supported
+ */
+ public boolean isAwbLockSupported() {
+ return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
+ }
+
+
+ /*
* Determine if camera device support manual lens shading map control
*
* @return {@code true} if manual lens shading map control is supported