blob: e55ae3583f277cf57669bd692a2703e35257ef1c [file] [log] [blame]
/*
* Copyright (C) 2023 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 com.google.jetpackcamera.domain.camera
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.UseCaseGroup
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
/**
* Runs a camera for the duration of a coroutine.
*
* The camera selected by [cameraSelector] will run with the provided [useCases] for the
* duration that [block] is active. This means that [block] should suspend until the camera
* should be closed.
*/
suspend fun <R> ProcessCameraProvider.runWith(
cameraSelector: CameraSelector,
useCases: UseCaseGroup,
block: suspend (Camera) -> R
): R = coroutineScope {
val scopedLifecycle = CoroutineLifecycleOwner(coroutineContext)
block(this@runWith.bindToLifecycle(scopedLifecycle, cameraSelector, useCases))
}
/**
* A [LifecycleOwner] that follows the lifecycle of a coroutine.
*
* If the coroutine is active, the owned lifecycle will jump to a
* [Lifecycle.State.RESUMED] state. When the coroutine completes, the owned lifecycle will
* transition to a [Lifecycle.State.DESTROYED] state.
*/
private class CoroutineLifecycleOwner(coroutineContext: CoroutineContext) :
LifecycleOwner {
private val lifecycleRegistry: LifecycleRegistry =
LifecycleRegistry(this).apply {
currentState = Lifecycle.State.INITIALIZED
}
init {
if (coroutineContext[Job]?.isActive == true) {
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
coroutineContext[Job]?.invokeOnCompletion {
lifecycleRegistry.apply {
currentState = Lifecycle.State.STARTED
currentState = Lifecycle.State.CREATED
currentState = Lifecycle.State.DESTROYED
}
}
} else {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
}
override public val lifecycle: Lifecycle = lifecycleRegistry
}