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.integration.interop 18 19 import androidx.annotation.RestrictTo 20 import androidx.annotation.VisibleForTesting 21 import androidx.camera.camera2.pipe.integration.adapter.CameraControlAdapter 22 import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture 23 import androidx.camera.camera2.pipe.integration.compat.Camera2CameraControlCompat 24 import androidx.camera.camera2.pipe.integration.impl.ComboRequestListener 25 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraControl 26 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl 27 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads 28 import androidx.camera.core.CameraControl 29 import androidx.camera.core.impl.CameraControlInternal 30 import androidx.camera.core.impl.utils.futures.Futures 31 import androidx.core.util.Preconditions 32 import com.google.common.util.concurrent.ListenableFuture 33 34 /** 35 * An class that provides ability to interoperate with the [android.hardware.camera2] APIs. 36 * 37 * Camera2 specific controls, like capture request options, can be applied through this class. A 38 * Camera2CameraControl can be created from a general [CameraControl] which is associated to a 39 * camera. Then the controls will affect all use cases that are using that camera. 40 * 41 * If any option applied by Camera2CameraControl conflicts with the options required by CameraX 42 * internally. The options from Camera2CameraControl will override, which may result in unexpected 43 * behavior depends on the options being applied. 44 */ 45 @SuppressWarnings("HiddenSuperclass") 46 @ExperimentalCamera2Interop 47 public class Camera2CameraControl 48 private constructor( 49 private val compat: Camera2CameraControlCompat, 50 private val threads: UseCaseThreads, 51 @get:VisibleForTesting internal val requestListener: ComboRequestListener, 52 ) : UseCaseCameraControl { 53 54 private var _useCaseCameraRequestControl: UseCaseCameraRequestControl? = null 55 override var requestControl: UseCaseCameraRequestControl? 56 @RestrictTo(RestrictTo.Scope.LIBRARY) get() = _useCaseCameraRequestControl 57 @RestrictTo(RestrictTo.Scope.LIBRARY) 58 set(value) { 59 _useCaseCameraRequestControl = value <lambda>null60 _useCaseCameraRequestControl?.also { 61 requestListener.removeListener(compat) 62 requestListener.addListener(compat, threads.sequentialExecutor) 63 compat.applyAsync(it, false) 64 } 65 } 66 67 @RestrictTo(RestrictTo.Scope.LIBRARY) resetnull68 override fun reset() { 69 // Clear the current task, but don't clear the CaptureRequestOptions. Camera2CameraControl 70 // will store the CaptureRequestOptions while use case is detached. 71 compat.cancelCurrentTask() 72 requestListener.removeListener(compat) 73 } 74 75 /** 76 * Sets a [CaptureRequestOptions] and updates the session with the options it contains. 77 * 78 * This will first clear all options that have already been set, then apply the new options. 79 * 80 * Any values which are in conflict with values already set by CameraX, such as by 81 * [androidx.camera.core.CameraControl], will overwrite the existing values. The values will be 82 * submitted with every repeating and single capture requests issued by CameraX, which may 83 * result in unexpected behavior depending on the values being applied. 84 * 85 * @param bundle The [CaptureRequestOptions] which will be set. 86 * @return a [ListenableFuture] which completes when the repeating 87 * [android.hardware.camera2.CaptureResult] shows the options have be submitted completely. 88 * The future fails with [CameraControl.OperationCanceledException] if newer options are set 89 * or camera is closed before the current request completes. Cancelling the ListenableFuture 90 * is a no-op. 91 */ 92 @SuppressWarnings("AsyncSuffixFuture") setCaptureRequestOptionsnull93 public fun setCaptureRequestOptions(bundle: CaptureRequestOptions): ListenableFuture<Void?> { 94 compat.clearRequestOption() 95 compat.addRequestOption(bundle) 96 return updateAsync("setCaptureRequestOptions") 97 } 98 99 /** 100 * Adds a [CaptureRequestOptions] updates the session with the options it contains. 101 * 102 * The options will be merged with the existing options. If one option is set with a different 103 * value, it will overwrite the existing value. 104 * 105 * Any values which are in conflict with values already set by CameraX, such as by 106 * [androidx.camera.core.CameraControl], will overwrite the existing values. The values will be 107 * submitted with every repeating and single capture requests issued by CameraX, which may 108 * result in unexpected behavior depends on the values being applied. 109 * 110 * @param bundle The [CaptureRequestOptions] which will be set. 111 * @return a [ListenableFuture] which completes when the repeating 112 * [android.hardware.camera2.CaptureResult] shows the options have be submitted completely. 113 * The future fails with [CameraControl.OperationCanceledException] if newer options are set 114 * or camera is closed before the current request completes. 115 */ 116 @SuppressWarnings("AsyncSuffixFuture") addCaptureRequestOptionsnull117 public fun addCaptureRequestOptions(bundle: CaptureRequestOptions): ListenableFuture<Void?> { 118 compat.addRequestOption(bundle) 119 return updateAsync("addCaptureRequestOptions") 120 } 121 122 /** 123 * Gets all the capture request options that is currently applied by the [Camera2CameraControl]. 124 * 125 * It doesn't include the capture request options applied by the 126 * [android.hardware.camera2.CameraDevice] templates or by CameraX. 127 * 128 * @return The [CaptureRequestOptions]. 129 */ getCaptureRequestOptionsnull130 public fun getCaptureRequestOptions(): CaptureRequestOptions = compat.getRequestOption() 131 132 /** 133 * Clears all capture request options that is currently applied by the [Camera2CameraControl]. 134 * 135 * @return a [ListenableFuture] which completes when the repeating 136 * [android.hardware.camera2.CaptureResult] shows the options have be submitted completely. 137 * The future fails with [CameraControl.OperationCanceledException] if newer options are set 138 * or camera is closed before the current request completes. 139 */ 140 @SuppressWarnings("AsyncSuffixFuture") 141 public fun clearCaptureRequestOptions(): ListenableFuture<Void?> { 142 compat.clearRequestOption() 143 return updateAsync("clearCaptureRequestOptions") 144 } 145 updateAsyncnull146 private fun updateAsync(tag: String): ListenableFuture<Void?> = 147 Futures.nonCancellationPropagating( 148 compat.applyAsync(requestControl).asListenableFuture(tag) 149 ) 150 151 public companion object { 152 153 /** 154 * Gets the [Camera2CameraControl] from a [CameraControl]. 155 * 156 * The [CameraControl] is still usable after a [Camera2CameraControl] is obtained from it. 157 * Note that the [Camera2CameraControl] has higher priority than the [CameraControl]. For 158 * example, if [android.hardware.camera2.CaptureRequest.FLASH_MODE] is set through the 159 * [Camera2CameraControl]. All [CameraControl] features that required 160 * [android.hardware.camera2.CaptureRequest.FLASH_MODE] internally like torch may not work 161 * properly. 162 * 163 * @param cameraControl The [CameraControl] to get from. 164 * @return The camera control with Camera2 implementation. 165 * @throws IllegalArgumentException if the camera control does not contain the camera2 166 * information (e.g., if CameraX was not initialized with a 167 * [androidx.camera.camera2.pipe.integration.CameraPipeConfig]). 168 */ 169 @JvmStatic 170 public fun from(cameraControl: CameraControl): Camera2CameraControl { 171 var cameraControlImpl = (cameraControl as CameraControlInternal).implementation 172 Preconditions.checkArgument( 173 cameraControlImpl is CameraControlAdapter, 174 "CameraControl doesn't contain Camera2 implementation." 175 ) 176 return (cameraControlImpl as CameraControlAdapter).camera2cameraControl 177 } 178 179 /** This is the workaround to prevent constructor from being added to public API. */ 180 @RestrictTo(RestrictTo.Scope.LIBRARY) 181 @JvmStatic 182 public fun create( 183 compat: Camera2CameraControlCompat, 184 threads: UseCaseThreads, 185 requestListener: ComboRequestListener, 186 ): Camera2CameraControl { 187 return Camera2CameraControl(compat, threads, requestListener) 188 } 189 } 190 } 191