summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2014-06-03 18:30:27 -0700
committerEino-Ville Talvala <etalvala@google.com>2014-06-04 16:52:00 -0700
commit7fcb357811d4dc1f44624e30ad924e9e580d4cbf (patch)
tree051da2eb2fe60abe6de4adcdefe6aa944c479094 /core/java
parent648a309d9badc405bc969bcb4461369bf89fe7ef (diff)
downloadframeworks_base-7fcb357811d4dc1f44624e30ad924e9e580d4cbf.zip
frameworks_base-7fcb357811d4dc1f44624e30ad924e9e580d4cbf.tar.gz
frameworks_base-7fcb357811d4dc1f44624e30ad924e9e580d4cbf.tar.bz2
Camera2: Invoke onError callbacks for failure to open
When the initial attempt to connect to the remote camera device fails, fire the onError callback as documented, instead of throwing an exception from open(). Also ensure the correct exception is sent when methods are called while in the error state, and make sure onClosed() is called correctly if closing the device after an initial startup error. Bug: 14413756 Bug: 14413363 Change-Id: I0822261dad52bcd428a0c4556202f00032499990
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java21
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java77
2 files changed, 86 insertions, 12 deletions
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index e21fb1f..9046b13 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -226,7 +226,7 @@ public final class CameraManager {
synchronized (mLock) {
- ICameraDeviceUser cameraUser;
+ ICameraDeviceUser cameraUser = null;
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
@@ -248,8 +248,23 @@ public final class CameraManager {
// Use legacy camera implementation for HAL1 devices
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+ } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
+ e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
+ e.getReason() == CameraAccessException.CAMERA_DISABLED ||
+ e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
+ e.getReason() == CameraAccessException.CAMERA_ERROR) {
+ // Received one of the known connection errors
+ // The remote camera device cannot be connected to, so
+ // set the local camera to the startup error state
+ deviceImpl.setRemoteFailure(e);
+
+ if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
+ e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
+ // Per API docs, these failures call onError and throw
+ throw e;
+ }
} else {
- // Rethrow otherwise
+ // Unexpected failure - rethrow
throw e;
}
}
@@ -299,7 +314,7 @@ public final class CameraManager {
*
* <p>If opening the camera device fails, then the device listener's
* {@link CameraDevice.StateListener#onError onError} method will be called, and subsequent
- * calls on the camera device will throw an {@link IllegalStateException}.</p>
+ * calls on the camera device will throw a {@link CameraAccessException}.</p>
*
* @param cameraId
* The unique identifier of the camera device to open
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 81bd2fd..9795082 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -64,6 +64,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private volatile StateListener mSessionStateListener;
private final Handler mDeviceHandler;
+ private boolean mInError = false;
private boolean mIdle = true;
/** map request IDs to listener/request data */
@@ -211,6 +212,9 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
// TODO: Move from decorator to direct binder-mediated exceptions
synchronized(mLock) {
+ // If setRemoteFailure already called, do nothing
+ if (mInError) return;
+
mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
mDeviceHandler.post(mCallOnOpened);
@@ -218,6 +222,52 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ /**
+ * Call to indicate failed connection to a remote camera device.
+ *
+ * <p>This places the camera device in the error state and informs the listener.
+ * Use in place of setRemoteDevice() when startup fails.</p>
+ */
+ public void setRemoteFailure(final CameraRuntimeException failure) {
+ int failureCode = StateListener.ERROR_CAMERA_DEVICE;
+ boolean failureIsError = true;
+
+ switch (failure.getReason()) {
+ case CameraAccessException.CAMERA_IN_USE:
+ failureCode = StateListener.ERROR_CAMERA_IN_USE;
+ break;
+ case CameraAccessException.MAX_CAMERAS_IN_USE:
+ failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
+ break;
+ case CameraAccessException.CAMERA_DISABLED:
+ failureCode = StateListener.ERROR_CAMERA_DISABLED;
+ break;
+ case CameraAccessException.CAMERA_DISCONNECTED:
+ failureIsError = false;
+ break;
+ case CameraAccessException.CAMERA_ERROR:
+ failureCode = StateListener.ERROR_CAMERA_DEVICE;
+ break;
+ default:
+ Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
+ break;
+ }
+ final int code = failureCode;
+ final boolean isError = failureIsError;
+ synchronized (mLock) {
+ mInError = true;
+ mDeviceHandler.post(new Runnable() {
+ public void run() {
+ if (isError) {
+ mDeviceListener.onError(CameraDeviceImpl.this, code);
+ } else {
+ mDeviceListener.onDisconnected(CameraDeviceImpl.this);
+ }
+ }
+ });
+ }
+ }
+
@Override
public String getId() {
return mCameraId;
@@ -230,7 +280,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
outputs = new ArrayList<Surface>();
}
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
@@ -298,7 +348,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
Log.d(TAG, "createCaptureSession");
}
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
// TODO: we must be in UNCONFIGURED mode to begin with, or using another session
@@ -336,7 +386,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
public CaptureRequest.Builder createCaptureRequest(int templateType)
throws CameraAccessException {
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
CameraMetadataNative templatedRequest = new CameraMetadataNative();
@@ -456,7 +506,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
int requestId;
if (repeating) {
@@ -528,7 +578,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
public void stopRepeating() throws CameraAccessException {
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
if (mRepeatingRequestId != REQUEST_ID_NONE) {
int requestId = mRepeatingRequestId;
@@ -559,7 +609,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private void waitUntilIdle() throws CameraAccessException {
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
if (mRepeatingRequestId != REQUEST_ID_NONE) {
throw new IllegalStateException("Active repeating request ongoing");
}
@@ -580,7 +630,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
@Override
public void flush() throws CameraAccessException {
synchronized (mLock) {
- checkIfCameraClosed();
+ checkIfCameraClosedOrInError();
mDeviceHandler.post(mCallOnBusy);
try {
@@ -614,11 +664,15 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
// impossible
}
- if (mRemoteDevice != null) {
+ // Only want to fire the onClosed callback once;
+ // either a normal close where the remote device is valid
+ // or a close after a startup error (no remote device but in error state)
+ if (mRemoteDevice != null || mInError) {
mDeviceHandler.post(mCallOnClosed);
}
mRemoteDevice = null;
+ mInError = false;
}
}
@@ -835,6 +889,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (isClosed()) return;
synchronized(mLock) {
+ mInError = true;
switch (errorCode) {
case ERROR_CAMERA_DISCONNECTED:
r = mCallOnDisconnected;
@@ -1032,7 +1087,11 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return handler;
}
- private void checkIfCameraClosed() {
+ private void checkIfCameraClosedOrInError() throws CameraAccessException {
+ if (mInError) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
+ "The camera device has encountered a serious error");
+ }
if (mRemoteDevice == null) {
throw new IllegalStateException("CameraDevice was already closed");
}