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.