I want the camera to freeze preview when the image capture button is pressed. I have looked at other stack-overflow questions but they they are outdated.
cameraX version I am using: 1.0.0-beta03
Any help will be appreciated. Thanks
I want the camera to freeze preview when the image capture button is pressed. I have looked at other stack-overflow questions but they they are outdated.
cameraX version I am using: 1.0.0-beta03
Any help will be appreciated. Thanks
There isn't a "proper" way to do it yet, but a couple of ways to achieve it include:
Stop the preview stream by unbinding the Preview
use case, take the picture, then bind a new Preview
use case to continue the preview stream.
For this approach to work, you'd need to also have an ImageAnalysis
use case bound, since ImageCapture
cannot take a picture if it's the only bound use case (another Preview
or ImageAnalysis
use case has to also be bound, check out the official documentation on the possible use case combinations). While this approach works, it would result in a slight delay between the moment the ImageCapture
callback is called, and when the preview continues, during this time the screen will be blank.
At the moment you take a picture, use the latest frame from ImageAnalysis
to display it on top of the preview, you can convert the frame -which is an ImageProxy
- to a Bitmap
and display it in an ImageView
. Once the ImageCapture
callback is invoked, remove the frame and continue the preview.
Edit:
Starting from camera-view version 1.0.0-alpha12, you can get a Bitmap
representation of the preview using PreviewView.getBitmap()
. Using this method, you can get the Bitmap
representation of the preview at the moment the user takes a picture, show it on top of the preview in an ImageView
, then once an image capture result is available, hide the image.
Also I think you can try and create (as a workaround) a custom LifecycleOwner wrapper and manually set lifecycle state to ON_PAUSE when you want to pause preview. So it will be something like this:
class CameraXLifecycleOwner : LifecycleOwner {
private val lifecycle = LifecycleRegistry(this)
private val observer = object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
}
fun attachLifecycleOwner(lifecycleOwner: LifecycleOwner) {
lifecycle.currentState = lifecycleOwner.lifecycle.currentState
lifecycleOwner.lifecycle.addObserver(observer)
}
fun detachLifecycleOwner(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycle.removeObserver(observer)
}
fun pauseCamera() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
}
fun resumeCamera() {
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
}
override fun getLifecycle(): Lifecycle = lifecycle
}
So you then wrap default fragment's viewLifecycleOwner by passing it to attachLifecycleOwner() and this way the wrapper will repeat all viewLifecycleOwner's states, but then you can also call pauseCamera()/resumeCamera() to manually change state faking onPause/onResume state change. Not sure it's the best idea, but it's an idea.