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