feat: Add biometric authentication check

This commit is contained in:
Myzel394 2023-12-23 19:57:55 +01:00
parent bf84396a86
commit a73fc6c48f
No known key found for this signature in database
GPG Key ID: 50098FCA22080F0F
3 changed files with 68 additions and 38 deletions

View File

@ -553,16 +553,8 @@ data class NotificationSettings(
@Serializable
class AppLockSettings {
// If the object is present, biometric authentication is enabled.
// To disable biometric authentication, set the instance to null.
val isEnabled
get() = true
companion object {
fun getDefaultInstance(): AppLockSettings = AppLockSettings()
fun isSupported(context: Context): Boolean {
val biometricManager = BiometricManager.from(context)
when (biometricManager.canAuthenticate(Authenticators.BIOMETRIC_STRONG or Authenticators.DEVICE_CREDENTIAL)) {
}
}
}

View File

@ -0,0 +1,64 @@
package app.myzel394.alibi.helpers
import android.content.Context
import androidx.biometric.BiometricManager
import androidx.core.content.ContextCompat
import androidx.biometric.BiometricPrompt
import androidx.fragment.app.FragmentActivity
import kotlinx.coroutines.CompletableDeferred
class AppLockHelper {
enum class SupportType {
AVAILABLE,
UNAVAILABLE,
NONE_ENROLLED,
}
companion object {
fun isSupported(context: Context): SupportType {
val biometricManager = BiometricManager.from(context)
when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
BiometricManager.BIOMETRIC_SUCCESS -> return SupportType.AVAILABLE
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> return SupportType.NONE_ENROLLED
else -> return SupportType.UNAVAILABLE
}
}
fun authenticate(
context: Context,
title: String,
subtitle: String
): CompletableDeferred<Unit> {
val deferred = CompletableDeferred<Unit>()
val mainExecutor = ContextCompat.getMainExecutor(context)
val biometricPrompt = BiometricPrompt(
context as FragmentActivity,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
deferred.completeExceptionally(Exception(errString.toString()))
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
deferred.complete(Unit)
}
override fun onAuthenticationFailed() {
deferred.completeExceptionally(Exception("Authentication failed"))
}
}
)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(title)
.setSubtitle(subtitle)
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
.build()
biometricPrompt.authenticate(promptInfo)
return deferred
}
}
}

View File

@ -45,6 +45,7 @@ import app.myzel394.alibi.ui.screens.CustomRecordingNotificationsScreen
import app.myzel394.alibi.ui.screens.SettingsScreen
import app.myzel394.alibi.ui.screens.WelcomeScreen
import app.myzel394.alibi.ui.utils.CameraInfo
import app.myzel394.alibi.helpers.AppLockHelper
const val SCALE_IN = 1.25f
@ -73,34 +74,7 @@ fun Navigation(
LaunchedEffect(Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val executor = ContextCompat.getMainExecutor(context)
val promptInfo = BiometricPrompt.Builder(context)
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setAllowedAuthenticators(
BIOMETRIC_STRONG or DEVICE_CREDENTIAL
)
.build()
// Prompt appears when user clicks "Log in".
// Consider integrating with the keystore to unlock cryptographic operations,
// if needed by your app.
promptInfo.authenticate(
CancellationSignal(),
executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
}
})
AppLockHelper.authenticate(context, "Title", "Subtitle")
}
}