mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-20 15:45:26 +02:00
feat: Add POC for CameraHandler
This commit is contained in:
parent
9997e0a3ec
commit
f22f2c3802
@ -95,7 +95,7 @@ dependencies {
|
|||||||
implementation 'androidx.compose.ui:ui-graphics'
|
implementation 'androidx.compose.ui:ui-graphics'
|
||||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||||
implementation 'androidx.compose.material3:material3'
|
implementation 'androidx.compose.material3:material3'
|
||||||
implementation "androidx.compose.material:material-icons-extended:1.4.3"
|
implementation "androidx.compose.material:material-icons-extended:1.5.0"
|
||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-service:2.6.1'
|
implementation 'androidx.lifecycle:lifecycle-service:2.6.1'
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
@ -106,7 +106,7 @@ dependencies {
|
|||||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||||
|
|
||||||
implementation "androidx.navigation:navigation-compose:2.7.0-rc01"
|
implementation "androidx.navigation:navigation-compose:2.7.0"
|
||||||
|
|
||||||
implementation 'com.google.dagger:hilt-android:2.46.1'
|
implementation 'com.google.dagger:hilt-android:2.46.1'
|
||||||
annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1'
|
annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1'
|
||||||
|
170
app/src/main/java/app/myzel394/alibi/CameraHandler.kt
Normal file
170
app/src/main/java/app/myzel394/alibi/CameraHandler.kt
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package app.myzel394.alibi
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
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.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
|
||||||
|
|
||||||
|
class CameraHandler(
|
||||||
|
private val manager: CameraManager,
|
||||||
|
private val device: CameraDevice,
|
||||||
|
private val handler: Handler,
|
||||||
|
private val thread: HandlerThread,
|
||||||
|
) {
|
||||||
|
private lateinit var imageReader: ImageReader
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
|
private suspend fun createCaptureSession(
|
||||||
|
outputs: List<Surface>,
|
||||||
|
): CameraCaptureSession = suspendCancellableCoroutine { cont ->
|
||||||
|
// I really don't want to use a deprecated method, but there is
|
||||||
|
// absolutely no documentation available for the new method.
|
||||||
|
device.createCaptureSession(
|
||||||
|
outputs,
|
||||||
|
object : CameraCaptureSession.StateCallback() {
|
||||||
|
override fun onConfigured(session: CameraCaptureSession) {
|
||||||
|
cont.resume(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||||
|
cont.resumeWithException(RuntimeException("Failed to configure session"))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
|
public suspend fun takePhoto(
|
||||||
|
outputFile: File,
|
||||||
|
) {
|
||||||
|
Log.d("Alibi", "Taking photo")
|
||||||
|
|
||||||
|
Log.d("Alibi", "Creating Camera Characteristics")
|
||||||
|
val characteristics = manager.getCameraCharacteristics(CameraCharacteristics.LENS_FACING_BACK.toString())
|
||||||
|
Log.d("Alibi", "Creating size")
|
||||||
|
val size = characteristics.get(
|
||||||
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
|
||||||
|
.getOutputSizes(ImageFormat.JPEG).maxByOrNull { it.height * it.width }!!
|
||||||
|
Log.d("Alibi", "Creating image reader")
|
||||||
|
imageReader = ImageReader.newInstance(
|
||||||
|
size.width,
|
||||||
|
size.height,
|
||||||
|
ImageFormat.JPEG,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
|
||||||
|
imageReader.setOnImageAvailableListener({ reader ->
|
||||||
|
val image = reader.acquireLatestImage()
|
||||||
|
|
||||||
|
// Save image to file
|
||||||
|
outputFile.outputStream().use { stream ->
|
||||||
|
image.planes[0].buffer.apply {
|
||||||
|
val bytes = ByteArray(remaining())
|
||||||
|
get(bytes)
|
||||||
|
stream.write(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Image saved to ${outputFile.absolutePath}")
|
||||||
|
|
||||||
|
image.close()
|
||||||
|
}, handler)
|
||||||
|
|
||||||
|
Log.d("Alibi", "Creating capture session")
|
||||||
|
val session = createCaptureSession(listOf(imageReader.surface))
|
||||||
|
|
||||||
|
Log.d("Alibi", "Creating capture request")
|
||||||
|
val captureRequest = device.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
|
||||||
|
captureRequest.addTarget(imageReader.surface)
|
||||||
|
|
||||||
|
Log.d("Alibi", "Capturing")
|
||||||
|
session.capture(captureRequest.build(), null, handler)
|
||||||
|
Log.d("Alibi", "Success!")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val IMAGE_BUFFER_SIZE = 3
|
||||||
|
|
||||||
|
fun getCameraManager(
|
||||||
|
context: Context,
|
||||||
|
): CameraManager = getSystemService(context, CameraManager::class.java)!!
|
||||||
|
|
||||||
|
fun createThread(): HandlerThread = HandlerThread("CameraHandler").apply { start() }
|
||||||
|
fun createHandler(thread: HandlerThread): Handler = Handler(thread.looper)
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
suspend fun openCamera(
|
||||||
|
manager: CameraManager,
|
||||||
|
cameraId: String,
|
||||||
|
thread: HandlerThread,
|
||||||
|
): CameraHandler = suspendCancellableCoroutine { cont ->
|
||||||
|
val handler = createHandler(thread)
|
||||||
|
manager.openCamera(cameraId, object : CameraDevice.StateCallback() {
|
||||||
|
override fun onOpened(device: CameraDevice) {
|
||||||
|
cont.resume(
|
||||||
|
CameraHandler(
|
||||||
|
manager,
|
||||||
|
device,
|
||||||
|
handler,
|
||||||
|
thread,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisconnected(device: CameraDevice) {
|
||||||
|
Log.w("Alibi", "Camera $cameraId has been disconnected")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(device: CameraDevice, error: Int) {
|
||||||
|
val msg = when (error) {
|
||||||
|
ERROR_CAMERA_DEVICE -> "Fatal (device)"
|
||||||
|
ERROR_CAMERA_DISABLED -> "Device policy"
|
||||||
|
ERROR_CAMERA_IN_USE -> "Camera in use"
|
||||||
|
ERROR_CAMERA_SERVICE -> "Fatal (service)"
|
||||||
|
ERROR_MAX_CAMERAS_IN_USE -> "Maximum cameras in use"
|
||||||
|
else -> "Unknown"
|
||||||
|
}
|
||||||
|
val exc = RuntimeException("Camera $cameraId error: ($error) $msg")
|
||||||
|
Log.e("Alibi", exc.message, exc)
|
||||||
|
if (cont.isActive) cont.resumeWithException(exc)
|
||||||
|
}
|
||||||
|
}, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun openCamera(
|
||||||
|
context: Context,
|
||||||
|
): CameraHandler {
|
||||||
|
val manager = getCameraManager(context)
|
||||||
|
val cameraId = manager.cameraIdList.first()
|
||||||
|
val thread = createThread()
|
||||||
|
return openCamera(manager, cameraId, thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,6 @@ import app.myzel394.alibi.services.RecorderService
|
|||||||
import app.myzel394.alibi.services.VideoRecorderService
|
import app.myzel394.alibi.services.VideoRecorderService
|
||||||
|
|
||||||
@ExperimentalVideo class VideoRecorderModel: ViewModel() {
|
@ExperimentalVideo class VideoRecorderModel: ViewModel() {
|
||||||
/*
|
|
||||||
var recorderState by mutableStateOf(RecorderState.IDLE)
|
var recorderState by mutableStateOf(RecorderState.IDLE)
|
||||||
private set
|
private set
|
||||||
var recordingTime by mutableStateOf<Long?>(null)
|
var recordingTime by mutableStateOf<Long?>(null)
|
||||||
@ -37,7 +36,7 @@ import app.myzel394.alibi.services.VideoRecorderService
|
|||||||
get() = recorderState === RecorderState.PAUSED
|
get() = recorderState === RecorderState.PAUSED
|
||||||
|
|
||||||
val progress: Float
|
val progress: Float
|
||||||
get() = (recordingTime!! / recorderService!!.settings!!.maxDuration).toFloat()
|
get() = 0f
|
||||||
|
|
||||||
private var intent: Intent? = null
|
private var intent: Intent? = null
|
||||||
var recorderService: VideoRecorderService? = null
|
var recorderService: VideoRecorderService? = null
|
||||||
@ -51,28 +50,6 @@ import app.myzel394.alibi.services.VideoRecorderService
|
|||||||
|
|
||||||
private val connection = object : ServiceConnection {
|
private val connection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||||
recorderService = ((service as RecorderService.RecorderBinder).getService() as VideoRecorderService).also { recorder ->
|
|
||||||
recorder.onStateChange = { state ->
|
|
||||||
recorderState = state
|
|
||||||
}
|
|
||||||
recorder.onRecordingTimeChange = { time ->
|
|
||||||
recordingTime = time
|
|
||||||
}
|
|
||||||
recorder.onAmplitudeChange = { amps ->
|
|
||||||
amplitudes = amps
|
|
||||||
onAmplitudeChange()
|
|
||||||
}
|
|
||||||
recorder.onError = {
|
|
||||||
recorderService!!.createLastRecording()
|
|
||||||
onError()
|
|
||||||
}
|
|
||||||
|
|
||||||
recorderState = recorder.state
|
|
||||||
recordingTime = recorder.recordingTime
|
|
||||||
amplitudes = recorder.amplitudes
|
|
||||||
|
|
||||||
recorder.startRecording()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceDisconnected(arg0: ComponentName) {
|
override fun onServiceDisconnected(arg0: ComponentName) {
|
||||||
@ -99,7 +76,6 @@ import app.myzel394.alibi.services.VideoRecorderService
|
|||||||
|
|
||||||
fun stopRecording(context: Context, saveAsLastRecording: Boolean = true) {
|
fun stopRecording(context: Context, saveAsLastRecording: Boolean = true) {
|
||||||
if (saveAsLastRecording) {
|
if (saveAsLastRecording) {
|
||||||
lastRecording = recorderService!!.createLastRecording()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
@ -111,15 +87,12 @@ import app.myzel394.alibi.services.VideoRecorderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pauseRecording() {
|
fun pauseRecording() {
|
||||||
recorderService!!.changeState(RecorderState.PAUSED)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resumeRecording() {
|
fun resumeRecording() {
|
||||||
recorderService!!.changeState(RecorderState.RECORDING)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setMaxAmplitudesAmount(amount: Int) {
|
fun setMaxAmplitudesAmount(amount: Int) {
|
||||||
recorderService?.amplitudesAmount = amount
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -130,6 +103,4 @@ import app.myzel394.alibi.services.VideoRecorderService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
package app.myzel394.alibi.ui.screens
|
package app.myzel394.alibi.ui.screens
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.ImageFormat
|
import android.graphics.ImageFormat
|
||||||
import android.hardware.camera2.CameraCaptureSession
|
import android.hardware.camera2.CameraCaptureSession
|
||||||
import android.hardware.camera2.CameraCharacteristics
|
import android.hardware.camera2.CameraCharacteristics
|
||||||
import android.hardware.camera2.CameraDevice
|
import android.hardware.camera2.CameraDevice
|
||||||
|
import android.hardware.camera2.CameraManager
|
||||||
import android.hardware.camera2.params.SessionConfiguration
|
import android.hardware.camera2.params.SessionConfiguration
|
||||||
import android.media.Image
|
import android.media.Image
|
||||||
import android.media.ImageReader
|
import android.media.ImageReader
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
|
import android.util.Log
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
import androidx.camera.core.ImageCapture
|
import androidx.camera.core.ImageCapture
|
||||||
@ -21,6 +26,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -37,7 +43,9 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import app.myzel394.alibi.CameraHandler
|
||||||
import app.myzel394.alibi.R
|
import app.myzel394.alibi.R
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.AudioRecordingStatus
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.AudioRecordingStatus
|
||||||
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.StartRecording
|
import app.myzel394.alibi.ui.components.RecorderScreen.molecules.StartRecording
|
||||||
@ -50,9 +58,10 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import androidx.compose.runtime.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission", "NewApi")
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun RecorderScreen(
|
fun RecorderScreen(
|
||||||
@ -64,63 +73,6 @@ fun RecorderScreen(
|
|||||||
val lifecycle = LocalLifecycleOwner.current
|
val lifecycle = LocalLifecycleOwner.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val cameraController = remember {LifecycleCameraController(context)}
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
scope.launch {
|
|
||||||
// Take a picture
|
|
||||||
val manager = ContextCompat.getSystemService(context, android.hardware.camera2.CameraManager::class.java)!!
|
|
||||||
|
|
||||||
val cameraId = manager.cameraIdList.first()
|
|
||||||
|
|
||||||
manager.openCamera(
|
|
||||||
cameraId,
|
|
||||||
object: CameraDevice.StateCallback() {
|
|
||||||
override fun onDisconnected(p0: CameraDevice) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(p0: CameraDevice, p1: Int) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOpened(p0: CameraDevice) {
|
|
||||||
val camDevice = p0
|
|
||||||
|
|
||||||
val cameraCharacteristics = manager.getCameraCharacteristics(cameraId)
|
|
||||||
val previewSize = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!.getOutputSizes(
|
|
||||||
ImageFormat.JPEG).maxByOrNull { it.height * it.width }!!
|
|
||||||
val imageReader = ImageReader.newInstance(previewSize.width, previewSize.height, ImageFormat.JPEG, 1)
|
|
||||||
imageReader.setOnImageAvailableListener(
|
|
||||||
{ reader ->
|
|
||||||
val image: Image = reader.acquireLatestImage()
|
|
||||||
},
|
|
||||||
null
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create capture
|
|
||||||
val captureBuilder = camDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
|
|
||||||
captureBuilder.addTarget(imageReader.surface)
|
|
||||||
|
|
||||||
// Create session
|
|
||||||
camDevice.createCaptureSession(
|
|
||||||
listOf(imageReader.surface),
|
|
||||||
object: CameraCaptureSession.StateCallback() {
|
|
||||||
override fun onConfigureFailed(p0: CameraCaptureSession) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConfigured(p0: CameraCaptureSession) {
|
|
||||||
val session = p0
|
|
||||||
session.capture(captureBuilder.build(), object: CameraCaptureSession.CaptureCallback() {}, null)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@ -141,6 +93,92 @@ fun RecorderScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {padding ->
|
) { padding ->
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// Wait for `CameraHadler.openCamera`
|
||||||
|
var camera by remember { mutableStateOf<CameraHandler?>(null) }
|
||||||
|
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(padding),
|
||||||
|
onClick = {
|
||||||
|
scope.launch {
|
||||||
|
if (camera == null) {
|
||||||
|
camera = CameraHandler.Companion.openCamera(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
camera!!.takePhoto(
|
||||||
|
File(
|
||||||
|
context.externalCacheDir!!.absolutePath,
|
||||||
|
"test.jpg"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Take photo")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
val cameraManager = getSystemService(context, CameraManager::class.java)!!
|
||||||
|
val backgroundThread = HandlerThread("CameraVideo").apply {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
val backgroundHandler = Handler(backgroundThread.looper)
|
||||||
|
|
||||||
|
val characteristics = cameraManager.getCameraCharacteristics(CameraCharacteristics.LENS_FACING_BACK.toString())
|
||||||
|
|
||||||
|
|
||||||
|
val cameraStateCallback = object : CameraDevice.StateCallback() {
|
||||||
|
override fun onOpened(camera: CameraDevice) {
|
||||||
|
val captureStateCallback = object : CameraCaptureSession.StateCallback() {
|
||||||
|
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||||
|
Log.e("Camera", "Failed to configure camera")
|
||||||
|
}
|
||||||
|
override fun onConfigured(session: CameraCaptureSession) {
|
||||||
|
val onImageAvailableListener = object: ImageReader.OnImageAvailableListener{
|
||||||
|
override fun onImageAvailable(reader: ImageReader) {
|
||||||
|
val image: Image = reader.acquireLatestImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
|
||||||
|
|
||||||
|
session.capture(captureRequest.build(), null, backgroundHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val previewSize = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!.getOutputSizes(ImageFormat.JPEG).maxByOrNull { it.height * it.width }!!
|
||||||
|
val imageReader = ImageReader.newInstance(previewSize.width, previewSize.height, ImageFormat.JPEG, 1)
|
||||||
|
camera.createCaptureSession(
|
||||||
|
listOf(imageReader.surface),
|
||||||
|
captureStateCallback,
|
||||||
|
backgroundHandler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisconnected(cameraDevice: CameraDevice) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
||||||
|
val errorMsg = when(error) {
|
||||||
|
ERROR_CAMERA_DEVICE -> "Fatal (device)"
|
||||||
|
ERROR_CAMERA_DISABLED -> "Device policy"
|
||||||
|
ERROR_CAMERA_IN_USE -> "Camera in use"
|
||||||
|
ERROR_CAMERA_SERVICE -> "Fatal (service)"
|
||||||
|
ERROR_MAX_CAMERAS_IN_USE -> "Maximum cameras in use"
|
||||||
|
else -> "Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraManager.openCamera(
|
||||||
|
CameraCharacteristics.LENS_FACING_BACK.toString(),
|
||||||
|
cameraStateCallback,
|
||||||
|
backgroundHandler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user