Skip to content

Android: screen.screenshot() captures a TextureView or a SurfaceView as transparent pixels #197

Open

Description

@YevheniiKotyrlo

Describe the bug

On Android, screen.screenshot() returns the area of a TextureView or a SurfaceView as fully transparent pixels, while the device shows their content. Any view a GPU renders — react-native-skia, react-native-webgpu, a video or camera preview, a map — therefore can't be checked with toMatchImageSnapshot on Android.

On screen (adb exec-out screencap -p) screen.screenshot()

A red TextureView above a blue SurfaceView, each 100 × 100 dp; the checkerboard marks transparent pixels.

UIHelperImpl.captureScreenshot draws the view tree into a software Bitmap (root.draw(canvas)). A TextureView draws nothing into a software canvas (TextureView: "When rendered in software, TextureView will draw nothing"), and a SurfaceView's content lives on a surface of its own behind the window, which leaves a transparent hole over it.

A fix I have working: capture an on-screen region with PixelCopy (API 26+). PixelCopy.request(window, …) copies the window's surface, which TextureViews render into, and PixelCopy.request(surfaceView, …) copies each visible SurfaceView's surface, drawn under the window's copy so it shows through the hole. Off-screen elements keep the direct view draw. With it, the screenshot above matches the screen pixel for pixel. One limit: SurfaceView.isZOrderedOnTop() is hidden API, so a SurfaceView set on top of its window would be drawn under it; a host-side adb exec-out screencap from the Android runner, like the web runner's Playwright capture, has no such limit. I can open a PR with either approach.

System Info

System:
  OS: Windows 11 10.0.26200
Binaries:
  Node: 26.5.0
SDKs:
  Android SDK:
    API Levels: 35, 36, 37
    Build Tools: 35.0.0, 36.0.0, 36.1.0, 37.0.0
Android:
  hermesEnabled: true
  newArchEnabled: true
react-native: 0.82.1 (apps/playground)
Device: Android emulator, API 36, x86_64

React Native Harness Version

1.5.0 (main at 58850ce)

Reproduction

https://github.com/YevheniiKotyrlo/react-native-harness/tree/repro/android-screenshot-gpu-surfaces

Steps to reproduce

  1. Check out the branch above. It adds two native views to the playground — a TextureView and a SurfaceView that each paint one color from the CPU — and src/__tests__/normal/ui/surfaces.android.harness.tsx, which waits until both have shown their frame and then screenshots each.
  2. Build the playground for Android and run react-native-harness --harnessRunner android src/__tests__/normal/ui/surfaces.android.harness.tsx.
  3. The run passes, because toMatchImageSnapshot writes a missing snapshot, and the snapshots it writes, __image_snapshots__/android/texture-view-red.png and surface-view-blue.png, are fully transparent instead of red and blue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions