Search code examples
androidandroid-jetpack-composeandroid-camera

Camera PreviewView produces black screen


This is my code:

@Composable
fun MyCameraPreview() {
    val lifecycleOwner = LocalLifecycleOwner.current
    AndroidView(factory = { context ->
        val previewView = PreviewView(context).apply {
            scaleType = PreviewView.ScaleType.FILL_CENTER
            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
            implementationMode = PreviewView.ImplementationMode.COMPATIBLE
        }

        ProcessCameraProvider.getInstance(context).apply {
            addListener({
                val cameraProvider = this.get()
                val preview = androidx.camera.core.Preview.Builder().build().apply {
                    setSurfaceProvider(previewView.surfaceProvider)
                }

                try {
                    cameraProvider.unbindAll()
                    cameraProvider.bindToLifecycle(lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }, ContextCompat.getMainExecutor(context))
        }

        previewView
    })
}

which I took from this answer.

All I see is a black screen though. In the manifest I've requested these permissions:

<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

(do I even need the record audio permission? I'm not interested in recording audio.)

Is there anything else I'm missing? How to make PreviewView actually show what's coming from the camera?

Oh, there is this error in the log:

Camera reopening attempted for 10000ms without success.


Solution

  • Turns out, one has to explicitely ask for permission to use the camera. Just having it in the manifest isn't enough.

    Boild down, this could just be:

        registerForActivityResult(ActivityResultContracts.RequestPermission()) { permission ->
            Log.d("-- CAMERA PERMISSION --", permission.toString())
        }.launch(Manifest.permission.CAMERA)
        
    

    Oh, and no, it seems like I don't need the record audio permission.