Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5308480 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala Committed by Android (Google) Code Review
Browse files

Merge "Camera2: Invoke onError callbacks for failure to open" into lmp-preview-dev

parents 58ff7de9 7fcb3578
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -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
+68 −9
Original line number Diff line number Diff line
@@ -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");
        }