1

I'm quite new to Android app development. However I can't really figure out why this code Fragment is not working, I'm trying to preview the camera in a PreviewView within an android fragment.

Fragment XML:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Camera">
    
    <androidx.camera.view.PreviewView
        android:id="@+id/cameraPreview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

Fragment Kotlin code:

package dev.splitsecond.splitsecond_poc

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import dev.splitsecond.splitsecond_poc.databinding.FragmentCameraBinding
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


class Camera : Fragment() {
    private lateinit var cameraExecutor: ExecutorService
    private lateinit var binding: FragmentCameraBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = FragmentCameraBinding.inflate(layoutInflater, null, false)
        cameraExecutor = Executors.newSingleThreadExecutor()
        requestRequiredPermissions()
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_camera, container, false)
    }

    private fun requestRequiredPermissions() {
        requestCameraPermissionIfMissing { granted ->
            if (granted)
                startCamera()
            else
                Toast.makeText(activity, "Please allow camera permission", Toast.LENGTH_LONG).show()
        }
    }

    private fun requestCameraPermissionIfMissing(onResult: ((Boolean) -> Unit)) {
        if (ContextCompat.checkSelfPermission(
                requireContext(),
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED
        )
            onResult(true)
        else
            registerForActivityResult(ActivityResultContracts.RequestPermission()) {
                onResult(it)
            }.launch(Manifest.permission.CAMERA)
    }

    private fun startCamera() {
        val processCameraProvider = ProcessCameraProvider.getInstance(requireContext())
        processCameraProvider.addListener({

            val cameraProvider = processCameraProvider.get()
            val previewUseCase = buildPreviewUseCase()


            cameraProvider.unbindAll()
            cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, previewUseCase)
        }, ContextCompat.getMainExecutor(requireContext()))
    }

    private fun buildPreviewUseCase(): Preview {
        return Preview.Builder().build()
            .also { it.setSurfaceProvider(binding.cameraPreview.surfaceProvider) }
    }
}

And the logcat logs:

2022-12-01 09:21:15.984 25928-25962/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} Opening camera.
2022-12-01 09:21:15.984 25928-25962/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} Transitioning camera internal state: INITIALIZED --> OPENING
2022-12-01 09:21:15.984 25928-25962/dev.splitsecond.splitsecond_poc D/CameraStateMachine: New public camera state CameraState{type=OPENING, error=null} from OPENING and null
2022-12-01 09:21:15.984 25928-25962/dev.splitsecond.splitsecond_poc D/CameraStateMachine: Publishing new public camera state CameraState{type=OPENING, error=null}
2022-12-01 09:21:15.985 25928-25962/dev.splitsecond.splitsecond_poc D/UseCaseAttachState: All use case: [androidx.camera.core.Preview-996def38-14f2-4f96-a3bb-26039503675b19184323] for camera: 0
2022-12-01 09:21:15.996 25928-25962/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} Use case androidx.camera.core.Preview-996def38-14f2-4f96-a3bb-26039503675b19184323 ACTIVE
2022-12-01 09:21:15.996 25928-25962/dev.splitsecond.splitsecond_poc D/UseCaseAttachState: Active and attached use case: [androidx.camera.core.Preview-996def38-14f2-4f96-a3bb-26039503675b19184323] for camera: 0
2022-12-01 09:21:15.998 25928-25962/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} CameraDevice.onOpened()
2022-12-01 09:21:15.998 25928-25962/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} Transitioning camera internal state: OPENING --> OPENED
2022-12-01 09:21:15.998 25928-25962/dev.splitsecond.splitsecond_poc D/CameraStateRegistry: Recalculating open cameras:
    Camera                                       State                 
    -------------------------------------------------------------------
    Camera@43190c8[id=0]                         OPEN                  
    Camera@a26fb0c[id=1]                         UNKNOWN               
    -------------------------------------------------------------------
    Open count: 1 (Max allowed: 1)
2022-12-01 09:21:15.998 25928-25962/dev.splitsecond.splitsecond_poc D/CameraStateMachine: New public camera state CameraState{type=OPEN, error=null} from OPEN and null
2022-12-01 09:21:15.998 25928-25962/dev.splitsecond.splitsecond_poc D/CameraStateMachine: Publishing new public camera state CameraState{type=OPEN, error=null}
2022-12-01 09:21:15.999 25928-25962/dev.splitsecond.splitsecond_poc D/UseCaseAttachState: All use case: [androidx.camera.core.Preview-996def38-14f2-4f96-a3bb-26039503675b19184323] for camera: 0
2022-12-01 09:21:16.000 25928-25962/dev.splitsecond.splitsecond_poc D/UseCaseAttachState: Active and attached use case: [androidx.camera.core.Preview-996def38-14f2-4f96-a3bb-26039503675b19184323] for camera: 0
2022-12-01 09:21:17.173 25928-25940/dev.splitsecond.splitsecond_poc W/System: A resource failed to call close. 
2022-12-01 09:21:21.006 25928-25961/dev.splitsecond.splitsecond_poc D/Camera2CameraImpl: {Camera@43190c8[id=0]} Transitioning camera internal state: OPENED --> OPENED
2022-12-01 09:21:21.007 25928-25961/dev.splitsecond.splitsecond_poc D/CameraStateMachine: New public camera state CameraState{type=OPEN, error=StateError{code=4, cause=java.util.concurrent.TimeoutException: Cannot complete surfaceList within 5000}} from OPEN and StateError{code=4, cause=java.util.concurrent.TimeoutException: Cannot complete surfaceList within 5000}
2022-12-01 09:21:21.007 25928-25961/dev.splitsecond.splitsecond_poc D/CameraStateMachine: Publishing new public camera state CameraState{type=OPEN, error=StateError{code=4, cause=java.util.concurrent.TimeoutException: Cannot complete surfaceList within 5000}}
2022-12-01 09:21:21.008 25928-25961/dev.splitsecond.splitsecond_poc E/Camera2CameraImpl: Unable to configure camera 0, timeout!

I would really like to understand what I am doing wrong.

Ramon Vermeulen
  • 112
  • 2
  • 9
  • Which CameraX version do you use? For some people upgrading the library version helped. Unfortunately not for me. See https://stackoverflow.com/q/73451099/8019153 – Adam Głowacki Jan 11 '23 at 22:19

0 Answers0