Loading core/java/android/hardware/camera2/CameraManager.java +18 −3 Original line number Diff line number Diff line Loading @@ -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( Loading @@ -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; } } Loading Loading @@ -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 Loading core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +68 −9 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -456,7 +506,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice { } synchronized (mLock) { checkIfCameraClosed(); checkIfCameraClosedOrInError(); int requestId; if (repeating) { Loading Loading @@ -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; Loading Loading @@ -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"); } Loading @@ -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 { Loading Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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"); } Loading Loading
core/java/android/hardware/camera2/CameraManager.java +18 −3 Original line number Diff line number Diff line Loading @@ -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( Loading @@ -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; } } Loading Loading @@ -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 Loading
core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +68 −9 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -456,7 +506,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice { } synchronized (mLock) { checkIfCameraClosed(); checkIfCameraClosedOrInError(); int requestId; if (repeating) { Loading Loading @@ -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; Loading Loading @@ -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"); } Loading @@ -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 { Loading Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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"); } Loading