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.camera2.pipe.compat
18 
19 import android.hardware.camera2.CameraAccessException
20 import androidx.camera.camera2.pipe.CameraError
21 import androidx.camera.camera2.pipe.CameraId
22 import androidx.camera.camera2.pipe.core.Log
23 import androidx.camera.camera2.pipe.internal.CameraErrorListener
24 
25 /**
26  * Thrown when an operation cannot be executed because underlying object is closed or in an unusable
27  * state.
28  */
29 internal class ObjectUnavailableException(e: Throwable) : Exception(e)
30 
31 /** Catch specific exceptions that are not normally thrown, log them, then rethrow. */
32 @Throws(ObjectUnavailableException::class)
catchAndReportCameraExceptionsnull33 internal inline fun <T> catchAndReportCameraExceptions(
34     cameraId: CameraId,
35     cameraErrorListener: CameraErrorListener,
36     crossinline block: () -> T
37 ): T? {
38     // Camera2 has, at different points in time, thrown a large number of checked and/or
39     // unchecked exceptions under different circumstances that are not listed in the
40     // documentation. This method catches and recasts these exceptions into a common exception
41     // type.
42     //
43     // Specific examples:
44     // * Some exceptions (such as IllegalArgumentException) can happen if a surface is destroyed
45     //   out of band during configuration.
46     // * Some exceptions (such as IllegalStateException) can be thrown but are not reported as
47     //   being thrown by various methods on some versions of the OS.
48     // * Some exceptions (such as SecurityException) can happen even when the application has
49     //   permission to access the camera but a higher priority or security sensitive service is
50     //   currently using the camera.
51     // * Some exceptions (such as UnsupportedOperationException) can be thrown on some versions
52     //   of the OS (b/28617016)
53     try {
54         return block()
55     } catch (e: Exception) {
56         Log.warn { "Unexpected error: " + e.message }
57         when (e) {
58             is CameraAccessException -> {
59                 cameraErrorListener.onCameraError(
60                     cameraId,
61                     CameraError.from(e),
62                     // CameraAccessException indicates the task failed because the camera is
63                     // unavailable, such as when the camera is in use or disconnected. Such errors
64                     // can be recovered when the camera becomes available.
65                     willAttemptRetry = true,
66                 )
67                 return null
68             }
69             is IllegalArgumentException,
70             is IllegalStateException,
71             is SecurityException,
72             is UnsupportedOperationException,
73             is NullPointerException -> {
74                 cameraErrorListener.onCameraError(
75                     cameraId,
76                     CameraError.ERROR_GRAPH_CONFIG,
77                     willAttemptRetry = false
78                 )
79                 return null
80             }
81             else -> throw e
82         }
83     }
84 }
85