blob: f7a6c0cfbec46ff7dd8c2c5d69a597fa894e2ec0 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.camera2.pipe.integration.adapter
import android.annotation.SuppressLint
import android.graphics.Rect
import android.hardware.camera2.CameraCharacteristics
import androidx.annotation.RequiresApi
import androidx.arch.core.util.Function
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.core.Log.warn
import androidx.camera.camera2.pipe.integration.config.CameraScope
import androidx.camera.camera2.pipe.integration.impl.CameraProperties
import androidx.camera.camera2.pipe.integration.impl.EvCompControl
import androidx.camera.camera2.pipe.integration.impl.FlashControl
import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
import androidx.camera.camera2.pipe.integration.impl.StillCaptureRequestControl
import androidx.camera.camera2.pipe.integration.impl.TorchControl
import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
import androidx.camera.camera2.pipe.integration.interop.Camera2CameraControl
import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.FocusMeteringResult
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO
import androidx.camera.core.ImageCapture.FLASH_MODE_ON
import androidx.camera.core.impl.CameraControlInternal
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.Config
import androidx.camera.core.impl.SessionConfig
import androidx.camera.core.impl.utils.executor.CameraXExecutors
import androidx.camera.core.impl.utils.futures.FutureChain
import androidx.camera.core.impl.utils.futures.Futures
import com.google.common.util.concurrent.ListenableFuture
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
/**
* Adapt the [CameraControlInternal] interface to [CameraPipe].
*
* This controller class maintains state as use-cases are attached / detached from the camera as
* well as providing access to other utility methods. The primary purpose of this class it to
* forward these interactions to the currently configured [UseCaseCamera].
*/
@SuppressLint("UnsafeOptInUsageError")
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@CameraScope
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalCamera2Interop::class)
class CameraControlAdapter @Inject constructor(
private val cameraProperties: CameraProperties,
private val evCompControl: EvCompControl,
private val flashControl: FlashControl,
private val focusMeteringControl: FocusMeteringControl,
private val stillCaptureRequestControl: StillCaptureRequestControl,
private val torchControl: TorchControl,
private val threads: UseCaseThreads,
private val zoomControl: ZoomControl,
private val zslControl: ZslControl,
val camera2cameraControl: Camera2CameraControl,
) : CameraControlInternal {
override fun getSensorRect(): Rect {
return cameraProperties.metadata[CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE]!!
}
override fun addInteropConfig(config: Config) {
camera2cameraControl.addCaptureRequestOptions(
CaptureRequestOptions.Builder.from(config).build()
)
}
override fun clearInteropConfig() {
camera2cameraControl.clearCaptureRequestOptions()
}
override fun getInteropConfig(): Config {
return camera2cameraControl.getCaptureRequestOptions()
}
override fun enableTorch(torch: Boolean): ListenableFuture<Void> =
Futures.nonCancellationPropagating(
FutureChain.from(
torchControl.setTorchAsync(torch).asListenableFuture()
).transform(
Function { return@Function null }, CameraXExecutors.directExecutor()
)
)
override fun startFocusAndMetering(
action: FocusMeteringAction
): ListenableFuture<FocusMeteringResult> =
Futures.nonCancellationPropagating(focusMeteringControl.startFocusAndMetering(action))
override fun cancelFocusAndMetering(): ListenableFuture<Void> {
return Futures.nonCancellationPropagating(
threads.sequentialScope.async {
focusMeteringControl.cancelFocusAndMeteringAsync().join()
// Convert to null once the task is done, ignore the results.
return@async null
}.asListenableFuture()
)
}
override fun setZoomRatio(ratio: Float): ListenableFuture<Void> =
zoomControl.setZoomRatio(ratio)
override fun setLinearZoom(linearZoom: Float): ListenableFuture<Void> =
zoomControl.setLinearZoom(linearZoom)
override fun getFlashMode(): Int {
return flashControl.flashMode
}
override fun setFlashMode(@ImageCapture.FlashMode flashMode: Int) {
flashControl.setFlashAsync(flashMode)
zslControl.setZslDisabledByFlashMode(
flashMode == FLASH_MODE_ON ||
flashMode == FLASH_MODE_AUTO
)
}
override fun setScreenFlash(screenFlash: ImageCapture.ScreenFlash?) {
flashControl.setScreenFlash(screenFlash)
}
override fun setExposureCompensationIndex(exposure: Int): ListenableFuture<Int> =
Futures.nonCancellationPropagating(
evCompControl.updateAsync(exposure).asListenableFuture()
)
override fun setZslDisabledByUserCaseConfig(disabled: Boolean) {
zslControl.setZslDisabledByUserCaseConfig(disabled)
}
override fun isZslDisabledByByUserCaseConfig(): Boolean {
return zslControl.isZslDisabledByUserCaseConfig()
}
override fun addZslConfig(sessionConfigBuilder: SessionConfig.Builder) {
zslControl.addZslConfig(sessionConfigBuilder)
}
override fun submitStillCaptureRequests(
captureConfigs: List<CaptureConfig>,
@ImageCapture.CaptureMode captureMode: Int,
@ImageCapture.FlashType flashType: Int,
) = stillCaptureRequestControl.issueCaptureRequests(
captureConfigs,
captureMode,
flashType
)
override fun getSessionConfig(): SessionConfig {
warn { "TODO: getSessionConfig is not yet supported" }
return SessionConfig.defaultEmptySessionConfig()
}
}