Implemented asking for Camera permission

This commit is contained in:
dankito 2024-10-04 05:48:11 +02:00
parent 316a0027f7
commit e1bb7722ff
5 changed files with 57 additions and 11 deletions

View File

@ -106,6 +106,7 @@ kotlin {
androidMain.dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.fragment) // to fix bug IllegalArgumentException: Can only use lower 16 bits for requestCode
implementation(libs.androidx.biometric)
implementation(libs.favre.bcrypt)

View File

@ -2,6 +2,7 @@ package net.codinux.banking.ui
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.fragment.app.FragmentActivity
@ -11,6 +12,11 @@ import net.codinux.banking.ui.service.BiometricAuthenticationService
import net.codinux.banking.ui.service.ImageService
class MainActivity : FragmentActivity() {
private val request = ActivityResultContracts.RequestMultiplePermissions()
private val activityResultLauncher = registerForActivityResult(request) { }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -23,8 +29,29 @@ class MainActivity : FragmentActivity() {
App()
}
}
fun requestPermissions(requiredPermissions: List<String>): Boolean {
val requiredPermissionsArray = requiredPermissions.toTypedArray()
activityResultLauncher.launch(requiredPermissionsArray)
var result = request.getSynchronousResult(baseContext, requiredPermissionsArray)
while (result == null) {
result = request.getSynchronousResult(baseContext, requiredPermissionsArray)
}
return if (result.value != null) {
val allPermissionsGranted = result.value.entries.filter { it.key in requiredPermissions }.all { it.value == true }
allPermissionsGranted
} else {
false
}
}
}
@Preview
@Composable
fun AppAndroidPreview() {

View File

@ -0,0 +1,13 @@
package net.codinux.banking.ui.service
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
object PermissionsService {
fun allPermissionsGranted(baseContext: Context, permissions: List<String>) = permissions.all {
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
}
}

View File

@ -1,5 +1,6 @@
package net.codinux.banking.ui.service
import android.Manifest
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
@ -7,15 +8,14 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.QRCodeReader
import net.codinux.banking.persistence.AndroidContext
import net.codinux.banking.ui.MainActivity
import net.codinux.banking.ui.config.DI
import net.codinux.log.logger
import java.nio.ByteBuffer
@ -23,6 +23,8 @@ import java.util.concurrent.Executors
actual object QrCodeService {
private val RequiredPermissions = listOf(Manifest.permission.CAMERA)
private val cameraExecutor = Executors.newCachedThreadPool()
private val log by logger()
@ -32,16 +34,17 @@ actual object QrCodeService {
@Composable
actual fun readQrCodeFromCamera(resultCallback: (QrCodeReadResult) -> Unit) {
val context = AndroidContext.mainActivity
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
val mainActivity = LocalLifecycleOwner.current as MainActivity // we only have MainActivity, so we can be sure that LocalLifecycleOwner.current is MainActivity
val localContext = LocalContext.current
log.info { "LocalContext.current = ${localContext.javaClass} ${localContext}" }
if (PermissionsService.allPermissionsGranted(AndroidContext.applicationContext, RequiredPermissions) == false &&
mainActivity.requestPermissions(RequiredPermissions) == false) {
return // we don't have the permission to start the camera
}
val cameraProviderFuture = ProcessCameraProvider.getInstance(mainActivity)
val lifecycleOwner = LocalLifecycleOwner.current
// val context = LocalContext.current
val previewView = remember {
PreviewView(context)
PreviewView(mainActivity)
}
cameraProviderFuture.addListener({
@ -69,13 +72,13 @@ actual object QrCodeService {
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(context as FragmentActivity, cameraSelector, preview, imageAnalyzer)
cameraProvider.bindToLifecycle(mainActivity, cameraSelector, preview, imageAnalyzer)
} catch(e: Exception) {
log.error(e) { "Use case binding failed" }
}
}, ContextCompat.getMainExecutor(context))
}, ContextCompat.getMainExecutor(mainActivity))
AndroidView(factory = { previewView }, modifier = Modifier.fillMaxSize())

View File

@ -24,6 +24,7 @@ android-targetSdk = "34"
androidx-activityCompose = "1.9.2"
androidx-lifecycle = "2.8.2"
androidx-fragment = "1.8.3"
androidx-biometric = "1.1.0"
compose-plugin = "1.6.11"
@ -57,6 +58,7 @@ sqldelight-native-driver = { module = "app.cash.sqldelight:native-driver", versi
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "androidx-fragment" }
androidx-biometric = { group = "androidx.biometric", name = "biometric", version.ref = "androidx-biometric" }
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }