From 20b466872b53e26083d057512f10e01e0a2cb3f4 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Thu, 17 Aug 2023 11:08:14 +0200 Subject: [PATCH] current stand --- .../java/app/myzel394/alibi/CameraHandler.kt | 69 +++++++++++++++--- .../alibi/ui/screens/RecorderScreen.kt | 71 ++++++++++++------- 2 files changed, 104 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/CameraHandler.kt b/app/src/main/java/app/myzel394/alibi/CameraHandler.kt index cbc3e41..7c9b392 100644 --- a/app/src/main/java/app/myzel394/alibi/CameraHandler.kt +++ b/app/src/main/java/app/myzel394/alibi/CameraHandler.kt @@ -6,27 +6,18 @@ import android.graphics.ImageFormat import android.hardware.camera2.CameraCaptureSession import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraDevice -import android.hardware.camera2.CameraDevice.StateCallback.ERROR_CAMERA_DEVICE -import android.hardware.camera2.CameraDevice.StateCallback.ERROR_CAMERA_SERVICE import android.hardware.camera2.CameraManager -import android.hardware.camera2.params.OutputConfiguration -import android.hardware.camera2.params.SessionConfiguration -import android.media.Image import android.media.ImageReader import android.os.Build import android.os.Handler import android.os.HandlerThread import android.util.Log +import android.util.Size import android.view.Surface import androidx.annotation.RequiresApi -import androidx.core.content.ContentProviderCompat.requireContext -import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.getSystemService import kotlinx.coroutines.suspendCancellableCoroutine import java.io.File -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.Executor -import java.util.logging.Logger import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -60,7 +51,25 @@ class CameraHandler( } @RequiresApi(Build.VERSION_CODES.P) - public suspend fun takePhoto( + suspend fun startPreview( + surface: Surface, + ) { + val outputs = listOf(surface) + val session = createCaptureSession(outputs) + + val captureRequest = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) + captureRequest.addTarget(surface) + + session.setRepeatingRequest(captureRequest.build(), null, handler) + } + + fun stopPreview() { + device.close() + thread.quitSafely() + } + + @RequiresApi(Build.VERSION_CODES.P) + suspend fun takePhoto( outputFile: File, ) { Log.d("Alibi", "Taking photo") @@ -108,6 +117,44 @@ class CameraHandler( Log.d("Alibi", "Success!") } + private fun getOptimalPreviewSize(sizes: List, w: Int, h: Int): Size { + val ASPECT_TOLERANCE = 0.1 + val targetRatio = h.toDouble() / w + var optimalSize: Size? = null + + var minDiff = Double.MAX_VALUE + + for (size in sizes) { + val ratio: Double = size.width as Double / size.height + if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue + if (Math.abs(size.height - h) < minDiff) { + optimalSize = size + minDiff = Math.abs(size.height - h).toDouble() + } + } + + + if (optimalSize == null) { + minDiff = Double.MAX_VALUE + for (size in sizes) { + if (Math.abs(size.height - h) < minDiff) { + optimalSize = size + minDiff = Math.abs(size.height - h).toDouble() + } + } + } + + return optimalSize!! + } + + fun getPreviewSize(): Size { + val characteristics = manager.getCameraCharacteristics(CameraCharacteristics.LENS_FACING_BACK.toString()) + return characteristics + .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!! + .getOutputSizes(ImageFormat.JPEG) + .maxByOrNull { it.height * it.width }!! + } + companion object { const val IMAGE_BUFFER_SIZE = 3 diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt index 483ba99..d6d8a35 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt @@ -13,6 +13,8 @@ import android.media.ImageReader import android.os.Handler import android.os.HandlerThread import android.util.Log +import android.view.SurfaceHolder +import android.view.SurfaceView import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import androidx.camera.core.ImageCapture @@ -71,41 +73,61 @@ fun RecorderScreen( ) { val context = LocalContext.current val lifecycle = LocalLifecycleOwner.current + val scope = rememberCoroutineScope() - Scaffold( - topBar = { - TopAppBar( - title = { - Text(stringResource(R.string.app_name)) - }, - actions = { - IconButton( - onClick = { - navController.navigate(Screen.Settings.route) - }, - ) { - Icon( - Icons.Default.Settings, - contentDescription = null + var camera by remember { mutableStateOf(null) } + + + AndroidView( + factory = {context -> + val surfaceView = SurfaceView(context).apply { + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ) + } + + surfaceView.holder.addCallback(object : SurfaceHolder.Callback { + override fun surfaceCreated(holder: SurfaceHolder) { + scope.launch { + camera = CameraHandler.openCamera(context) + + val previewSize = camera!!.getPreviewSize() + + holder.setFixedSize( + 1080, + 1920, ) + + camera!!.startPreview(holder.surface) } } - ) - }, - ) { padding -> - val scope = rememberCoroutineScope() - // Wait for `CameraHadler.openCamera` - var camera by remember { mutableStateOf(null) } + override fun surfaceChanged( + holder: SurfaceHolder, + format: Int, + width: Int, + height: Int + ) { + } + override fun surfaceDestroyed(holder: SurfaceHolder) { + scope.launch { + camera!!.stopPreview() + } + } + }) + + surfaceView + } + + ) Button( - modifier = Modifier - .padding(padding), onClick = { scope.launch { if (camera == null) { - camera = CameraHandler.Companion.openCamera(context) + camera = CameraHandler.openCamera(context) } camera!!.takePhoto( @@ -180,5 +202,4 @@ fun RecorderScreen( ) } */ - } }