diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index e21fb1fff95bf..9046b136e3c13 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 { * *
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}.
+ * calls on the camera device will throw a {@link CameraAccessException}. * * @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 81bd2fd448754..97950827b6882 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. + * + *This places the camera device in the error state and informs the listener. + * Use in place of setRemoteDevice() when startup fails.
+ */ + 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