From fdfbe339d831121274174a2f52f27cc3e3997380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A9sir=C3=A9=20Werner=20Menrath?= Date: Tue, 4 Nov 2025 10:55:09 +0100 Subject: [PATCH] Fix: Behebt den Absturz beim BiometricPrompt durch Entfernen des negativen Button-Textes. --- .../java/de/lxtools/noteshop/MainActivity.kt | 9 +- .../java/de/lxtools/noteshop/ui/AppShell.kt | 111 +++++------------- .../noteshop/ui/ChooseLockMethodDialog.kt | 16 +-- .../noteshop/ui/EncryptionPasswordDialog.kt | 1 - .../noteshop/ui/JsonImportExportDialog.kt | 1 - .../lxtools/noteshop/ui/SetPatternDialogs.kt | 72 ------------ .../de/lxtools/noteshop/ui/SettingsScreen.kt | 1 - .../noteshop/ui/appshell/AppDialogs.kt | 40 +------ app/src/main/res/values/strings.xml | 3 +- 9 files changed, 36 insertions(+), 218 deletions(-) delete mode 100644 app/src/main/java/de/lxtools/noteshop/ui/SetPatternDialogs.kt diff --git a/app/src/main/java/de/lxtools/noteshop/MainActivity.kt b/app/src/main/java/de/lxtools/noteshop/MainActivity.kt index c495a68..4a7baea 100644 --- a/app/src/main/java/de/lxtools/noteshop/MainActivity.kt +++ b/app/src/main/java/de/lxtools/noteshop/MainActivity.kt @@ -134,7 +134,6 @@ class BiometricAuthenticator(private val context: Context) { fun promptBiometricAuth( title: String, subtitle: String, - negativeButtonText: String, fragmentActivity: FragmentActivity, onSuccess: (BiometricPrompt.AuthenticationResult) -> Unit, onFailed: () -> Unit, @@ -143,8 +142,7 @@ class BiometricAuthenticator(private val context: Context) { promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle(title) .setSubtitle(subtitle) - .setNegativeButtonText(negativeButtonText) - .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG) + .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL) .build() val executor = ContextCompat.getMainExecutor(context) @@ -171,7 +169,6 @@ class BiometricAuthenticator(private val context: Context) { fun promptBiometricAuth( title: String, subtitle: String, - negativeButtonText: String, fragmentActivity: FragmentActivity, crypto: BiometricPrompt.CryptoObject, onSuccess: (BiometricPrompt.AuthenticationResult) -> Unit, @@ -181,8 +178,7 @@ class BiometricAuthenticator(private val context: Context) { promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle(title) .setSubtitle(subtitle) - .setNegativeButtonText(negativeButtonText) - .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG) + .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL) .build() val executor = ContextCompat.getMainExecutor(context) @@ -275,7 +271,6 @@ class MainActivity : FragmentActivity() { biometricAuthenticator.promptBiometricAuth( title = getString(R.string.unlock_app), subtitle = getString(R.string.confirm_to_unlock), - negativeButtonText = getString(R.string.cancel), fragmentActivity = this, onSuccess = { _ -> isUnlocked = true }, onFailed = { diff --git a/app/src/main/java/de/lxtools/noteshop/ui/AppShell.kt b/app/src/main/java/de/lxtools/noteshop/ui/AppShell.kt index 07c787e..02ab05f 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/AppShell.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/AppShell.kt @@ -155,7 +155,6 @@ fun AppShell( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.remove_encryption), subtitle = context.getString(R.string.confirm_to_disable_encryption), - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = activity, crypto = crypto, onSuccess = { result -> @@ -217,7 +216,6 @@ fun AppShell( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.remove_encryption), subtitle = context.getString(R.string.confirm_to_remove_encryption), - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = activity, crypto = crypto, onSuccess = { result -> @@ -531,7 +529,6 @@ fun AppShell( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.unlock_app), subtitle = context.getString(R.string.confirm_to_unlock), - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = activity, crypto = crypto, onSuccess = { result -> @@ -642,12 +639,9 @@ fun AppShell( var showSetPasswordDialog by rememberSaveable { mutableStateOf(false) } var showSetRecipePasswordDialog by rememberSaveable { mutableStateOf(false) } var showSetListPasswordDialog by rememberSaveable { mutableStateOf(false) } - var showSetPatternDialog by rememberSaveable { mutableStateOf(false) } - var showUnlockPatternDialog by rememberSaveable { mutableStateOf(false) } - var unlockPatternErrorMessage by remember { mutableStateOf(null) } - + + var showUnlockPasswordDialog by rememberSaveable { mutableStateOf(false) } - var showUnlockPinDialog by rememberSaveable { mutableStateOf(false) } var unlockErrorMessage by rememberSaveable { mutableStateOf(null) } var itemToUnlockId by rememberSaveable { mutableStateOf(null) } var itemToUnlockType by rememberSaveable { mutableStateOf(null) } @@ -658,50 +652,34 @@ fun AppShell( val onUnlockItem: (Int, Screen, Int) -> Unit = { id, type, protectionType -> - if (protectionType == 1) { // Password protected - itemToUnlockId = id - itemToUnlockType = type - showUnlockPasswordDialog = true - } else if (protectionType == 2) { // Biometric protected - if (canUseBiometrics) { - biometricAuthenticator.promptBiometricAuth( - title = context.getString(R.string.unlock_item), - subtitle = "", - negativeButtonText = context.getString(R.string.cancel), - fragmentActivity = context.findActivity() as FragmentActivity, - onSuccess = { - when (type) { - is Screen.ShoppingListDetail -> selectedListId = id - is Screen.NoteDetail -> selectedNoteId = id - is Screen.RecipeDetail -> selectedRecipeId = id - else -> {} - } - itemWasInitiallyLocked = true - currentScreen = type - }, - onFailed = { - // Biometric failed, offer password as fallback if desired - itemToUnlockId = id - itemToUnlockType = type - showUnlockPasswordDialog = true - }, - onError = { _, _ -> - // Biometric error, offer password as fallback if desired - itemToUnlockId = id - itemToUnlockType = type - showUnlockPasswordDialog = true + if (protectionType == 1 || protectionType == 2) { // Password or Biometric protected + biometricAuthenticator.promptBiometricAuth( + title = context.getString(R.string.unlock_item), + subtitle = "", + fragmentActivity = context.findActivity() as FragmentActivity, + onSuccess = { + when (type) { + is Screen.ShoppingListDetail -> selectedListId = id + is Screen.NoteDetail -> selectedNoteId = id + is Screen.RecipeDetail -> selectedRecipeId = id + else -> {} } - ) - } else { - // Biometrics not available, offer password as fallback - itemToUnlockId = id - itemToUnlockType = type - showUnlockPasswordDialog = true - } - } else if (protectionType == 3) { // Pattern protected - itemToUnlockId = id - itemToUnlockType = type - showUnlockPatternDialog = true + itemWasInitiallyLocked = true + currentScreen = type + }, + onFailed = { + // Biometric failed, offer password as fallback if desired + itemToUnlockId = id + itemToUnlockType = type + showUnlockPasswordDialog = true + }, + onError = { _, _ -> + // Biometric error, offer password as fallback if desired + itemToUnlockId = id + itemToUnlockType = type + showUnlockPasswordDialog = true + } + ) } } @@ -915,7 +893,6 @@ fun AppShell( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.authenticate_to_perform_action), subtitle = "", - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = activity, onSuccess = { _ -> if (isPassword) { @@ -1185,15 +1162,6 @@ fun AppShell( itemToUnlockType = null } }, - showUnlockPatternDialog = showUnlockPatternDialog, - onShowUnlockPatternDialogChange = { - showUnlockPatternDialog = it - if (!it) { - unlockPatternErrorMessage = null - itemToUnlockId = null - itemToUnlockType = null - } - }, onUnlock = { password -> val hashedPassword = PasswordHasher.hashPassword(password) var isPasswordCorrect = false @@ -1230,7 +1198,6 @@ fun AppShell( itemToUnlockId = null itemToUnlockType = null showUnlockPasswordDialog = false - showUnlockPatternDialog = false } else { unlockErrorMessage = context.getString(R.string.incorrect_password) } @@ -1280,11 +1247,6 @@ fun AppShell( LockMethod.BIOMETRIC -> { shoppingListsViewModel.setProtectionBiometric(id) } - LockMethod.PATTERN -> { - selectedListId = id - showSetPatternDialog = true - } - } } LockableItemType.NOTE -> { @@ -1296,11 +1258,6 @@ fun AppShell( LockMethod.BIOMETRIC -> { notesViewModel.setProtectionBiometric(id) } - LockMethod.PATTERN -> { - selectedNoteId = id - showSetPatternDialog = true - } - } } LockableItemType.RECIPE -> { @@ -1312,11 +1269,6 @@ fun AppShell( LockMethod.BIOMETRIC -> { recipesViewModel.setProtectionBiometric(id) } - LockMethod.PATTERN -> { - selectedRecipeId = id - showSetPatternDialog = true - } - } } } @@ -1328,8 +1280,5 @@ fun AppShell( }, canUseBiometrics = canUseBiometrics, itemToLockType = itemToLockType, - showSetPatternDialog = showSetPatternDialog, - onShowSetPatternDialogChange = { showSetPatternDialog = it }, - - ) + ) } \ No newline at end of file diff --git a/app/src/main/java/de/lxtools/noteshop/ui/ChooseLockMethodDialog.kt b/app/src/main/java/de/lxtools/noteshop/ui/ChooseLockMethodDialog.kt index 6fc277b..9fb52ff 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/ChooseLockMethodDialog.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/ChooseLockMethodDialog.kt @@ -22,7 +22,7 @@ import de.lxtools.noteshop.R enum class LockMethod { BIOMETRIC, - PATTERN, + PASSWORD } @@ -53,19 +53,7 @@ fun ChooseLockMethodDialog( ) Text(text = stringResource(R.string.biometric_lock), modifier = Modifier.padding(start = 8.dp)) } - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { selectedMethod = LockMethod.PATTERN } - .padding(vertical = 8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - RadioButton( - selected = selectedMethod == LockMethod.PATTERN, - onClick = { selectedMethod = LockMethod.PATTERN } - ) - Text(text = stringResource(R.string.pattern), modifier = Modifier.padding(start = 8.dp)) - } + Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/de/lxtools/noteshop/ui/EncryptionPasswordDialog.kt b/app/src/main/java/de/lxtools/noteshop/ui/EncryptionPasswordDialog.kt index e4f8e2c..f389455 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/EncryptionPasswordDialog.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/EncryptionPasswordDialog.kt @@ -115,7 +115,6 @@ fun EncryptionPasswordDialog( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.set_encryption_password), subtitle = "", - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = context as FragmentActivity, crypto = cryptoObject, onSuccess = { result -> diff --git a/app/src/main/java/de/lxtools/noteshop/ui/JsonImportExportDialog.kt b/app/src/main/java/de/lxtools/noteshop/ui/JsonImportExportDialog.kt index 9961bc7..1da7e3e 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/JsonImportExportDialog.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/JsonImportExportDialog.kt @@ -61,7 +61,6 @@ fun JsonImportExportDialog( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.authenticate_for_import_export), subtitle = "", - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = activity, crypto = crypto, onSuccess = { result -> diff --git a/app/src/main/java/de/lxtools/noteshop/ui/SetPatternDialogs.kt b/app/src/main/java/de/lxtools/noteshop/ui/SetPatternDialogs.kt deleted file mode 100644 index 00707aa..0000000 --- a/app/src/main/java/de/lxtools/noteshop/ui/SetPatternDialogs.kt +++ /dev/null @@ -1,72 +0,0 @@ -package de.lxtools.noteshop.ui - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType -import de.lxtools.noteshop.R - -@Composable -fun SetPatternDialog(onDismiss: () -> Unit, onSetPattern: (String) -> Unit) { - var pattern by remember { mutableStateOf(emptyList()) } - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(text = "Set Pattern") }, - text = { - PatternInput(onPatternComplete = { - pattern = it - onSetPattern(it.joinToString("")) - }) - }, - confirmButton = { - TextButton(onClick = { onSetPattern(pattern.joinToString("")) }) { - Text(text = "OK") - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = "Cancel") - } - } - ) -} - -@Composable -fun UnlockPatternDialog(onDismiss: () -> Unit, onUnlock: (String) -> Unit, errorMessage: String?) { - var pattern by remember { mutableStateOf(emptyList()) } - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(text = stringResource(R.string.unlock_item)) }, - text = { - Column { - PatternInput(onPatternComplete = { - pattern = it - onUnlock(it.joinToString("")) - }) - if (errorMessage != null) { - Text(text = errorMessage, color = MaterialTheme.colorScheme.error) - } - } - }, - confirmButton = { - TextButton(onClick = { onUnlock(pattern.joinToString("")) }) { - Text(text = stringResource(R.string.unlock)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(R.string.cancel)) - } - } - ) -} diff --git a/app/src/main/java/de/lxtools/noteshop/ui/SettingsScreen.kt b/app/src/main/java/de/lxtools/noteshop/ui/SettingsScreen.kt index c7b2def..599d135 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/SettingsScreen.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/SettingsScreen.kt @@ -96,7 +96,6 @@ fun SettingsScreen( biometricAuthenticator.promptBiometricAuth( title = context.getString(R.string.confirm_to_proceed), subtitle = context.getString(R.string.authenticate_to_perform_action), - negativeButtonText = context.getString(R.string.cancel), fragmentActivity = context as FragmentActivity, onSuccess = { successAction() }, onFailed = { diff --git a/app/src/main/java/de/lxtools/noteshop/ui/appshell/AppDialogs.kt b/app/src/main/java/de/lxtools/noteshop/ui/appshell/AppDialogs.kt index 8d1d687..0921e36 100644 --- a/app/src/main/java/de/lxtools/noteshop/ui/appshell/AppDialogs.kt +++ b/app/src/main/java/de/lxtools/noteshop/ui/appshell/AppDialogs.kt @@ -79,12 +79,8 @@ fun AppDialogs( onShowSetListPasswordDialogChange: (Boolean) -> Unit, showUnlockPasswordDialog: Boolean, onShowUnlockPasswordDialogChange: (Boolean) -> Unit, - showUnlockPatternDialog: Boolean, - onShowUnlockPatternDialogChange: (Boolean) -> Unit, onUnlock: (String) -> Unit, unlockErrorMessage: String?, - - showPasswordDialog: Boolean, onShowPasswordDialogChange: (Boolean) -> Unit, onHasEncryptionPasswordChange: (Boolean) -> Unit, @@ -103,9 +99,6 @@ fun AppDialogs( onConfirmLockMethod: (LockMethod) -> Unit, canUseBiometrics: Boolean, itemToLockType: de.lxtools.noteshop.ui.LockableItemType?, - showSetPatternDialog: Boolean, - onShowSetPatternDialogChange: (Boolean) -> Unit, - ) { val scope = rememberCoroutineScope() val dynamicRecipeStrings = getDynamicRecipeStrings(recipesTitle) @@ -212,27 +205,6 @@ fun AppDialogs( ) } - if (showSetPatternDialog) { - de.lxtools.noteshop.ui.SetPatternDialog( - onDismiss = { onShowSetPatternDialogChange(false) }, - onSetPattern = { pattern -> - when (itemToLockType) { - LockableItemType.NOTE -> notesViewModel.setProtectionPattern(pattern) - LockableItemType.RECIPE -> recipesViewModel.setProtectionPattern(pattern) - LockableItemType.SHOPPING_LIST -> shoppingListsViewModel.setProtectionPattern(pattern) - else -> {} - } - onShowSetPatternDialogChange(false) - } - ) - } - - - - - - - if (showPasswordDialog) { EncryptionPasswordDialog( onDismiss = { onShowPasswordDialogChange(false) }, @@ -299,16 +271,6 @@ fun AppDialogs( ) } - if (showUnlockPatternDialog) { - de.lxtools.noteshop.ui.UnlockPatternDialog( - onDismiss = { - onShowUnlockPatternDialogChange(false) - }, - onUnlock = onUnlock, - errorMessage = unlockErrorMessage - ) - } - if (showChooseLockMethodDialog) { ChooseLockMethodDialog( onDismiss = { onShowChooseLockMethodDialogChange(false) }, @@ -318,4 +280,4 @@ fun AppDialogs( canUseBiometrics = canUseBiometrics ) } -} +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1acdb6a..745dc53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -238,8 +238,7 @@ Unlock Item Enter password to unlock this item. Incorrect password. - Incorrect pattern. - + Data Encryption Set Encryption Password Change Encryption Password