Merge "CameraController: catch invalid UseCase combination error in LifecycleCameraController" into androidx-main
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
index 630e7f3..fcd7805 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
@@ -112,6 +112,35 @@
}
}
+ @Test(expected = IllegalArgumentException::class)
+ fun setInvalidEffectsCombination_throwsException() {
+ // Arrange: setup PreviewView and CameraController
+ var previewView: PreviewView? = null
+ activityScenario!!.onActivity {
+ // Arrange.
+ previewView = PreviewView(context)
+ it.setContentView(previewView)
+ previewView!!.controller = controller
+ controller!!.bindToLifecycle(FakeLifecycleOwner())
+ controller!!.initializationFuture.get()
+ }
+ waitUtilPreviewViewIsReady(previewView!!)
+
+ // Act: set the same effect twice, which is invalid.
+ val previewEffect = FakePreviewEffect(
+ mainThreadExecutor(),
+ FakeSurfaceProcessor(mainThreadExecutor())
+ )
+ instrumentation.runOnMainSync {
+ controller!!.setEffects(
+ listOf(
+ previewEffect,
+ previewEffect
+ )
+ )
+ }
+ }
+
@Test
fun setEffectBundle_effectSetOnUseCase() {
// Arrange: setup PreviewView and CameraController
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index ce1a726..6a9ec13 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -420,6 +420,9 @@
/**
* Implemented by children to refresh after {@link UseCase} is changed.
+ *
+ * @throws IllegalStateException for invalid {@link UseCase} combinations.
+ * @throws RuntimeException for invalid {@link CameraEffect} combinations.
*/
@Nullable
abstract Camera startCamera();
@@ -1928,21 +1931,19 @@
/**
* @param restoreStateRunnable runnable to restore the controller to the previous good state if
* the binding fails.
- * @throws IllegalStateException if binding fails.
+ * @throws IllegalStateException for invalid {@link UseCase} combinations.
+ * @throws RuntimeException for invalid {@link CameraEffect} combinations.
*/
void startCameraAndTrackStates(@Nullable Runnable restoreStateRunnable) {
try {
mCamera = startCamera();
- } catch (IllegalArgumentException exception) {
+ } catch (RuntimeException exception) {
+ // Restore the previous state before re-throwing the exception.
if (restoreStateRunnable != null) {
restoreStateRunnable.run();
}
- // Catches the core exception and throw a more readable one.
- String errorMessage =
- "The selected camera does not support the enabled use cases. Please "
- + "disable use case and/or select a different camera. e.g. "
- + "#setVideoCaptureEnabled(false)";
- throw new IllegalStateException(errorMessage, exception);
+ // This exception will handled by the app.
+ throw exception;
}
if (!isCameraAttached()) {
Logger.d(TAG, CAMERA_NOT_ATTACHED);
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/LifecycleCameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/LifecycleCameraController.java
index 2f751af..9f695f9 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/LifecycleCameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/LifecycleCameraController.java
@@ -30,6 +30,7 @@
import androidx.annotation.RequiresPermission;
import androidx.annotation.RestrictTo;
import androidx.camera.core.Camera;
+import androidx.camera.core.CameraEffect;
import androidx.camera.core.UseCase;
import androidx.camera.core.UseCaseGroup;
import androidx.camera.core.impl.utils.Threads;
@@ -109,6 +110,8 @@
* Unbind and rebind all use cases to {@link LifecycleOwner}.
*
* @return null if failed to start camera.
+ * @throws IllegalStateException for invalid {@link UseCase} combinations.
+ * @throws RuntimeException for invalid {@link CameraEffect} combinations.
*/
@RequiresPermission(Manifest.permission.CAMERA)
@Override
@@ -128,7 +131,16 @@
// Use cases can't be created.
return null;
}
- return mCameraProvider.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCaseGroup);
+ try {
+ return mCameraProvider.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCaseGroup);
+ } catch (IllegalArgumentException e) {
+ // Catches the invalid use case combination exception and throw a more readable one.
+ String errorMessage =
+ "The selected camera does not support the enabled use cases. Please "
+ + "disable use case and/or select a different camera. e.g. "
+ + "#setVideoCaptureEnabled(false)";
+ throw new IllegalStateException(errorMessage, e);
+ }
}
/**