capacitor-community / capacitor-community/camera-preview

Android: intermittent black preview followed by process-fatal takePicture failed on v8.0.1

Open
#424 1 comment 0 reactions 1 assignee Claimed by @ryaa View on GitHub
bug
Dominant language
Java
Stars
227
Forks
185
PR merge metrics
No merged PRs in 30d

Description

## Description

On Android, the camera preview intermittently opens as a black surface even though `CameraPreview.start()` has resolved and the capture controls are enabled. If the user then calls `CameraPreview.capture()`, the app process terminates with an unhandled native exception:

```text
FATAL EXCEPTION: Thread-6
Process: boss.mobile.shared.example.app, PID: 6963
java.lang.RuntimeException: takePicture failed
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:1495)
at android.hardware.Camera.takePicture(Camera.java:1437)
at com.ahm.capacitor.camera.preview.CameraActivity$6.run(CameraActivity.java:843)
```

The failure is intermittent. Reopening the same flow can produce a working preview and successful capture.

This report does **not** claim that the problem was introduced by Capacitor 8. A similar black-preview/`takePicture failed` failure was reported in [#40](https://github.com/capacitor-community/camera-preview/issues/40) against an older plugin version. The current report confirms the behavior on v8.0.1 with a current Capacitor 8 application.

## Environment

| Item | Value |
| --- | --- |
| `@capacitor-community/camera-preview` | `8.0.1` |
| `@capacitor/core` | `8.5.0` |
| `@capacitor/android` | `8.5.0` |
| Framework | Ionic `8.8.19`; Angular `20.3.29` |
| Node / npm | Node `24.19.0`; npm `11.17.0` |
| Camera | Rear camera; physical device |

## Steps to reproduce

1. Install and launch the Android debug build on a physical device.
2. Grant camera permission if prompted.
3. Navigate to the flow that uses `CameraPreview.start()` with the rear camera.
4. Open the preview repeatedly until the native preview area remains black while the HTML overlay/capture controls are visible.
5. Tap the capture control, which invokes `CameraPreview.capture()`.
6. Observe that the app process terminates with `java.lang.RuntimeException: takePicture failed`.

## Actual behavior

- `CameraPreview.start()` resolves and the app enables capture controls.
- The preview surface remains black and no camera frames are visible.
- Calling `CameraPreview.capture()` in that state throws on a plugin-owned native thread and terminates the app process.
- The exception is not returned as a rejected Capacitor call, so application JavaScript cannot recover from it.

## Expected behavior

- A successful `start()` result, or another documented readiness signal, should mean that the native preview is actually running.
- A failure to start the preview should be propagated to the Capacitor caller.
- `capture()` should never terminate the app process. If the preview is not ready/running, the call should fail safely with an actionable error.

## Initial native-code observations

These are observations from the installed v8.0.1 source and are included as areas to investigate, not as a definitive maintainer diagnosis:

- [`CameraActivity.java`](https://github.com/capacitor-community/camera-preview/blob/v8.0.1/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java) appears to notify `onCameraStarted()` after attaching the camera to the preview, before `SurfaceView.surfaceChanged()` has necessarily completed `startPreview()`.
- [`Preview.java`](https://github.com/capacitor-community/camera-preview/blob/v8.0.1/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java) catches preview-start failures in the surface callback and logs them, but does not appear to propagate them to the pending Capacitor call.
- `takePicture()` invokes the legacy `android.hardware.Camera.takePicture()` from a plain thread. The observed `RuntimeException` is unhandled on that thread and is therefore process-fatal.
- `isCameraStarted()` appears to indicate that a camera object exists rather than that preview frames are flowing, so it cannot distinguish this black-preview state.

Could the Android implementation please provide a reliable preview-ready/failure signal and guard `capture()` so native camera failures reject the plugin call instead of terminating the process?

## Diagnostic evidence

- Black-preview screenshot:
Image

- Full Logcat capture:
```
2026-08-25 15:51:51.128 6963-6963 View boss.mobile.shared.example.app I setRequestedFrameRate frameRate=-4.0, this=com.getcapacitor.CapacitorWebView{d5f907c VFEDHVC.. .F...... 0,0-1080,2340 #7f090232 app:id/webview aid=1073741824}, caller=android.view.ViewGroup.setRequestedFrameRate:10045 WV.ue.p:1 WV.sf.h:117 WV.sf.onDraw:7 com.android.webview.chromium.WebViewChromium.onDraw:19
2026-08-25 15:51:51.132 6963-10058 AndroidRuntime boss.mobile.shared.example.app E FATAL EXCEPTION: Thread-6 (Fix with AI)
Process: boss.mobile.shared.example.app, PID: 6963
java.lang.RuntimeException: takePicture failed
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:1495)
at android.hardware.Camera.takePicture(Camera.java:1437)
at com.ahm.capacitor.camera.preview.CameraActivity$6.run(CameraActivity.java:843)
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.