aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTahsin Masrur <tahsinm@google.com>2023-02-23 17:41:07 +0800
committerTahsin Masrur <tahsinm@google.com>2023-02-23 19:01:50 +0800
commit5917b1d3c87da244b9a1942da415a6c6b60f1cb8 (patch)
tree7ae8c993e7af8ae6fbbdcc9d79bbef44a7966d86
parent7818194936cbd76cb390a4160a92eb32fed1812d (diff)
downloadsupport-5917b1d3c87da244b9a1942da415a6c6b60f1cb8.tar.gz
Handle CameraControlDeviceTest regression and move focus metering tests to FocusMeteringDeviceTest
The test regression occurred due to focus metering tests failing due to b/263211462. The tests are moved to FocusMeteringDeviceTest as they are more related to there, and FocusMeteringDeviceTest already has a workaround for this problem. Also refactored FocusMeteringDeviceTest to make the tests simpler and more maintanable. Bug: 270281297 Test: CameraControlDeviceTest, FocusMeteringDeviceTest Change-Id: Ife2d756e66711aa37790a452610d62bda7a433ea
-rw-r--r--camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FocusMeteringDeviceTest.kt223
-rw-r--r--camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/CameraControlDeviceTest.kt101
2 files changed, 124 insertions, 200 deletions
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FocusMeteringDeviceTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FocusMeteringDeviceTest.kt
index a4284608f81..1bcfbd096b4 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FocusMeteringDeviceTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FocusMeteringDeviceTest.kt
@@ -18,7 +18,9 @@ package androidx.camera.integration.core
import android.content.Context
import android.hardware.camera2.CameraCaptureSession
-import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AE
+import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AF
+import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AWB
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.TotalCaptureResult
import androidx.camera.camera2.Camera2Config
@@ -28,30 +30,31 @@ import androidx.camera.core.CameraControl
import androidx.camera.core.CameraSelector
import androidx.camera.core.CameraXConfig
import androidx.camera.core.FocusMeteringAction
-import androidx.camera.core.FocusMeteringResult
+import androidx.camera.core.FocusMeteringAction.FLAG_AE
+import androidx.camera.core.FocusMeteringAction.FLAG_AF
+import androidx.camera.core.FocusMeteringAction.FLAG_AWB
import androidx.camera.core.ImageCapture
import androidx.camera.core.SurfaceOrientedMeteringPointFactory
-import androidx.camera.core.impl.utils.executor.CameraXExecutors
import androidx.camera.integration.core.util.CameraPipeUtil
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.CameraPipeConfigTestRule
import androidx.camera.testing.CameraUtil
import androidx.camera.testing.fakes.FakeLifecycleOwner
-import androidx.core.content.ContextCompat
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
-import com.google.common.util.concurrent.FutureCallback
-import com.google.common.util.concurrent.Futures
+import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.CountDownLatch
+import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.CoreMatchers.not
import org.junit.After
+import org.junit.Assert
import org.junit.Assume
import org.junit.Assume.assumeThat
import org.junit.Before
@@ -144,8 +147,8 @@ class FocusMeteringDeviceTest(
}
if (implName == CameraPipeConfig::class.simpleName) {
- // TODO(b/264396089): Remove this waiting for camera opening to be completed
- // when camera can be closed properly without this
+ // TODO(b/263211462): Remove this waiting for camera opening to be completed
+ // when focus metering request can be submitted without the waiting
captureCallback.await(5000)
}
}
@@ -165,27 +168,7 @@ class FocusMeteringDeviceTest(
}
@Test
- fun resultFutureCompletes_whenFocusMeteringStarted() = runBlocking {
- val focusMeteringAction = FocusMeteringAction.Builder(validMeteringPoint).build()
-
- val result = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- val focusMeteringResultCallback = FocusMeteringResultCallback()
- Futures.addCallback<FocusMeteringResult>(
- result,
- focusMeteringResultCallback,
- ContextCompat.getMainExecutor(context)
- )
-
- focusMeteringResultCallback.await()
-
- assertWithMessage("Result future for startFocusAndMetering operation did not complete!")
- .that(focusMeteringResultCallback.successResult != null ||
- focusMeteringResultCallback.failureThrowable != null
- ).isTrue()
- }
-
- @Test
- fun canStartFocusMeteringSuccessfully() = runBlocking {
+ fun futureCompletes_whenFocusMeteringStarted() = runBlocking {
assumeThat(
"No AF/AE/AWB region available on this device!",
hasMeteringRegion(cameraSelector), equalTo(true)
@@ -193,23 +176,18 @@ class FocusMeteringDeviceTest(
val focusMeteringAction = FocusMeteringAction.Builder(validMeteringPoint).build()
- assumeThat(
- "FocusMeteringAction not supported!",
- camera.cameraInfo.isFocusMeteringSupported(focusMeteringAction), equalTo(true)
- )
+ val resultFuture = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
+ assertFutureCompletes(resultFuture)
+ }
- val result = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- val focusMeteringResultCallback = FocusMeteringResultCallback()
- Futures.addCallback<FocusMeteringResult>(
- result,
- focusMeteringResultCallback,
- ContextCompat.getMainExecutor(context)
- )
+ @Test
+ fun futureCompletes_whenFocusMeteringIsCancelled() {
+ val focusMeteringAction = FocusMeteringAction.Builder(validMeteringPoint).build()
- focusMeteringResultCallback.await()
+ camera.cameraControl.startFocusAndMetering(focusMeteringAction)
+ val resultFuture = camera.cameraControl.cancelFocusAndMetering()
- assertWithMessage("FocusMetering failed!")
- .that(focusMeteringResultCallback.successResult).isNotNull()
+ assertFutureCompletes(resultFuture)
}
@Test
@@ -245,18 +223,9 @@ class FocusMeteringDeviceTest(
camera.cameraInfo.isFocusMeteringSupported(focusMeteringAction), equalTo(true)
)
- val result = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- val focusMeteringResultCallback = FocusMeteringResultCallback()
- Futures.addCallback<FocusMeteringResult>(
- result,
- focusMeteringResultCallback,
- CameraXExecutors.mainThreadExecutor()
- )
+ val resultFuture = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- focusMeteringResultCallback.await()
-
- assertWithMessage("FocusMetering failed!")
- .that(focusMeteringResultCallback.successResult).isNotNull()
+ assertFutureCompletes(resultFuture)
}
@Test
@@ -268,19 +237,9 @@ class FocusMeteringDeviceTest(
camera.cameraInfo.isFocusMeteringSupported(focusMeteringAction), equalTo(false)
)
- val result = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- val focusMeteringResultCallback = FocusMeteringResultCallback()
- Futures.addCallback<FocusMeteringResult>(
- result,
- focusMeteringResultCallback,
- CameraXExecutors.mainThreadExecutor()
- )
-
- focusMeteringResultCallback.await()
+ val resultFuture = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- assertWithMessage("FocusMetering succeeded, should have failed for invalid argument!")
- .that(focusMeteringResultCallback.failureThrowable)
- .isInstanceOf(IllegalArgumentException::class.java)
+ assertFutureFailsWithIllegalArgumentException(resultFuture)
}
@Test
@@ -290,59 +249,125 @@ class FocusMeteringDeviceTest(
}
val focusMeteringAction = FocusMeteringAction.Builder(validMeteringPoint).build()
+ val resultFuture = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
+
+ assertFutureFailsWithOperationCancellation(resultFuture)
+ }
+
+ @Test
+ fun futureCompletes_whenFocusMeteringWithAe() {
+ assumeThat(
+ "b/270520932: IllegalArgumentException from Camera2 in CameraPipe",
+ implName, not(CameraPipeConfig::class.simpleName),
+ )
+
+ assumeThat(
+ "No AE region available on this device!",
+ hasMeteringRegion(cameraSelector, FLAG_AE), equalTo(true)
+ )
+
+ val action = FocusMeteringAction.Builder(validMeteringPoint, FLAG_AE).build()
+ val future = camera.cameraControl.startFocusAndMetering(action)
+
+ assertFutureCompletes(future)
+ }
+
+ @Test
+ fun futureCompletes_whenFocusMeteringWithAwb() {
+ assumeThat(
+ "b/270520932: IllegalArgumentException from Camera2 in CameraPipe",
+ implName, not(CameraPipeConfig::class.simpleName),
+ )
- val result = camera.cameraControl.startFocusAndMetering(focusMeteringAction)
- val focusMeteringResultCallback = FocusMeteringResultCallback()
- Futures.addCallback<FocusMeteringResult>(
- result,
- focusMeteringResultCallback,
- CameraXExecutors.mainThreadExecutor()
+ assumeThat(
+ "No AWB region available on this device!",
+ hasMeteringRegion(cameraSelector, FLAG_AWB), equalTo(true)
)
- focusMeteringResultCallback.await()
+ val action = FocusMeteringAction.Builder(validMeteringPoint, FLAG_AWB).build()
+ val future = camera.cameraControl.startFocusAndMetering(action)
- assertWithMessage("FocusMetering succeeded, should have failed for inactive camera!")
- .that(focusMeteringResultCallback.failureThrowable)
- .isInstanceOf(CameraControl.OperationCanceledException::class.java)
+ assertFutureCompletes(future)
}
- private fun hasMeteringRegion(selector: CameraSelector): Boolean {
+ @Test
+ fun futureCompletes_whenFocusMeteringWithAeAwb() {
+ assumeThat(
+ "b/270520932: IllegalArgumentException from Camera2 in CameraPipe",
+ implName, not(CameraPipeConfig::class.simpleName),
+ )
+
+ assumeThat(
+ "No AE/AWB region available on this device!",
+ hasMeteringRegion(cameraSelector, FLAG_AE or FLAG_AWB), equalTo(true)
+ )
+
+ val action = FocusMeteringAction.Builder(validMeteringPoint, FLAG_AE or FLAG_AWB).build()
+ val future = camera.cameraControl.startFocusAndMetering(action)
+
+ assertFutureCompletes(future)
+ }
+
+ @Test
+ fun futureCompletes_whenFocusMeteringWithMorePointsThanSupported() {
+ assumeThat(
+ "No AF/AE/AWB region available on this device!",
+ hasMeteringRegion(cameraSelector), equalTo(true)
+ )
+
+ val factory = SurfaceOrientedMeteringPointFactory(1f, 1f)
+ // Most devices don't support 4 AF/AE/AWB regions. but it should still complete.
+ val action = FocusMeteringAction.Builder(factory.createPoint(0f, 0f))
+ .addPoint(factory.createPoint(1f, 0f))
+ .addPoint(factory.createPoint(0.2f, 0.2f))
+ .addPoint(factory.createPoint(0.3f, 0.4f))
+ .build()
+ val future = camera.cameraControl.startFocusAndMetering(action)
+
+ assertFutureCompletes(future)
+ }
+
+ private fun hasMeteringRegion(
+ selector: CameraSelector,
+ @FocusMeteringAction.MeteringMode flags: Int = FLAG_AF or FLAG_AE or FLAG_AWB
+ ): Boolean {
return try {
val cameraCharacteristics = CameraUtil.getCameraCharacteristics(
selector.lensFacing!!
)
- cameraCharacteristics?.let { characteristics ->
- ((characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)!! > 0) ||
- (characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)!! > 0) ||
- (characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)!! > 0))
+ cameraCharacteristics?.run {
+ (if (flags.hasFlag(FLAG_AF)) (get(CONTROL_MAX_REGIONS_AF)!! > 0) else false) ||
+ (if (flags.hasFlag(FLAG_AE)) (get(CONTROL_MAX_REGIONS_AE)!! > 0) else false) ||
+ (if (flags.hasFlag(FLAG_AWB)) (get(CONTROL_MAX_REGIONS_AWB)!! > 0) else false)
} ?: false
} catch (e: Exception) {
false
}
}
- class FocusMeteringResultCallback : FutureCallback<FocusMeteringResult?> {
- private var latch = CountDownLatch(1)
+ private fun Int.hasFlag(flag: Int) = (this and flag) != 0
- @Volatile
- var successResult: FocusMeteringResult? = null
- @Volatile
- var failureThrowable: Throwable? = null
-
- override fun onSuccess(result: FocusMeteringResult?) {
- successResult = result
- latch.countDown()
+ private fun <T> assertFutureCompletes(future: ListenableFuture<T>) {
+ try {
+ future[10, TimeUnit.SECONDS]
+ } catch (e: Exception) {
+ Assert.fail("future fail:$e")
}
+ }
- override fun onFailure(t: Throwable) {
- failureThrowable = t
- latch.countDown()
+ private fun <T> assertFutureFailsWithIllegalArgumentException(future: ListenableFuture<T>) {
+ Assert.assertThrows(ExecutionException::class.java) {
+ future[10, TimeUnit.SECONDS]
+ }.apply {
+ assertThat(cause).isInstanceOf(IllegalArgumentException::class.java)
}
+ }
- suspend fun await(timeoutMs: Long = 10000) {
- withContext(Dispatchers.IO) {
- latch.await(timeoutMs, TimeUnit.MILLISECONDS)
- }
+ private fun <T> assertFutureFailsWithOperationCancellation(future: ListenableFuture<T>) {
+ Assert.assertThrows(ExecutionException::class.java) {
+ future[10, TimeUnit.SECONDS]
+ }.apply {
+ assertThat(cause).isInstanceOf(CameraControl.OperationCanceledException::class.java)
}
}
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/CameraControlDeviceTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/CameraControlDeviceTest.kt
index 9b35256ac99..82efaf21446 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/CameraControlDeviceTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/CameraControlDeviceTest.kt
@@ -16,13 +16,10 @@
package androidx.camera.integration.core.camera2
import android.content.Context
-import android.hardware.camera2.CameraCharacteristics
import androidx.camera.camera2.Camera2Config
import androidx.camera.camera2.pipe.integration.CameraPipeConfig
import androidx.camera.core.CameraSelector
-import androidx.camera.core.CameraSelector.LensFacing
import androidx.camera.core.CameraXConfig
-import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.camera.core.MeteringPoint
@@ -113,76 +110,6 @@ class CameraControlDeviceTest(
}
@Test
- fun startFocusMeteringAe_futureCompletes() {
- Assume.assumeTrue(isSupportAeRegion(cameraSelector))
- val action = FocusMeteringAction.Builder(
- meteringPoint1!!,
- FocusMeteringAction.FLAG_AE
- ).build()
- val future = camera!!.cameraControl.startFocusAndMetering(action)
- assertFutureCompletes(future)
- }
-
- @Test
- fun startFocusMeteringAwb_futureCompletes() {
- Assume.assumeTrue(isSupportAwbRegion(cameraSelector))
- val action = FocusMeteringAction.Builder(
- meteringPoint1!!,
- FocusMeteringAction.FLAG_AWB
- ).build()
- val future = camera!!.cameraControl.startFocusAndMetering(action)
- assertFutureCompletes(future)
- }
-
- @Test
- fun startFocusMeteringAeAwb_futureCompletes() {
- Assume.assumeTrue(isSupportAeRegion(cameraSelector) || isSupportAwbRegion(cameraSelector))
- val action = FocusMeteringAction.Builder(
- meteringPoint1!!,
- FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
- ).build()
- val future = camera!!.cameraControl.startFocusAndMetering(action)
- assertFutureCompletes(future)
- }
-
- @Test
- fun startFocusMeteringMorePointThanSupported_futureCompletes() {
- Assume.assumeTrue(isSupportAeRegion(cameraSelector) || isSupportAwbRegion(cameraSelector))
- val factory = SurfaceOrientedMeteringPointFactory(1f, 1f)
- // Most devices don't support 4 AF/AE/AWB regions. but it should still complete.
- val point1 = factory.createPoint(0f, 0f)
- val point2 = factory.createPoint(1f, 0f)
- val point3 = factory.createPoint(0.2f, 0.2f)
- val point4 = factory.createPoint(0.3f, 0.4f)
- val action = FocusMeteringAction.Builder(
- point1,
- FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
- )
- .addPoint(
- point2, FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
- )
- .addPoint(
- point3,
- FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
- )
- .addPoint(
- point4,
- FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
- )
- .build()
- val future = camera!!.cameraControl.startFocusAndMetering(action)
- assertFutureCompletes(future)
- }
-
- @Test
- fun cancelFocusMetering_futureCompletes() {
- val action = FocusMeteringAction.Builder(meteringPoint1!!).build()
- camera!!.cameraControl.startFocusAndMetering(action)
- val result = camera!!.cameraControl.cancelFocusAndMetering()
- assertFutureCompletes(result)
- }
-
- @Test
fun rebindAndEnableTorch_futureCompletes() {
Assume.assumeTrue(CameraUtil.hasFlashUnitWithLensFacing(cameraSelector.lensFacing!!))
instrumentation.runOnMainSync {
@@ -207,34 +134,6 @@ class CameraControlDeviceTest(
}
}
- private fun getCameraCharacteristicWithLensFacing(
- @LensFacing lensFacing: Int
- ): CameraCharacteristics? {
- return CameraUtil.getCameraCharacteristics(lensFacing)
- }
-
- private fun isSupportAeRegion(cameraSelector: CameraSelector?): Boolean {
- return try {
- val characteristics = getCameraCharacteristicWithLensFacing(
- cameraSelector!!.lensFacing!!
- )
- characteristics!!.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)!! > 0
- } catch (e: Exception) {
- false
- }
- }
-
- private fun isSupportAwbRegion(cameraSelector: CameraSelector?): Boolean {
- return try {
- val characteristics = getCameraCharacteristicWithLensFacing(
- cameraSelector!!.lensFacing!!
- )
- characteristics!!.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)!! > 0
- } catch (e: Exception) {
- false
- }
- }
-
companion object {
@JvmStatic
@Parameterized.Parameters(name = "selector={0},config={2}")