CameraX beta03 and bottom sheet scroll issue

Viewed 407

I was upgrading cameraX alpha to 1.0.0-beta03 in my project. I am following this. Everything is working and I am able to take an image as expected.

But I have a bottom sheet in the camera fragment. After I have implemented the beta03, while scrolling the bottom sheet, it seems to be overlapped by some invisible view, like this:

enter image description here

After debugging for some time found out this is only happening when I pass camera?.cameraInfo to viewFinder.createSurfaceProvider. If I pass null, this issue is not happening. But I don't know the implications of this.

preview?.setSurfaceProvider(
                viewFinder.createSurfaceProvider(camera?.cameraInfo))

When I pass null here, The bottom sheet completely comes up.

This is what the documentation says:

/**
     * Gets the {@link Preview.SurfaceProvider} to be used with
     * {@link Preview#setSurfaceProvider(Executor, Preview.SurfaceProvider)}.
     * <p>
     * The returned {@link Preview.SurfaceProvider} will provide a preview
     * {@link android.view.Surface} to the camera that's either managed by a
     * {@link android.view.TextureView} or {@link android.view.SurfaceView}. This option is
     * determined by the {@linkplain #setPreferredImplementationMode(ImplementationMode)
     * preferred implementation mode} and the device's capabilities.
     *
     * @param cameraInfo The {@link CameraInfo} of the camera that will use the
     *                   {@link android.view.Surface} provided by the returned
     *                   {@link Preview.SurfaceProvider}.
     * @return A {@link Preview.SurfaceProvider} used to start the camera preview.
     */

I have added a random bottom sheet to google's sample app and pushed it here(Github link) with the bug reproduced. (Please build Cameraxbasic module. My branch is Bug_repro_bottomsheet)

Can someone please explain whats going on and how to fix this?

Note: I tried updating the z-index and elevation of the bottom sheet. and it didn't work

2 Answers

The documentation of PreviewView.createSurfaceProvider() states:

The returned Preview.SurfaceProvider will provide a preview Surface to the camera that's either managed by a TextureView or SurfaceView. This option is determined by the preferred implementation mode and the device's capabilities.

Note that whether the preview surface is managed by a TextureView or SurfaceView partially depends on the CameraInfo instance you pass into PreviewView.createSurfcaeProvider().

  • If you pass in null, PreviewView uses a TextureView by default.
  • If you pass in a non-null CameraInfo instance, PreviewView will try to use a SurfaceView, but will fall back to using a TextureView on certain devices, e.g Legacy devices, devices running on API level 24 or lower, etc.

Going back to the issue you're seeing, it's happening when you pass in a non-null CameraInfo instance, it's probably because the device you tested on supports SurfaceView well, so PreviewView uses it.

When you pull up the bottom sheet, it stops where the SurfaceView ends. Even though the SurfaceView seems to occupy the entire screen, it only occupies a part of it (the rectangle from the top of the screen until the point where the bottom sheet stops), that's because the SurfaceView is scaled up to fill the entire screen (PreviewView calls the methods SurfaceView.setScaleX() and PSurfaceView.setScaleY() internally, causing the preview to stretch, but the bounds of the SurfaceView, aka the rectangle it occupies in the View hierarchy, doesn't change).

Going through the documentation of SurfaceView, you'll see that:

The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed.

The SurfaceView isn't like your typical View, it's handled/rendered differently than a normal View, and its surface exists on a separate layer, independent of the graphics layer used to render the View hierarchy. So if you intend to have other Views scroll on top of the preview, you might need to force PreviewView to use a TextureView to manage the preview surface. You can do this by either passing null to PreviewView.createSurfaceProvider(), or call PreviewView.setPreferredImplementationMode(ImplementationMode.PreviewView).

You can read more about PreviewView here.

For androidx.camera:camera-view:1.0.0-alpha31 just set compatible implementationMode to PreviewView (before setSurfaceProvider) to fix this issue:

previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE
Related