Fixed
Status Update
Comments
wu...@google.com <wu...@google.com> #2
Hi Ed, Thank you so much for these suggestions. I've been reviewing them and merging them in. Hopefully it should be live. I've included a thank you note too in the article.
ni...@gmail.com <ni...@gmail.com> #3
Great! Thanks a lot, I'll look for the live updates soon!
ch...@google.com <ch...@google.com>
ch...@google.com <ch...@google.com> #4
By adding some log info in the library side, the issue happens in the following steps when running the sample project provided in
- Activity is launched and the 1st pair of CameraController and PreviewView is created. The CameraController is set to the PreviewView by PreviewView#setController.
- Press the thumbup button to create the 2nd pair of Camera CameraController and PreviewView.
- The 1st PreviewView will receive onDetachedFromWindow callback. It will call CameraController#clearPreviewSurface() and then ProcessCameraProvider#unbindAll() will be called.
All use cases are unbound so the camera is closed.
The following log is extracted from the attached log when the issue happens:
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.lifecycle.LifecycleCameraRepository.suspendUseCases(LifecycleCameraRepository.java:438)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.lifecycle.LifecycleCameraRepository.setInactive(LifecycleCameraRepository.java:394)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.lifecycle.LifecycleCameraRepository.unbindAll(LifecycleCameraRepository.java:334)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.lifecycle.ProcessCameraProvider.unbindAll(ProcessCameraProvider.java:514)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.view.CameraController.clearPreviewSurface(CameraController.java:514)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.camera.view.PreviewView.onDetachedFromWindow(PreviewView.java:277)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.View.dispatchDetachedFromWindow(View.java:21358)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:4649)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:4641)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.ViewGroup.removeViewInternal(ViewGroup.java:6287)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.ViewGroup.removeViewInternal(ViewGroup.java:6258)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.ViewGroup.removeView(ViewGroup.java:6189)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.platform.AndroidComposeView.removeAndroidView(AndroidComposeView.android.kt:466)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$4.invoke(AndroidViewHolder.android.kt:254)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$4.invoke(AndroidViewHolder.android.kt:253)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.node.LayoutNode.detach$ui_release(LayoutNode.kt:370)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.node.LayoutNode.detach$ui_release(LayoutNode.kt:381)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.node.LayoutNode.detach$ui_release(LayoutNode.kt:381)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.node.LayoutNode.removeAt$ui_release(LayoutNode.kt:257)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.node.UiApplier.remove(UiApplier.android.kt:36)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.runtime.ComposerImpl$realizeMovement$1.invoke(Composer.kt:2903)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.runtime.ComposerImpl$realizeMovement$1.invoke(Composer.kt:2903)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:629)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:479)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:416)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.Choreographer$CallbackRecord.run(Choreographer.java:997)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.Choreographer.doCallbacks(Choreographer.java:797)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.Choreographer.doFrame(Choreographer.java:728)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:984)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.os.Handler.handleCallback(Handler.java:883)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.os.Handler.dispatchMessage(Handler.java:100)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.os.Looper.loop(Looper.java:237)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at android.app.ActivityThread.main(ActivityThread.java:8167)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at java.lang.reflect.Method.invoke(Native Method)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
10-31 00:49:59.042 10102 2039 2039 D XXXXX : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
The issue disappears if resetting CameraController when new PreviewView is created.
var previewView : PreviewView? = null
@Composable
fun CameraPreview(flashEnabled: Boolean, modifier: Modifier = Modifier) {
val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current
// Resets CameraController from the previous PreviewView
previewView?.controller = null
val controller = remember {
LifecycleCameraController(context).apply {
cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
}
}
DisposableEffect(true) {
Log.d("XXXXX","DisposableEffect++ lifecycleOwner: " + lifecycleOwner)
controller.bindToLifecycle(lifecycleOwner)
Log.d("XXXXX","DisposableEffect++")
onDispose {
}
}
controller.enableTorch(flashEnabled)
previewView = PreviewView(context)
previewView!!.controller = controller
AndroidView(
factory = { ctx -> previewView!!
},
modifier = modifier
)
}
The solution in the camera-view side will be only unbinding the use cases created by the CameraController instead of directly calling ProcessorCameraProvider#unbindAll().
ap...@google.com <ap...@google.com> #6
Project: platform/frameworks/support
Branch: androidx-main
commit 9e9384994a57d1e94d773d6368c238f4b68db27a
Author: Charcoal Chen <charcoalchen@google.com>
Date: Tue Aug 31 15:02:48 2021
CameraController#clearPreviewSurface unbinds its own use cases only instead of calling unbindAll
When multiple CameraController and PreviewView are used in one Activity, the previous PreviewView might receive the onDetachedFromWindow callback after the new pair of CameraController and PreviewView are created. It will cause the previous CameraController to call unbindAll in clearPreviewSurface function. This will unbind the use cases bound by the new CameraController. CameraController should only unbind its own use cases. Otherwise, it might unexpectedly unbind use cases that belongs to another LifecycleCamera.
Relnote: "Fixed the issue that camera is closed unexpectedly when multiple CameraController and PreviewView are used in one Activity."
Bug: 197539358
Test: buildview='./gradlew camera:camera-view:build' && testview='./gradlew camera:camera-view:connectedAndroidTest'
Change-Id: Ibfd1842890b683ae3db639bf0cc4a2202110fe9f
M camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
M camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
https://android-review.googlesource.com/1813958
Branch: androidx-main
commit 9e9384994a57d1e94d773d6368c238f4b68db27a
Author: Charcoal Chen <charcoalchen@google.com>
Date: Tue Aug 31 15:02:48 2021
CameraController#clearPreviewSurface unbinds its own use cases only instead of calling unbindAll
When multiple CameraController and PreviewView are used in one Activity, the previous PreviewView might receive the onDetachedFromWindow callback after the new pair of CameraController and PreviewView are created. It will cause the previous CameraController to call unbindAll in clearPreviewSurface function. This will unbind the use cases bound by the new CameraController. CameraController should only unbind its own use cases. Otherwise, it might unexpectedly unbind use cases that belongs to another LifecycleCamera.
Relnote: "Fixed the issue that camera is closed unexpectedly when multiple CameraController and PreviewView are used in one Activity."
Bug: 197539358
Test: buildview='./gradlew camera:camera-view:build' && testview='./gradlew camera:camera-view:connectedAndroidTest'
Change-Id: Ibfd1842890b683ae3db639bf0cc4a2202110fe9f
M camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
M camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
ch...@google.com <ch...@google.com> #7
The issue is fixed by
Description
CAMERAX VERSION 1.1.0-alpha08, also in 1.0.0
DEVICE NAME: Pixel 4XL
DESCRIPTION: An app that display the camera on Screen A, then going to Screen B which also displays the camera. Screen B will be black if using the CameraController class to display the camera on the screen.
STEPS TO REPRODUCE: See sample here (in Compose, sorry) :https://github.com/NitroG42/CameraXSuccessiveCameraController
OBSERVED RESULTS: It seems that when going to the second screen, the lifecycle of first screen is destroyed and it closes the camera, which leaves the second screen in a bad state. When going back to the first screen, the camera is still closed.
EXPECTED RESULTS: The camera doesn't close if it's already used in a new screen.
REPRODUCIBILITY: Always