public abstract class

CameraState

extends java.lang.Object

 java.lang.Object

↳androidx.camera.core.CameraState

Gradle dependencies

compile group: 'androidx.camera', name: 'camera-core', version: '1.2.0-alpha01'

  • groupId: androidx.camera
  • artifactId: camera-core
  • version: 1.2.0-alpha01

Artifact androidx.camera:camera-core:1.2.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Represents the different states the camera can be in.

The following table displays the states the camera can be in, and the possible transitions between them.

State Transition cause New State
CLOSED Received signal to open camera, and camera unavailable PENDING_OPEN
Received signal to open camera, and camera available OPENING
PENDING_OPEN Received signal that camera is available OPENING
OPENING Camera opened successfully OPEN
Camera encountered recoverable error while opening OPENING(Error)
Camera encountered critical error while opening CLOSING(Error)
Camera opening failed prematurely CLOSED(Error)
Reached max limit of camera (re)open attempts PENDING_OPEN
OPEN Camera encountered recoverable error OPENING(Error)
Camera encountered critical error CLOSING(Error)
Received signal to close camera CLOSING
CLOSING Camera closed CLOSED

Initially, a camera is in a CameraState.Type.CLOSED state. When it receives a signal to open, for example after one or multiple use cases are attached to it, its state moves to the CameraState.Type.OPENING state. If it successfully opens the camera device, its state moves to the CameraState.Type.OPEN state, otherwise, it may move to a different state depending on the error it encountered:

  • If opening the camera device fails prematurely, for example, when "Do Not Disturb" mode is enabled on a device that's affected by a bug in Android 9 (see CameraState.ERROR_DO_NOT_DISTURB_MODE_ENABLED), the state moves to the CameraState.Type.CLOSED state .
  • If the error is recoverable, CameraX will attempt to reopen the camera device. If a recovery attempt succeeds, the camera state moves to the CameraState.Type.OPEN state, however, if all recovery attempts are unsuccessful, the camera waits in a CameraState.Type.PENDING_OPEN state to attempt recovery again once the camera device's availability changes.
  • If the error is critical, and requires the intervention of the developer or user, the camera's state moves to the CameraState.Type.CLOSING state.

While in the CameraState.Type.PENDING_OPEN state, the camera waits for a signal indicating the camera device's availability. The signal can either be an external one from the camera service, or an internal one from within CameraX. When received, the camera's state moves to the CameraState.Type.OPENING state, and an attempt to open the camera device is made.

While in the CameraState.Type.OPEN state, the camera device may be disconnected due to an error. In this case, depending on whether the error is critical or recoverable, CameraX may or may not attempt to recover from it, thus the state will move to either a CameraState.Type.CLOSING or CameraState.Type.OPENING state.

If the camera is in an CameraState.Type.OPEN state and receives a signal to close the camera device, for example when all its previously attached use cases are detached, its state moves to the CameraState.Type.CLOSING state. Once the camera device finishes closing, the camera state moves to the CameraState.Type.CLOSED state.

Whenever the camera encounters an error, it reports it through CameraState.getError().

Summary

Fields
public static final intERROR_CAMERA_DISABLED

An error indicating that the camera device could not be opened due to a device policy.

public static final intERROR_CAMERA_FATAL_ERROR

An error indicating that the camera device was closed due to a fatal error.

public static final intERROR_CAMERA_IN_USE

An error indicating that the camera device is already in use.

public static final intERROR_DO_NOT_DISTURB_MODE_ENABLED

An error indicating that the camera could not be opened because "Do Not Disturb" mode is enabled on devices affected by a bug in Android 9 (API level 28).

public static final intERROR_MAX_CAMERAS_IN_USE

An error indicating that the limit number of open cameras has been reached, and more cameras cannot be opened until other instances are closed.

public static final intERROR_OTHER_RECOVERABLE_ERROR

An error indicating that the camera device has encountered a recoverable error.

public static final intERROR_STREAM_CONFIG

An error indicating that configuring the camera has failed.

Constructors
publicCameraState()

Methods
public static CameraStatecreate(CameraState.Type type)

Create a new CameraState instance from a CameraState.Type and a null CameraState.StateError.

public static CameraStatecreate(CameraState.Type type, CameraState.StateError error)

Create a new CameraState instance from a CameraState.Type and a potential CameraState.StateError.

public abstract CameraState.StateErrorgetError()

Potentially returns an error the camera encountered.

public abstract CameraState.TypegetType()

Returns the camera's state.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int ERROR_MAX_CAMERAS_IN_USE

An error indicating that the limit number of open cameras has been reached, and more cameras cannot be opened until other instances are closed.

public static final int ERROR_CAMERA_IN_USE

An error indicating that the camera device is already in use.

This could be due to the camera device being used by a higher-priority camera client.

public static final int ERROR_OTHER_RECOVERABLE_ERROR

An error indicating that the camera device has encountered a recoverable error.

CameraX will attempt to recover from the error, it if succeeds in doing so, the camera will open, otherwise the camera will move to a CameraState.Type.PENDING_OPEN state. When CameraX uses a android.hardware.camera2 implementation, this error represents a error.

public static final int ERROR_STREAM_CONFIG

An error indicating that configuring the camera has failed.

public static final int ERROR_CAMERA_DISABLED

An error indicating that the camera device could not be opened due to a device policy.

The error may be encountered if a client from a background process attempts to open the camera.

See also:

public static final int ERROR_CAMERA_FATAL_ERROR

An error indicating that the camera device was closed due to a fatal error.

The error may require the Android device to be shut down and restarted to restore camera function. It may also indicate the existence of a persistent camera hardware problem. When CameraX uses a android.hardware.camera2 implementation, this error represents a error.

public static final int ERROR_DO_NOT_DISTURB_MODE_ENABLED

An error indicating that the camera could not be opened because "Do Not Disturb" mode is enabled on devices affected by a bug in Android 9 (API level 28).

When "Do Not Disturb" mode is enabled, opening the camera device fails on certain Android devices running on an early Android 9 release with a camera hardware level.

CameraX will not attempt to reopen the camera device, instead, disable the "Do Not Disturb" mode, then explicitly open the camera again.

Constructors

public CameraState()

Methods

public static CameraState create(CameraState.Type type)

Create a new CameraState instance from a CameraState.Type and a null CameraState.StateError.

A CameraState is not expected to be instantiated in normal operation.

public static CameraState create(CameraState.Type type, CameraState.StateError error)

Create a new CameraState instance from a CameraState.Type and a potential CameraState.StateError.

A CameraState is not expected to be instantiated in normal operation.

public abstract CameraState.Type getType()

Returns the camera's state.

Returns:

The camera's state

public abstract CameraState.StateError getError()

Potentially returns an error the camera encountered.

Returns:

An error the camera encountered, or null otherwise.

Source

/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.camera.core;

import android.content.ComponentName;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.google.auto.value.AutoValue;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Represents the different states the camera can be in.
 *
 * <p>The following table displays the states the camera can be in, and the possible transitions
 * between them.
 *
 * <table>
 * <tr>
 *     <th>State</th>
 *     <th>Transition cause</th>
 *     <th>New State</th>
 * </tr>
 * <tr>
 *     <td rowspan="2">CLOSED</td>
 *     <td>Received signal to open camera, and camera unavailable</td>
 *     <td>PENDING_OPEN</td>
 * </tr>
 * <tr>
 *     <td>Received signal to open camera, and camera available</td>
 *     <td>OPENING</td>
 * </tr>
 * <tr>
 *     <td>PENDING_OPEN</td>
 *     <td>Received signal that camera is available</td>
 *     <td>OPENING</td>
 * </tr>
 * <tr>
 *     <td rowspan="5">OPENING</td>
 *     <td>Camera opened successfully</td>
 *     <td>OPEN</td>
 * </tr>
 * <tr>
 *     <td>Camera encountered recoverable error while opening</td>
 *     <td>OPENING(Error)</td>
 * </tr>
 * <tr>
 *     <td>Camera encountered critical error while opening</td>
 *     <td>CLOSING(Error)</td>
 * </tr>
 * <tr>
 *     <td>Camera opening failed prematurely</td>
 *     <td>CLOSED(Error)</td>
 * </tr>
 * <tr>
 *     <td>Reached max limit of camera (re)open attempts</td>
 *     <td>PENDING_OPEN</td>
 * </tr>
 * <tr>
 *     <td rowspan="3">OPEN</td>
 *     <td>Camera encountered recoverable error</td>
 *     <td>OPENING(Error)</td>
 * </tr>
 * <tr>
 *     <td>Camera encountered critical error</td>
 *     <td>CLOSING(Error)</td>
 * </tr>
 * <tr>
 *     <td>Received signal to close camera</td>
 *     <td>CLOSING</td>
 * </tr>
 * <tr>
 *     <td>CLOSING</td>
 *     <td>Camera closed</td>
 *     <td>CLOSED</td>
 * </tr>
 * </table>
 *
 * <p>Initially, a camera is in a {@link Type#CLOSED} state. When it receives a signal to open, for
 * example after one or multiple {@linkplain UseCase use cases} are attached to it, its state
 * moves to the {@link Type#OPENING} state. If it successfully opens the camera device, its state
 * moves to the {@link Type#OPEN} state, otherwise, it may move to a different state depending on
 * the error it encountered:
 *
 * <ul>
 * <li>If opening the camera device fails prematurely, for example, when "Do Not Disturb" mode is
 * enabled on a device that's affected by a bug in Android 9 (see
 * {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}), the state moves to the {@link Type#CLOSED} state
 * .</li>
 * <li>If the error is recoverable, CameraX will attempt to reopen the camera device. If a recovery
 * attempt succeeds, the camera state moves to the {@link Type#OPEN} state, however, if all recovery
 * attempts are unsuccessful, the camera waits in a {@link Type#PENDING_OPEN} state to attempt
 * recovery again once the camera device's availability changes.</li>
 * <li>If the error is critical, and requires the intervention of the developer or user, the
 * camera's state moves to the {@link Type#CLOSING} state.</li>
 * </ul>
 *
 * <p>While in the {@link Type#PENDING_OPEN} state, the camera waits for a signal indicating the
 * camera device's availability. The signal can either be an external one from the camera service,
 * or an internal one from within CameraX. When received, the camera's state moves to the
 * {@link Type#OPENING} state, and an attempt to open the camera device is made.
 *
 * <p>While in the {@link Type#OPEN} state, the camera device may be disconnected due to an error.
 * In this case, depending on whether the error is critical or recoverable, CameraX may or may not
 * attempt to recover from it, thus the state will move to either a {@link Type#CLOSING} or
 * {@link Type#OPENING} state.
 *
 * <p>If the camera is in an {@link Type#OPEN} state and receives a signal to close the camera
 * device, for example when all its previously attached {@link UseCase use cases} are detached,
 * its state moves to the {@link Type#CLOSING} state. Once the camera device finishes closing,
 * the camera state moves to the {@link Type#CLOSED} state.
 *
 * <p>Whenever the camera encounters an error, it reports it through {@link #getError()}.
 */
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@AutoValue
public abstract class CameraState {

    /**
     * An error indicating that the limit number of open cameras has been reached, and more
     * cameras cannot be opened until other instances are closed.
     */
    @SuppressWarnings("MinMaxConstant")
    public static final int ERROR_MAX_CAMERAS_IN_USE = 1;

    /**
     * An error indicating that the camera device is already in use.
     *
     * <p>This could be due to the camera device being used by a higher-priority camera client.
     */
    public static final int ERROR_CAMERA_IN_USE = 2;

    /**
     * An error indicating that the camera device has encountered a recoverable error.
     *
     * <p>CameraX will attempt to recover from the error, it if succeeds in doing so, the
     * camera will open, otherwise the camera will move to a {@link Type#PENDING_OPEN} state.
     *
     * When CameraX uses a {@link android.hardware.camera2} implementation, this error represents
     * a {@link android.hardware.camera2.CameraDevice.StateCallback#ERROR_CAMERA_DEVICE} error.
     */
    public static final int ERROR_OTHER_RECOVERABLE_ERROR = 3;

    /** An error indicating that configuring the camera has failed. */
    public static final int ERROR_STREAM_CONFIG = 4;

    /**
     * An error indicating that the camera device could not be opened due to a device policy.
     *
     * <p>The error may be encountered if a client from a background process attempts to open the
     * camera.
     *
     * @see android.app.admin.DevicePolicyManager#setCameraDisabled(ComponentName, boolean)
     */
    public static final int ERROR_CAMERA_DISABLED = 5;

    /**
     * An error indicating that the camera device was closed due to a fatal error.
     *
     * <p>The error may require the Android device to be shut down and restarted to restore camera
     * function. It may also indicate the existence of a persistent camera hardware problem.
     *
     * When CameraX uses a {@link android.hardware.camera2} implementation, this error represents
     * a {@link android.hardware.camera2.CameraDevice.StateCallback#ERROR_CAMERA_SERVICE} error.
     */
    public static final int ERROR_CAMERA_FATAL_ERROR = 6;

    /**
     * An error indicating that the camera could not be opened because "Do Not Disturb" mode is
     * enabled on devices affected by a bug in Android 9 (API level 28).
     *
     * <p>When "Do Not Disturb" mode is enabled, opening the camera device fails on certain
     * Android devices running on an early Android 9 release with a
     * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}
     * camera hardware level.
     *
     * <p>CameraX will not attempt to reopen the camera device, instead, disable the "Do Not
     * Disturb" mode, then explicitly open the camera again.
     */
    public static final int ERROR_DO_NOT_DISTURB_MODE_ENABLED = 7;

    /**
     * Create a new {@link CameraState} instance from a {@link Type} and a {@code null}
     * {@link StateError}.
     *
     * <p>A {@link CameraState} is not expected to be instantiated in normal operation.
     */
    @NonNull
    public static CameraState create(@NonNull Type type) {
        return create(type, null);
    }

    /**
     * Create a new {@link CameraState} instance from a {@link Type} and a potential
     * {@link StateError}.
     *
     * <p>A {@link CameraState} is not expected to be instantiated in normal operation.
     */
    @NonNull
    public static CameraState create(@NonNull Type type, @Nullable StateError error) {
        return new AutoValue_CameraState(type, error);
    }

    /**
     * Returns the camera's state.
     *
     * @return The camera's state
     */
    @NonNull
    public abstract Type getType();

    /**
     * Potentially returns an error the camera encountered.
     *
     * @return An error the camera encountered, or {@code null} otherwise.
     */
    @Nullable
    public abstract StateError getError();

    @IntDef(value = {
            ERROR_CAMERA_IN_USE,
            ERROR_MAX_CAMERAS_IN_USE,
            ERROR_OTHER_RECOVERABLE_ERROR,
            ERROR_STREAM_CONFIG,
            ERROR_CAMERA_DISABLED,
            ERROR_CAMERA_FATAL_ERROR,
            ERROR_DO_NOT_DISTURB_MODE_ENABLED})
    @Retention(RetentionPolicy.SOURCE)
    @interface ErrorCode {
    }

    /**
     * Types of errors the camera can encounter.
     *
     * <p>CameraX tries to recover from recoverable errors, which include
     * {@link #ERROR_CAMERA_IN_USE}, {@link #ERROR_MAX_CAMERAS_IN_USE} and
     * {@link #ERROR_OTHER_RECOVERABLE_ERROR}. The rest of the errors are critical, and require
     * the intervention of the developer or user to restore camera function. These errors include
     * {@link #ERROR_STREAM_CONFIG}, {@link #ERROR_CAMERA_DISABLED},
     * {@link #ERROR_CAMERA_FATAL_ERROR} and {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
     */
    public enum ErrorType {
        /**
         * An error the camera encountered that CameraX will attempt to recover from.
         *
         * <p>Recoverable errors include {@link #ERROR_CAMERA_IN_USE},
         * {@link #ERROR_MAX_CAMERAS_IN_USE} and {@link #ERROR_OTHER_RECOVERABLE_ERROR}.
         */
        RECOVERABLE,

        /**
         * An error the camera encountered that CameraX will not attempt to recover from.
         *
         * <p>A critical error is one that requires the intervention of the developer or user to
         * restore camera function, and includes {@link #ERROR_STREAM_CONFIG},
         * {@link #ERROR_CAMERA_DISABLED}, {@link #ERROR_CAMERA_FATAL_ERROR} and
         * {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
         */
        CRITICAL
    }

    /** States the camera can be in. */
    public enum Type {
        /**
         * Represents a state where the camera is waiting for a signal to attempt to open the camera
         * device.
         *
         * <p>The camera can move to this state from a {@link Type#CLOSED} or {@link Type#OPENING}
         * state:
         * <ul>
         * <li>It moves to this state from a {@link Type#CLOSED} state if it attempts to open an
         * unavailable camera device. A camera device is unavailable for opening if (a) it's
         * already in use by another camera client, for example one with higher priority or (b)
         * the maximum number of cameras allowed to be open at the same time in CameraX has been
         * reached, this limit is currently set to 1.</li>
         * <li>It moves to this state from an {@link Type#OPENING} state if it reaches the
         * maximum number of camera reopen attempts while trying to recover from a camera opening
         * error.</li>
         * </ul>
         *
         * <p>While in this state, the camera waits for an external signal from the camera
         * service or an internal one from CameraX to attempt to reopen the camera device.
         *
         * <p>Developers may rely on this state to close any other open cameras in the app, or
         * request their user close an open camera in another app.
         */
        PENDING_OPEN,

        /**
         * Represents a state where the camera device is currently opening.
         *
         * <p>The camera can move to this state from a {@link Type#PENDING_OPEN} or
         * {@link Type#CLOSED} state: It moves to this state from a {@link Type#PENDING_OPEN}
         * state after it receives a signal that the camera is available to open, and from a
         * {@link Type#CLOSED} state after a request to open the camera is made, and the camera
         * is available to open.
         *
         * <p>While in this state, the camera is actively attempting to open the camera device.
         * This takes several hundred milliseconds on most devices. If it succeeds, the state
         * moves to the {@link Type#OPEN} state. If it fails however, the camera may attempt to
         * reopen the camera device a certain number of times. While this is happening, the
         * camera state remains the same, i.e. in an opening state, and it exposes the error it
         * encountered through {@link #getError()}.
         *
         * <p>Developers can rely on this state to be aware of when the camera is actively
         * attempting to open the camera device, this allows them to communicate it to their
         * users through the UI.
         */
        OPENING,

        /**
         * Represents a state where the camera device is open.
         *
         * <p>The camera can only move to this state from an {@link Type#OPENING} state.
         *
         * <p>Once in this state, active {@linkplain UseCase use cases} attached to this camera
         * could expect to shortly start receiving camera frames.
         *
         * <p>Developers can rely on this state to be notified of when the camera device is actually
         * ready for use, and can then set up camera dependent resources, especially if they're
         * heavyweight.
         */
        OPEN,

        /**
         * Represents a state where the camera device is currently closing.
         *
         * <p>The camera can move to this state from an {@link Type#OPEN} or {@link Type#OPENING}
         * state: It moves to this state from an {@link Type#OPEN} state after it receives a
         * signal to close the camera device, this can be after all its attached
         * {@linkplain UseCase use cases} are detached, and from an {@link Type#OPENING} state if
         * the camera encounters a fatal error it cannot recover from.
         *
         * <p>Developers can rely on this state to be aware of when the camera device is actually
         * in the process of closing. this allows them to communicate it to their users through
         * the UI.
         */
        CLOSING,

        /**
         * Represents a state where the camera device is closed.
         *
         * <p>The camera is initially in this state, and can move back to it from a
         * {@link Type#CLOSING} or {@link Type#OPENING} state: It moves to this state from a
         * {@link Type#CLOSING} state after the camera device successfully closes, and from an
         * {@link Type#OPENING} state when opening a camera device that is unavailable due to
         * {@link android.app.NotificationManager.Policy}, as some API level 28 devices cannot
         * access the camera when the device is in "Do Not Disturb" mode.
         *
         * <p>Developers can rely on this state to be notified of when the camera device is actually
         * closed, and then use this signal to free up camera resources, or start the camera device
         * with another camera client.
         */
        CLOSED
    }

    /**
     * Error that the camera has encountered.
     *
     * <p>The camera may report an error when it's in one of the following states:
     * {@link Type#OPENING}, {@link Type#OPEN}, {@link Type#CLOSING} and {@link Type#CLOSED}.
     *
     * <p>CameraX attempts to recover from certain errors it encounters when opening the camera
     * device, in these instances, the error is {@linkplain ErrorType#RECOVERABLE recoverable},
     * otherwise, the error is {@linkplain ErrorType#CRITICAL critical}.
     *
     * <p>When CameraX encounters a critical error, the developer and/or user must intervene to
     * restore camera function. When the error is recoverable, the developer and/or user can
     * still aid in the recovery process, as shown in the following table.
     * <table>
     * <tr>
     *     <th>State</th>
     *     <th>Error Code</th>
     *     <th>Recoverable</th>
     *     <th>How to handle it</th>
     * </tr>
     * <tr>
     *     <td>{@link Type#OPEN}</td>
     *     <td>{@linkplain #ERROR_STREAM_CONFIG ERROR_STREAM_CONFIG}</td>
     *     <td>No</td>
     *     <td>Make sure you set up your {@linkplain UseCase use cases} correctly.</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#OPENING}</td>
     *     <td>{@linkplain #ERROR_CAMERA_IN_USE ERROR_CAMERA_IN_USE}</td>
     *     <td>Yes</td>
     *     <td>Close the camera, or ask the user to close another camera app that is using the
     *     camera.</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#OPENING}</td>
     *     <td>{@linkplain #ERROR_MAX_CAMERAS_IN_USE ERROR_MAX_CAMERAS_IN_USE}</td>
     *     <td>Yes</td>
     *     <td>Close another open camera in the app, or ask the user to close another camera
     *     app that's using the camera.</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#OPENING}</td>
     *     <td>{@linkplain #ERROR_OTHER_RECOVERABLE_ERROR ERROR_OTHER_RECOVERABLE_ERROR}</td>
     *     <td>Yes</td>
     *     <td>N/A</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#CLOSING}</td>
     *     <td>{@linkplain #ERROR_CAMERA_DISABLED ERROR_CAMERA_DISABLED}</td>
     *     <td>No</td>
     *     <td>Ask the user to enable the device's cameras.</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#CLOSING}</td>
     *     <td>{@linkplain #ERROR_CAMERA_FATAL_ERROR ERROR_CAMERA_FATAL_ERROR}</td>
     *     <td>No</td>
     *     <td>Ask the user to reboot the device to restore camera function.</td>
     * </tr>
     * <tr>
     *     <td>{@link Type#CLOSED}</td>
     *     <td>{@linkplain #ERROR_DO_NOT_DISTURB_MODE_ENABLED
     *     ERROR_DO_NOT_DISTURB_MODE_ENABLED}</td>
     *     <td>No</td>
     *     <td>Ask the user to disable "Do Not Disturb" mode, then open the camera again.</td>
     * </tr>
     * </table>
     */
    @AutoValue
    public abstract static class StateError {

        /**
         * Creates a {@link StateError} with an error code.
         *
         * <p>A {@link StateError} is not expected to be instantiated in normal operation.
         */
        @NonNull
        public static StateError create(@ErrorCode int error) {
            return create(error, null);
        }

        /**
         * Creates a {@link StateError} with an error code and a {@linkplain Throwable cause}.
         *
         * <p>A {@link StateError} is not expected to be instantiated in normal operation.
         */
        @NonNull
        public static StateError create(@ErrorCode int error, @Nullable Throwable cause) {
            return new AutoValue_CameraState_StateError(error, cause);
        }

        /**
         * Returns the code of this error.
         *
         * <p>The error's code is one of the following: {@link #ERROR_CAMERA_IN_USE},
         * {@link #ERROR_MAX_CAMERAS_IN_USE}, {@link #ERROR_OTHER_RECOVERABLE_ERROR},
         * {@link #ERROR_STREAM_CONFIG}, {@link #ERROR_CAMERA_DISABLED},
         * {@link #ERROR_CAMERA_FATAL_ERROR} and {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
         *
         * @return The code of this error.
         */
        @ErrorCode
        public abstract int getCode();

        /**
         * Returns a potential cause of this error.
         *
         * @return The cause of this error, or {@code null} if the cause was not supplied.
         */
        @Nullable
        public abstract Throwable getCause();

        /**
         * Returns the type of this error.
         *
         * <p>An error can either be {@linkplain ErrorType#RECOVERABLE recoverable} or
         * {@linkplain ErrorType#CRITICAL critical}.
         *
         * @return The type of this error
         */
        @NonNull
        public ErrorType getType() {
            int code = getCode();
            if (code == ERROR_CAMERA_IN_USE || code == ERROR_MAX_CAMERAS_IN_USE
                    || code == ERROR_OTHER_RECOVERABLE_ERROR) {
                return ErrorType.RECOVERABLE;
            }
            return ErrorType.CRITICAL;
        }
    }
}