1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.camera.core;
18 
19 import android.content.ComponentName;
20 
21 import androidx.annotation.IntDef;
22 
23 import com.google.auto.value.AutoValue;
24 
25 import org.jspecify.annotations.NonNull;
26 import org.jspecify.annotations.Nullable;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 
31 /**
32  * Represents the different states the camera can be in.
33  *
34  * <p>The following table displays the states the camera can be in, and the possible transitions
35  * between them.
36  *
37  * <table>
38  * <tr>
39  *     <th>State</th>
40  *     <th>Transition cause</th>
41  *     <th>New State</th>
42  * </tr>
43  * <tr>
44  *     <td rowspan="2">CLOSED</td>
45  *     <td>Received signal to open camera, and camera unavailable</td>
46  *     <td>PENDING_OPEN</td>
47  * </tr>
48  * <tr>
49  *     <td>Received signal to open camera, and camera available</td>
50  *     <td>OPENING</td>
51  * </tr>
52  * <tr>
53  *     <td>PENDING_OPEN</td>
54  *     <td>Received signal that camera is available</td>
55  *     <td>OPENING</td>
56  * </tr>
57  * <tr>
58  *     <td rowspan="5">OPENING</td>
59  *     <td>Camera opened successfully</td>
60  *     <td>OPEN</td>
61  * </tr>
62  * <tr>
63  *     <td>Camera encountered recoverable error while opening</td>
64  *     <td>OPENING(Error)</td>
65  * </tr>
66  * <tr>
67  *     <td>Camera encountered critical error while opening</td>
68  *     <td>CLOSING(Error)</td>
69  * </tr>
70  * <tr>
71  *     <td>Camera opening failed prematurely</td>
72  *     <td>CLOSED(Error)</td>
73  * </tr>
74  * <tr>
75  *     <td>Reached max limit of camera (re)open attempts</td>
76  *     <td>PENDING_OPEN</td>
77  * </tr>
78  * <tr>
79  *     <td rowspan="3">OPEN</td>
80  *     <td>Camera encountered recoverable error</td>
81  *     <td>OPENING(Error)</td>
82  * </tr>
83  * <tr>
84  *     <td>Camera encountered critical error</td>
85  *     <td>CLOSING(Error)</td>
86  * </tr>
87  * <tr>
88  *     <td>Received signal to close camera</td>
89  *     <td>CLOSING</td>
90  * </tr>
91  * <tr>
92  *     <td>CLOSING</td>
93  *     <td>Camera closed</td>
94  *     <td>CLOSED</td>
95  * </tr>
96  * </table>
97  *
98  * <p>Initially, a camera is in a {@link Type#CLOSED} state. When it receives a signal to open, for
99  * example after one or multiple {@linkplain UseCase use cases} are attached to it, its state
100  * moves to the {@link Type#OPENING} state. If it successfully opens the camera device, its state
101  * moves to the {@link Type#OPEN} state, otherwise, it may move to a different state depending on
102  * the error it encountered:
103  *
104  * <ul>
105  * <li>If opening the camera device fails prematurely, for example, when "Do Not Disturb" mode is
106  * enabled on a device that's affected by a bug in Android 9 (see
107  * {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}), the state moves to the {@link Type#CLOSED} state
108  * .</li>
109  * <li>If the error is recoverable, CameraX will attempt to reopen the camera device. If a recovery
110  * attempt succeeds, the camera state moves to the {@link Type#OPEN} state, however, if all recovery
111  * attempts are unsuccessful, the camera waits in a {@link Type#PENDING_OPEN} state to attempt
112  * recovery again once the camera device's availability changes.</li>
113  * <li>If the error is critical, and requires the intervention of the developer or user, the
114  * camera's state moves to the {@link Type#CLOSING} state.</li>
115  * </ul>
116  *
117  * <p>While in the {@link Type#PENDING_OPEN} state, the camera waits for a signal indicating the
118  * camera device's availability. The signal can either be an external one from the camera service,
119  * or an internal one from within CameraX. When received, the camera's state moves to the
120  * {@link Type#OPENING} state, and an attempt to open the camera device is made.
121  *
122  * <p>While in the {@link Type#OPEN} state, the camera device may be disconnected due to an error.
123  * In this case, depending on whether the error is critical or recoverable, CameraX may or may not
124  * attempt to recover from it, thus the state will move to either a {@link Type#CLOSING} or
125  * {@link Type#OPENING} state.
126  *
127  * <p>If the camera is in an {@link Type#OPEN} state and receives a signal to close the camera
128  * device, for example when all its previously attached {@link UseCase use cases} are detached,
129  * its state moves to the {@link Type#CLOSING} state. Once the camera device finishes closing,
130  * the camera state moves to the {@link Type#CLOSED} state.
131  *
132  * <p>Whenever the camera encounters an error, it reports it through {@link #getError()}.
133  */
134 @AutoValue
135 public abstract class CameraState {
136 
137     /**
138      * An error indicating that the limit number of open cameras has been reached, and more
139      * cameras cannot be opened until other instances are closed.
140      */
141     @SuppressWarnings("MinMaxConstant")
142     public static final int ERROR_MAX_CAMERAS_IN_USE = 1;
143 
144     /**
145      * An error indicating that the camera device is already in use.
146      *
147      * <p>This could be due to the camera device being used by a higher-priority camera client.
148      */
149     public static final int ERROR_CAMERA_IN_USE = 2;
150 
151     /**
152      * An error indicating that the camera device has encountered a recoverable error.
153      *
154      * <p>CameraX will attempt to recover from the error, it if succeeds in doing so, the
155      * camera will open, otherwise the camera will move to a {@link Type#PENDING_OPEN} state.
156      *
157      * When CameraX uses a {@link android.hardware.camera2} implementation, this error represents
158      * a {@link android.hardware.camera2.CameraDevice.StateCallback#ERROR_CAMERA_DEVICE} error.
159      */
160     public static final int ERROR_OTHER_RECOVERABLE_ERROR = 3;
161 
162     /** An error indicating that configuring the camera has failed. */
163     public static final int ERROR_STREAM_CONFIG = 4;
164 
165     /**
166      * An error indicating that the camera device could not be opened due to a device policy.
167      *
168      * <p>The error may be encountered if a client from a background process attempts to open the
169      * camera.
170      *
171      * @see android.app.admin.DevicePolicyManager#setCameraDisabled(ComponentName, boolean)
172      */
173     public static final int ERROR_CAMERA_DISABLED = 5;
174 
175     /**
176      * An error indicating that the camera device was closed due to a fatal error.
177      *
178      * <p>The error may require the Android device to be shut down and restarted to restore camera
179      * function. It may also indicate the existence of a persistent camera hardware problem.
180      *
181      * When CameraX uses a {@link android.hardware.camera2} implementation, this error represents
182      * a {@link android.hardware.camera2.CameraDevice.StateCallback#ERROR_CAMERA_SERVICE} error.
183      */
184     public static final int ERROR_CAMERA_FATAL_ERROR = 6;
185 
186     /**
187      * An error indicating that the camera could not be opened because "Do Not Disturb" mode is
188      * enabled on devices affected by a bug in Android 9 (API level 28).
189      *
190      * <p>When "Do Not Disturb" mode is enabled, opening the camera device fails on certain
191      * Android devices running on an early Android 9 release with a
192      * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}
193      * camera hardware level.
194      *
195      * <p>CameraX will not attempt to reopen the camera device, instead, disable the "Do Not
196      * Disturb" mode, then explicitly open the camera again.
197      */
198     public static final int ERROR_DO_NOT_DISTURB_MODE_ENABLED = 7;
199 
200     /**
201      * Create a new {@link CameraState} instance from a {@link Type} and a {@code null}
202      * {@link StateError}.
203      *
204      * <p>A {@link CameraState} is not expected to be instantiated in normal operation.
205      */
create(@onNull Type type)206     public static @NonNull CameraState create(@NonNull Type type) {
207         return create(type, null);
208     }
209 
210     /**
211      * Create a new {@link CameraState} instance from a {@link Type} and a potential
212      * {@link StateError}.
213      *
214      * <p>A {@link CameraState} is not expected to be instantiated in normal operation.
215      */
create(@onNull Type type, @Nullable StateError error)216     public static @NonNull CameraState create(@NonNull Type type, @Nullable StateError error) {
217         return new AutoValue_CameraState(type, error);
218     }
219 
220     /**
221      * Returns the camera's state.
222      *
223      * @return The camera's state
224      */
getType()225     public abstract @NonNull Type getType();
226 
227     /**
228      * Potentially returns an error the camera encountered.
229      *
230      * @return An error the camera encountered, or {@code null} otherwise.
231      */
getError()232     public abstract @Nullable StateError getError();
233 
234     @IntDef(value = {
235             ERROR_CAMERA_IN_USE,
236             ERROR_MAX_CAMERAS_IN_USE,
237             ERROR_OTHER_RECOVERABLE_ERROR,
238             ERROR_STREAM_CONFIG,
239             ERROR_CAMERA_DISABLED,
240             ERROR_CAMERA_FATAL_ERROR,
241             ERROR_DO_NOT_DISTURB_MODE_ENABLED})
242     @Retention(RetentionPolicy.SOURCE)
243     @interface ErrorCode {
244     }
245 
246     /**
247      * Types of errors the camera can encounter.
248      *
249      * <p>CameraX tries to recover from recoverable errors, which include
250      * {@link #ERROR_CAMERA_IN_USE}, {@link #ERROR_MAX_CAMERAS_IN_USE} and
251      * {@link #ERROR_OTHER_RECOVERABLE_ERROR}. The rest of the errors are critical, and require
252      * the intervention of the developer or user to restore camera function. These errors include
253      * {@link #ERROR_STREAM_CONFIG}, {@link #ERROR_CAMERA_DISABLED},
254      * {@link #ERROR_CAMERA_FATAL_ERROR} and {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
255      */
256     public enum ErrorType {
257         /**
258          * An error the camera encountered that CameraX will attempt to recover from.
259          *
260          * <p>Recoverable errors include {@link #ERROR_CAMERA_IN_USE},
261          * {@link #ERROR_MAX_CAMERAS_IN_USE} and {@link #ERROR_OTHER_RECOVERABLE_ERROR}.
262          */
263         RECOVERABLE,
264 
265         /**
266          * An error the camera encountered that CameraX will not attempt to recover from.
267          *
268          * <p>A critical error is one that requires the intervention of the developer or user to
269          * restore camera function, and includes {@link #ERROR_STREAM_CONFIG},
270          * {@link #ERROR_CAMERA_DISABLED}, {@link #ERROR_CAMERA_FATAL_ERROR} and
271          * {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
272          */
273         CRITICAL
274     }
275 
276     /** States the camera can be in. */
277     public enum Type {
278         /**
279          * Represents a state where the camera is waiting for a signal to attempt to open the camera
280          * device.
281          *
282          * <p>The camera can move to this state from a {@link Type#CLOSED} or {@link Type#OPENING}
283          * state:
284          * <ul>
285          * <li>It moves to this state from a {@link Type#CLOSED} state if it attempts to open an
286          * unavailable camera device. A camera device is unavailable for opening if (a) it's
287          * already in use by another camera client, for example one with higher priority or (b)
288          * the maximum number of cameras allowed to be open at the same time in CameraX has been
289          * reached, this limit is currently set to 1.</li>
290          * <li>It moves to this state from an {@link Type#OPENING} state if it reaches the
291          * maximum number of camera reopen attempts while trying to recover from a camera opening
292          * error.</li>
293          * </ul>
294          *
295          * <p>While in this state, the camera waits for an external signal from the camera
296          * service or an internal one from CameraX to attempt to reopen the camera device.
297          *
298          * <p>Developers may rely on this state to close any other open cameras in the app, or
299          * request their user close an open camera in another app.
300          */
301         PENDING_OPEN,
302 
303         /**
304          * Represents a state where the camera device is currently opening.
305          *
306          * <p>The camera can move to this state from a {@link Type#PENDING_OPEN} or
307          * {@link Type#CLOSED} state: It moves to this state from a {@link Type#PENDING_OPEN}
308          * state after it receives a signal that the camera is available to open, and from a
309          * {@link Type#CLOSED} state after a request to open the camera is made, and the camera
310          * is available to open.
311          *
312          * <p>While in this state, the camera is actively attempting to open the camera device.
313          * This takes several hundred milliseconds on most devices. If it succeeds, the state
314          * moves to the {@link Type#OPEN} state. If it fails however, the camera may attempt to
315          * reopen the camera device a certain number of times. While this is happening, the
316          * camera state remains the same, i.e. in an opening state, and it exposes the error it
317          * encountered through {@link #getError()}.
318          *
319          * <p>Developers can rely on this state to be aware of when the camera is actively
320          * attempting to open the camera device, this allows them to communicate it to their
321          * users through the UI.
322          */
323         OPENING,
324 
325         /**
326          * Represents a state where the camera device is open.
327          *
328          * <p>The camera can only move to this state from an {@link Type#OPENING} state.
329          *
330          * <p>Once in this state, active {@linkplain UseCase use cases} attached to this camera
331          * could expect to shortly start receiving camera frames.
332          *
333          * <p>Developers can rely on this state to be notified of when the camera device is actually
334          * ready for use, and can then set up camera dependent resources, especially if they're
335          * heavyweight.
336          */
337         OPEN,
338 
339         /**
340          * Represents a state where the camera device is currently closing.
341          *
342          * <p>The camera can move to this state from an {@link Type#OPEN} or {@link Type#OPENING}
343          * state: It moves to this state from an {@link Type#OPEN} state after it receives a
344          * signal to close the camera device, this can be after all its attached
345          * {@linkplain UseCase use cases} are detached, and from an {@link Type#OPENING} state if
346          * the camera encounters a fatal error it cannot recover from.
347          *
348          * <p>Developers can rely on this state to be aware of when the camera device is actually
349          * in the process of closing. this allows them to communicate it to their users through
350          * the UI.
351          */
352         CLOSING,
353 
354         /**
355          * Represents a state where the camera device is closed.
356          *
357          * <p>The camera is initially in this state, and can move back to it from a
358          * {@link Type#CLOSING} or {@link Type#OPENING} state: It moves to this state from a
359          * {@link Type#CLOSING} state after the camera device successfully closes, and from an
360          * {@link Type#OPENING} state when opening a camera device that is unavailable due to
361          * {@link android.app.NotificationManager.Policy}, as some API level 28 devices cannot
362          * access the camera when the device is in "Do Not Disturb" mode.
363          *
364          * <p>Developers can rely on this state to be notified of when the camera device is actually
365          * closed, and then use this signal to free up camera resources, or start the camera device
366          * with another camera client.
367          */
368         CLOSED
369     }
370 
371     /**
372      * Error that the camera has encountered.
373      *
374      * <p>The camera may report an error when it's in one of the following states:
375      * {@link Type#OPENING}, {@link Type#OPEN}, {@link Type#CLOSING} and {@link Type#CLOSED}.
376      *
377      * <p>CameraX attempts to recover from certain errors it encounters when opening the camera
378      * device, in these instances, the error is {@linkplain ErrorType#RECOVERABLE recoverable},
379      * otherwise, the error is {@linkplain ErrorType#CRITICAL critical}.
380      *
381      * <p>When CameraX encounters a critical error, the developer and/or user must intervene to
382      * restore camera function. When the error is recoverable, the developer and/or user can
383      * still aid in the recovery process, as shown in the following table.
384      * <table>
385      * <tr>
386      *     <th>State</th>
387      *     <th>Error Code</th>
388      *     <th>Recoverable</th>
389      *     <th>How to handle it</th>
390      * </tr>
391      * <tr>
392      *     <td>{@link Type#OPEN}</td>
393      *     <td>{@linkplain #ERROR_STREAM_CONFIG ERROR_STREAM_CONFIG}</td>
394      *     <td>No</td>
395      *     <td>Make sure you set up your {@linkplain UseCase use cases} correctly.</td>
396      * </tr>
397      * <tr>
398      *     <td>{@link Type#OPENING}</td>
399      *     <td>{@linkplain #ERROR_CAMERA_IN_USE ERROR_CAMERA_IN_USE}</td>
400      *     <td>Yes</td>
401      *     <td>Close the camera, or ask the user to close another camera app that is using the
402      *     camera.</td>
403      * </tr>
404      * <tr>
405      *     <td>{@link Type#OPENING}</td>
406      *     <td>{@linkplain #ERROR_MAX_CAMERAS_IN_USE ERROR_MAX_CAMERAS_IN_USE}</td>
407      *     <td>Yes</td>
408      *     <td>Close another open camera in the app, or ask the user to close another camera
409      *     app that's using the camera.</td>
410      * </tr>
411      * <tr>
412      *     <td>{@link Type#OPENING}</td>
413      *     <td>{@linkplain #ERROR_OTHER_RECOVERABLE_ERROR ERROR_OTHER_RECOVERABLE_ERROR}</td>
414      *     <td>Yes</td>
415      *     <td>N/A</td>
416      * </tr>
417      * <tr>
418      *     <td>{@link Type#CLOSING}</td>
419      *     <td>{@linkplain #ERROR_CAMERA_DISABLED ERROR_CAMERA_DISABLED}</td>
420      *     <td>No</td>
421      *     <td>Ask the user to enable the device's cameras.</td>
422      * </tr>
423      * <tr>
424      *     <td>{@link Type#CLOSING}</td>
425      *     <td>{@linkplain #ERROR_CAMERA_FATAL_ERROR ERROR_CAMERA_FATAL_ERROR}</td>
426      *     <td>No</td>
427      *     <td>Ask the user to reboot the device to restore camera function.</td>
428      * </tr>
429      * <tr>
430      *     <td>{@link Type#CLOSED}</td>
431      *     <td>{@linkplain #ERROR_DO_NOT_DISTURB_MODE_ENABLED
432      *     ERROR_DO_NOT_DISTURB_MODE_ENABLED}</td>
433      *     <td>No</td>
434      *     <td>Ask the user to disable "Do Not Disturb" mode, then open the camera again.</td>
435      * </tr>
436      * </table>
437      */
438     @AutoValue
439     public abstract static class StateError {
440 
441         /**
442          * Creates a {@link StateError} with an error code.
443          *
444          * <p>A {@link StateError} is not expected to be instantiated in normal operation.
445          */
create(@rrorCode int error)446         public static @NonNull StateError create(@ErrorCode int error) {
447             return create(error, null);
448         }
449 
450         /**
451          * Creates a {@link StateError} with an error code and a {@linkplain Throwable cause}.
452          *
453          * <p>A {@link StateError} is not expected to be instantiated in normal operation.
454          */
create(@rrorCode int error, @Nullable Throwable cause)455         public static @NonNull StateError create(@ErrorCode int error, @Nullable Throwable cause) {
456             return new AutoValue_CameraState_StateError(error, cause);
457         }
458 
459         /**
460          * Returns the code of this error.
461          *
462          * <p>The error's code is one of the following: {@link #ERROR_CAMERA_IN_USE},
463          * {@link #ERROR_MAX_CAMERAS_IN_USE}, {@link #ERROR_OTHER_RECOVERABLE_ERROR},
464          * {@link #ERROR_STREAM_CONFIG}, {@link #ERROR_CAMERA_DISABLED},
465          * {@link #ERROR_CAMERA_FATAL_ERROR} and {@link #ERROR_DO_NOT_DISTURB_MODE_ENABLED}.
466          *
467          * @return The code of this error.
468          */
469         @ErrorCode
getCode()470         public abstract int getCode();
471 
472         /**
473          * Returns a potential cause of this error.
474          *
475          * @return The cause of this error, or {@code null} if the cause was not supplied.
476          */
getCause()477         public abstract @Nullable Throwable getCause();
478 
479         /**
480          * Returns the type of this error.
481          *
482          * <p>An error can either be {@linkplain ErrorType#RECOVERABLE recoverable} or
483          * {@linkplain ErrorType#CRITICAL critical}.
484          *
485          * @return The type of this error
486          */
getType()487         public @NonNull ErrorType getType() {
488             int code = getCode();
489             if (code == ERROR_CAMERA_IN_USE || code == ERROR_MAX_CAMERAS_IN_USE
490                     || code == ERROR_OTHER_RECOVERABLE_ERROR) {
491                 return ErrorType.RECOVERABLE;
492             }
493             return ErrorType.CRITICAL;
494         }
495     }
496 }
497