1 /*
2  * Copyright 2022 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.integration.core.util
18 
19 import android.hardware.camera2.CameraCaptureSession
20 import android.hardware.camera2.CameraCharacteristics
21 import android.hardware.camera2.CameraDevice
22 import android.hardware.camera2.CaptureRequest
23 import android.os.Build
24 import androidx.annotation.OptIn
25 import androidx.camera.camera2.Camera2Config
26 import androidx.camera.camera2.interop.Camera2CameraControl
27 import androidx.camera.camera2.interop.Camera2CameraInfo
28 import androidx.camera.camera2.interop.Camera2Interop
29 import androidx.camera.camera2.interop.CaptureRequestOptions
30 import androidx.camera.camera2.interop.ExperimentalCamera2Interop
31 import androidx.camera.camera2.pipe.integration.CameraPipeConfig
32 import androidx.camera.camera2.pipe.integration.interop.Camera2CameraControl as CPCamera2CameraControl
33 import androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo as CPCamera2CameraInfo
34 import androidx.camera.camera2.pipe.integration.interop.Camera2Interop as CPCamera2Interop
35 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions as CPCaptureRequestOptions
36 import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop as CPExperimentalCamera2Interop
37 import androidx.camera.core.CameraControl
38 import androidx.camera.core.CameraInfo
39 import androidx.camera.core.ExtendableBuilder
40 import com.google.common.util.concurrent.ListenableFuture
41 
42 @kotlin.OptIn(CPExperimentalCamera2Interop::class)
43 @OptIn(markerClass = [ExperimentalCamera2Interop::class])
44 object Camera2InteropUtil {
45 
46     @JvmStatic
setCamera2InteropOptionsnull47     fun <T> setCamera2InteropOptions(
48         implName: String,
49         builder: ExtendableBuilder<T>,
50         captureCallback: CameraCaptureSession.CaptureCallback? = null,
51         deviceStateCallback: CameraDevice.StateCallback? = null,
52         sessionStateCallback: CameraCaptureSession.StateCallback? = null,
53         physicalCameraId: String? = null
54     ) {
55         if (implName == CameraPipeConfig::class.simpleName) {
56             val extendedBuilder = CPCamera2Interop.Extender(builder)
57             captureCallback?.let { extendedBuilder.setSessionCaptureCallback(it) }
58             deviceStateCallback?.let { extendedBuilder.setDeviceStateCallback(it) }
59             sessionStateCallback?.let { extendedBuilder.setSessionStateCallback(it) }
60             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && physicalCameraId != null) {
61                 extendedBuilder.setPhysicalCameraId(physicalCameraId)
62             }
63         } else {
64             val extendedBuilder = Camera2Interop.Extender(builder)
65             captureCallback?.let { extendedBuilder.setSessionCaptureCallback(it) }
66             deviceStateCallback?.let { extendedBuilder.setDeviceStateCallback(it) }
67             sessionStateCallback?.let { extendedBuilder.setSessionStateCallback(it) }
68             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && physicalCameraId != null) {
69                 extendedBuilder.setPhysicalCameraId(physicalCameraId)
70             }
71         }
72     }
73 
74     @JvmStatic
setCameraCaptureSessionCallbacknull75     fun <T> setCameraCaptureSessionCallback(
76         implName: String,
77         builder: ExtendableBuilder<T>,
78         captureCallback: CameraCaptureSession.CaptureCallback
79     ) {
80         setCamera2InteropOptions(
81             implName = implName,
82             builder = builder,
83             captureCallback = captureCallback
84         )
85     }
86 
87     @JvmStatic
setDeviceStateCallbacknull88     fun <T> setDeviceStateCallback(
89         implName: String,
90         builder: ExtendableBuilder<T>,
91         stateCallback: CameraDevice.StateCallback
92     ) {
93         setCamera2InteropOptions(
94             implName = implName,
95             builder = builder,
96             deviceStateCallback = stateCallback
97         )
98     }
99 
100     @JvmStatic
setSessionStateCallbacknull101     fun <T> setSessionStateCallback(
102         implName: String,
103         builder: ExtendableBuilder<T>,
104         stateCallback: CameraCaptureSession.StateCallback
105     ) {
106         setCamera2InteropOptions(
107             implName = implName,
108             builder = builder,
109             sessionStateCallback = stateCallback
110         )
111     }
112 
113     @JvmStatic
getCameraIdnull114     fun getCameraId(implName: String, cameraInfo: CameraInfo): String =
115         if (implName == CameraPipeConfig::class.simpleName) {
116             CPCamera2CameraInfo.from(cameraInfo).getCameraId()
117         } else {
118             Camera2CameraInfo.from(cameraInfo).cameraId
119         }
120 
121     @JvmStatic
getCamera2CameraInfoCharacteristicsnull122     fun <T> getCamera2CameraInfoCharacteristics(
123         implName: String,
124         cameraInfo: CameraInfo,
125         key: CameraCharacteristics.Key<T>
126     ): T? =
127         if (implName == Camera2Config::class.simpleName) {
128             Camera2CameraInfo.from(cameraInfo).getCameraCharacteristic(key)
129         } else {
130             CPCamera2CameraInfo.from(cameraInfo).getCameraCharacteristic(key)
131         }
132 
133     interface Camera2CameraInfoWrapper {
getCameraCharacteristicnull134         fun <T> getCameraCharacteristic(key: CameraCharacteristics.Key<T>): T?
135 
136         companion object
137     }
138 
139     interface Camera2CameraControlWrapper {
140         fun setCaptureRequestOptions(bundle: CaptureRequestOptionsWrapper): ListenableFuture<Void?>
141 
142         fun clearCaptureRequestOptions(): ListenableFuture<Void?>
143 
144         companion object
145     }
146 
147     @JvmStatic
Camera2CameraInfoWrappernull148     fun Camera2CameraInfoWrapper.Companion.from(
149         implName: String,
150         cameraInfo: CameraInfo
151     ): Camera2CameraInfoWrapper {
152         return when (implName) {
153             CameraPipeConfig::class.simpleName ->
154                 object : Camera2CameraInfoWrapper {
155                     private val wrappedCameraInfo = CPCamera2CameraInfo.from(cameraInfo)
156 
157                     override fun <T> getCameraCharacteristic(
158                         key: CameraCharacteristics.Key<T>
159                     ): T? {
160                         return wrappedCameraInfo.getCameraCharacteristic(key)
161                     }
162                 }
163             Camera2Config::class.simpleName ->
164                 object : Camera2CameraInfoWrapper {
165                     private val wrappedCameraInfo = Camera2CameraInfo.from(cameraInfo)
166 
167                     override fun <T> getCameraCharacteristic(
168                         key: CameraCharacteristics.Key<T>
169                     ): T? {
170                         return wrappedCameraInfo.getCameraCharacteristic(key)
171                     }
172                 }
173             else -> throw IllegalArgumentException("Unexpected implementation: $implName")
174         }
175     }
176 
177     interface CaptureRequestOptionsWrapper {
178 
unwrapnull179         fun unwrap(): Any
180 
181         interface Builder {
182             fun <ValueT : Any> setCaptureRequestOption(
183                 key: CaptureRequest.Key<ValueT>,
184                 value: ValueT
185             ): Builder
186 
187             fun build(): CaptureRequestOptionsWrapper
188         }
189 
190         companion object
191     }
192 
193     @JvmStatic
CaptureRequestOptionsWrappernull194     fun CaptureRequestOptionsWrapper.Companion.builder(
195         implName: String
196     ): CaptureRequestOptionsWrapper.Builder {
197         return when (implName) {
198             CameraPipeConfig::class.simpleName ->
199                 object : CaptureRequestOptionsWrapper.Builder {
200                     private val wrappedBuilder = CPCaptureRequestOptions.Builder()
201 
202                     override fun <ValueT : Any> setCaptureRequestOption(
203                         key: CaptureRequest.Key<ValueT>,
204                         value: ValueT
205                     ): CaptureRequestOptionsWrapper.Builder {
206                         wrappedBuilder.setCaptureRequestOption(key, value)
207                         return this
208                     }
209 
210                     override fun build(): CaptureRequestOptionsWrapper {
211                         val wrappedOptions = wrappedBuilder.build()
212                         return object : CaptureRequestOptionsWrapper {
213                             override fun unwrap() = wrappedOptions
214                         }
215                     }
216                 }
217             Camera2Config::class.simpleName ->
218                 object : CaptureRequestOptionsWrapper.Builder {
219                     private val wrappedBuilder = CaptureRequestOptions.Builder()
220 
221                     override fun <ValueT : Any> setCaptureRequestOption(
222                         key: CaptureRequest.Key<ValueT>,
223                         value: ValueT
224                     ): CaptureRequestOptionsWrapper.Builder {
225                         wrappedBuilder.setCaptureRequestOption(key, value)
226                         return this
227                     }
228 
229                     override fun build(): CaptureRequestOptionsWrapper {
230                         val wrappedOptions = wrappedBuilder.build()
231                         return object : CaptureRequestOptionsWrapper {
232                             override fun unwrap() = wrappedOptions
233                         }
234                     }
235                 }
236             else -> throw IllegalArgumentException("Unexpected implementation: $implName")
237         }
238     }
239 
240     @JvmStatic
fromnull241     fun Camera2CameraControlWrapper.Companion.from(
242         implName: String,
243         cameraControl: CameraControl
244     ): Camera2CameraControlWrapper {
245         return when (implName) {
246             CameraPipeConfig::class.simpleName ->
247                 object : Camera2CameraControlWrapper {
248                     private val wrappedCameraControl = CPCamera2CameraControl.from(cameraControl)
249 
250                     override fun setCaptureRequestOptions(
251                         bundle: CaptureRequestOptionsWrapper
252                     ): ListenableFuture<Void?> {
253                         return wrappedCameraControl.setCaptureRequestOptions(
254                             bundle.unwrap() as CPCaptureRequestOptions
255                         )
256                     }
257 
258                     override fun clearCaptureRequestOptions(): ListenableFuture<Void?> {
259                         return wrappedCameraControl.clearCaptureRequestOptions()
260                     }
261                 }
262             Camera2Config::class.simpleName ->
263                 object : Camera2CameraControlWrapper {
264                     private val wrappedCameraControl = Camera2CameraControl.from(cameraControl)
265 
266                     override fun setCaptureRequestOptions(
267                         bundle: CaptureRequestOptionsWrapper
268                     ): ListenableFuture<Void?> {
269                         return wrappedCameraControl.setCaptureRequestOptions(
270                             bundle.unwrap() as CaptureRequestOptions
271                         )
272                     }
273 
274                     override fun clearCaptureRequestOptions(): ListenableFuture<Void?> {
275                         return wrappedCameraControl.clearCaptureRequestOptions()
276                     }
277                 }
278             else -> throw IllegalArgumentException("Unexpected implementation: $implName")
279         }
280     }
281 }
282