1 /* 2 * Copyright 2019 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 package androidx.camera.lifecycle 17 18 import android.content.Context 19 import android.content.pm.PackageManager 20 import androidx.annotation.RestrictTo 21 import androidx.annotation.RestrictTo.Scope 22 import androidx.camera.core.Camera 23 import androidx.camera.core.CameraInfo 24 import androidx.camera.core.CameraProvider 25 import androidx.camera.core.CameraSelector 26 import androidx.camera.core.CameraXConfig 27 import androidx.camera.core.CompositionSettings 28 import androidx.camera.core.ConcurrentCamera 29 import androidx.camera.core.ConcurrentCamera.SingleCameraConfig 30 import androidx.camera.core.ImageAnalysis 31 import androidx.camera.core.ImageCapture 32 import androidx.camera.core.Preview 33 import androidx.camera.core.UseCase 34 import androidx.camera.core.UseCaseGroup 35 import androidx.camera.core.impl.utils.executor.CameraXExecutors 36 import androidx.camera.core.impl.utils.futures.Futures 37 import androidx.concurrent.futures.await 38 import androidx.core.util.Preconditions 39 import androidx.lifecycle.Lifecycle 40 import androidx.lifecycle.LifecycleOwner 41 import com.google.common.util.concurrent.ListenableFuture 42 43 /** 44 * Provides access to a camera which has its opening and closing controlled by a [LifecycleOwner]. 45 * 46 * This allows configuring multiple instances with different [Context] and [CameraXConfig]. The use 47 * cases can be bound to different camera providers simultaneously, but only one [LifecycleOwner] 48 * can be [active][Lifecycle.State.RESUMED] at a time. 49 * 50 * The sample shows how to configure and create two camera providers differently. 51 * 52 * @sample androidx.camera.lifecycle.samples.configureAndCreateInstances 53 */ 54 // TODO: Remove the annotation when LifecycleCameraProvider is ready to be public. 55 @RestrictTo(Scope.LIBRARY_GROUP) 56 public interface LifecycleCameraProvider : CameraProvider { 57 /** 58 * Returns `true` if the [UseCase] is bound to a lifecycle. Otherwise returns `false`. 59 * 60 * After binding a use case, use cases remain bound until the lifecycle reaches a 61 * [Lifecycle.State.DESTROYED] state or if is unbound by calls to [unbind] or [unbindAll]. 62 */ isBoundnull63 public fun isBound(useCase: UseCase): Boolean 64 65 /** 66 * Unbinds all specified use cases from the lifecycle provider. 67 * 68 * This will initiate a close of every open camera which has zero [UseCase] associated with it 69 * at the end of this call. 70 * 71 * If a use case in the argument list is not bound, then it is simply ignored. 72 * 73 * After unbinding a UseCase, the UseCase can be bound to another [Lifecycle] however listeners 74 * and settings should be reset by the application. 75 * 76 * @param useCases The collection of use cases to remove. 77 * @throws IllegalStateException If not called on main thread. 78 * @throws UnsupportedOperationException If called in concurrent mode. 79 */ 80 public fun unbind(vararg useCases: UseCase?): Unit 81 82 /** 83 * Unbinds all use cases from the lifecycle provider and removes them from CameraX. 84 * 85 * This will initiate a close of every currently open camera. 86 * 87 * @throws IllegalStateException If not called on main thread. 88 */ 89 public fun unbindAll(): Unit 90 91 /** 92 * Binds the collection of [UseCase] to a [LifecycleOwner]. 93 * 94 * The state of the lifecycle will determine when the cameras are open, started, stopped and 95 * closed. When started, the use cases receive camera data. 96 * 97 * Binding to a lifecycleOwner in state currently in [Lifecycle.State.STARTED] or greater will 98 * also initialize and start data capture. If the camera was already running this may cause a 99 * new initialization to occur temporarily stopping data from the camera before restarting it. 100 * 101 * Multiple use cases can be bound via adding them all to a single bindToLifecycle call, or by 102 * using multiple bindToLifecycle calls. Using a single call that includes all the use cases 103 * helps to set up a camera session correctly for all uses cases, such as by allowing 104 * determination of resolutions depending on all the use cases bound being bound. If the use 105 * cases are bound separately, it will find the supported resolution with the priority depending 106 * on the binding sequence. If the use cases are bound with a single call, it will find the 107 * supported resolution with the priority in sequence of [ImageCapture], [Preview] and then 108 * [ImageAnalysis]. The resolutions that can be supported depends on the camera device hardware 109 * level that there are some default guaranteed resolutions listed in 110 * [android.hardware.camera2.CameraDevice.createCaptureSession]. 111 * 112 * Currently up to 3 use cases may be bound to a [Lifecycle] at any time. Exceeding capability 113 * of target camera device will throw an IllegalArgumentException. 114 * 115 * A UseCase should only be bound to a single lifecycle and camera selector a time. Attempting 116 * to bind a use case to a lifecycle when it is already bound to another lifecycle is an error, 117 * and the use case binding will not change. Attempting to bind the same use case to multiple 118 * camera selectors is also an error and will not change the binding. 119 * 120 * If different use cases are bound to different camera selectors that resolve to distinct 121 * cameras, but the same lifecycle, only one of the cameras will operate at a time. The 122 * non-operating camera will not become active until it is the only camera with use cases bound. 123 * 124 * The [Camera] returned is determined by the given camera selector, plus other internal 125 * requirements, possibly from use case configurations. The camera returned from bindToLifecycle 126 * may differ from the camera determined solely by a camera selector. If the camera selector 127 * can't resolve a valid camera under the requirements, an IllegalArgumentException will be 128 * thrown. 129 * 130 * Only [UseCase] bound to latest active [Lifecycle] can keep alive. [UseCase] bound to other 131 * [Lifecycle] will be stopped. 132 * 133 * @param lifecycleOwner The lifecycleOwner which controls the lifecycle transitions of the use 134 * cases. 135 * @param cameraSelector The camera selector which determines the camera to use for set of use 136 * cases. 137 * @param useCases The use cases to bind to a lifecycle. 138 * @return The [Camera] instance which is determined by the camera selector and internal 139 * requirements. 140 * @throws IllegalStateException If the use case has already been bound to another lifecycle or 141 * method is not called on main thread. 142 * @throws IllegalArgumentException If the provided camera selector is unable to resolve a 143 * camera to be used for the given use cases. 144 * @throws UnsupportedOperationException If the camera is configured in concurrent mode. 145 */ 146 public fun bindToLifecycle( 147 lifecycleOwner: LifecycleOwner, 148 cameraSelector: CameraSelector, 149 vararg useCases: UseCase? 150 ): Camera 151 152 /** 153 * Binds a [UseCaseGroup] to a [LifecycleOwner]. 154 * 155 * Similar to [bindToLifecycle], with the addition that the bound collection of [UseCase] share 156 * parameters defined by [UseCaseGroup] such as consistent camera sensor rect across all 157 * [UseCase]s. 158 * 159 * If one [UseCase] is in multiple [UseCaseGroup]s, it will be linked to the [UseCaseGroup] in 160 * the latest [bindToLifecycle] call. 161 * 162 * @throws UnsupportedOperationException If the camera is configured in concurrent mode. 163 */ 164 public fun bindToLifecycle( 165 lifecycleOwner: LifecycleOwner, 166 cameraSelector: CameraSelector, 167 useCaseGroup: UseCaseGroup 168 ): Camera 169 170 /** 171 * Binds list of [SingleCameraConfig]s to [LifecycleOwner]. 172 * 173 * The concurrent camera is only supporting two cameras currently. If the input list of 174 * [SingleCameraConfig]s have less or more than two [SingleCameraConfig]s, 175 * [IllegalArgumentException] will be thrown. If cameras are already used by other [UseCase]s, 176 * [UnsupportedOperationException] will be thrown. 177 * 178 * A logical camera is a grouping of two or more of those physical cameras. See 179 * [Multi-camera API](https://developer.android.com/media/camera/camera2/multi-camera) 180 * 181 * If we want to open concurrent logical cameras, which are one front camera and one back 182 * camera, the device needs to support [PackageManager.FEATURE_CAMERA_CONCURRENT]. To set up 183 * concurrent logical camera, call [availableConcurrentCameraInfos] to get the list of available 184 * combinations of concurrent cameras. Each sub-list contains the [CameraInfo]s for a 185 * combination of cameras that can be operated concurrently. Each logical camera can have its 186 * own [UseCase]s and [LifecycleOwner]. See 187 * [CameraX lifecycles]({@docRoot}training/camerax/architecture#lifecycles) 188 * 189 * If the concurrent logical cameras are binding the same preview and video capture use cases, 190 * the concurrent cameras video recording will be supported. The concurrent camera preview 191 * stream will be shared with video capture and record the concurrent cameras streams as a 192 * composited stream. The [CompositionSettings] can be used to configure the position of each 193 * camera stream and different layouts can be built. See [CompositionSettings] for more details. 194 * 195 * If we want to open concurrent physical cameras, which are two front cameras or two back 196 * cameras, the device needs to support physical cameras and the capability could be checked via 197 * [CameraInfo.isLogicalMultiCameraSupported]. Each physical cameras can have its own [UseCase]s 198 * but needs to have the same [LifecycleOwner], otherwise [IllegalArgumentException] will be 199 * thrown. 200 * 201 * If we want to open one physical camera, for example ultra wide, we just need to set physical 202 * camera id in [CameraSelector] and bind to lifecycle. All CameraX features will work normally 203 * when only a single physical camera is used. 204 * 205 * If we want to open multiple physical cameras, we need to have multiple [CameraSelector]s, 206 * each in one [SingleCameraConfig] and set physical camera id, then bind to lifecycle with the 207 * [SingleCameraConfig]s. Internally each physical camera id will be set on [UseCase], for 208 * example, [Preview] and call 209 * [android.hardware.camera2.params.OutputConfiguration.setPhysicalCameraId]. 210 * 211 * Currently only two physical cameras for the same logical camera id are allowed and the device 212 * needs to support physical cameras by checking [CameraInfo.isLogicalMultiCameraSupported]. In 213 * addition, there is no guarantee or API to query whether the device supports multiple physical 214 * camera opening or not. Internally the library checks 215 * [android.hardware.camera2.CameraDevice.isSessionConfigurationSupported], if the device does 216 * not support the multiple physical camera configuration, [IllegalArgumentException] will be 217 * thrown. 218 * 219 * @param singleCameraConfigs Input list of [SingleCameraConfig]s. 220 * @return Output [ConcurrentCamera] instance. 221 * @throws IllegalArgumentException If less or more than two camera configs are provided. 222 * @throws UnsupportedOperationException If device is not supporting concurrent camera or 223 * cameras are already used by other [UseCase]s. 224 * @see ConcurrentCamera 225 * @see availableConcurrentCameraInfos 226 * @see CameraInfo.isLogicalMultiCameraSupported 227 * @see CameraInfo.getPhysicalCameraInfos 228 */ 229 public fun bindToLifecycle(singleCameraConfigs: List<SingleCameraConfig?>): ConcurrentCamera 230 231 public companion object { 232 /** 233 * Creates a lifecycle camera provider instance. 234 * 235 * @param context The Application context. 236 * @param cameraXConfig The configuration options to configure the lifecycle camera 237 * provider. If not set, the default configuration will be used. 238 * @return The lifecycle camera provider instance. 239 */ 240 @JvmOverloads 241 @JvmStatic 242 public suspend fun createInstance( 243 context: Context, 244 cameraXConfig: CameraXConfig? = null, 245 ): LifecycleCameraProvider { 246 return createInstanceAsync(context, cameraXConfig).await() 247 } 248 249 /** 250 * Creates a lifecycle camera provider instance asynchronously. 251 * 252 * @param context The Application context. 253 * @param cameraXConfig The configuration options to configure the lifecycle camera 254 * provider. If not set, the default configuration will be used. 255 * @return A [ListenableFuture] that will be completed when the lifecycle camera provider 256 * instance is initialized. 257 */ 258 @JvmOverloads 259 @JvmStatic 260 public fun createInstanceAsync( 261 context: Context, 262 cameraXConfig: CameraXConfig? = null, 263 ): ListenableFuture<LifecycleCameraProvider> { 264 Preconditions.checkNotNull(context) 265 val lifecycleCameraProvider = LifecycleCameraProviderImpl() 266 return Futures.transform( 267 lifecycleCameraProvider.initAsync(context, cameraXConfig), 268 { lifecycleCameraProvider }, 269 CameraXExecutors.directExecutor() 270 ) 271 } 272 } 273 } 274