aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-03 18:43:34 +0100
committerDanilo M. <danix@danix.xyz>2026-11-03 18:43:34 +0100
commitbf58bcfd32160f55b5fb28cde15a93691e624da5 (patch)
tree4075585c114e1fc3e3bb1008675fa6e9761474f9 /docs
parentd6b0c910e065fd51481eea1ab5819d7c8f57438e (diff)
downloadHardenedPass-bf58bcfd32160f55b5fb28cde15a93691e624da5.tar.gz
HardenedPass-bf58bcfd32160f55b5fb28cde15a93691e624da5.zip
fix(app): end the screen lock prompt on sensor errors
BiometricAuthenticator mapped onAuthenticationError(ERROR_UNABLE_TO_PROCESS) to Retry, but an error callback always closes the prompt. The settings screen keeps its one-prompt-at-a-time guard set on Retry, so the gated switches stayed locked until the section was left. The error now maps to Failure; Retry comes only from onAuthenticationFailed, while the prompt is still open. Once the device screen lock is removed, the biometric app lock could not be turned off: the prompt returns HardwareUnavailableOrDisabled and nothing was written. Turning it off without a usable screen lock now writes the value directly, as the passphrase cache row already does. The settings category rows and PreferenceAction rows get Role.Button for accessibility services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/plans/2026-11-03-compose-settings.md28
1 files changed, 18 insertions, 10 deletions
diff --git a/docs/superpowers/plans/2026-11-03-compose-settings.md b/docs/superpowers/plans/2026-11-03-compose-settings.md
index 4f4d3da9..e481b0be 100644
--- a/docs/superpowers/plans/2026-11-03-compose-settings.md
+++ b/docs/superpowers/plans/2026-11-03-compose-settings.md
@@ -728,7 +728,8 @@ fun PreferenceAction(
) {
ListItem(
headlineContent = { Text(title) },
- modifier = modifier.clickable(enabled = enabled, onClick = onClick).dimmed(enabled),
+ modifier =
+ modifier.clickable(enabled = enabled, role = Role.Button, onClick = onClick).dimmed(enabled),
supportingContent =
if (summary != null) {
{ Text(summary) }
@@ -1218,6 +1219,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.input.KeyboardType
import app.passwordstore.BuildConfig
import app.passwordstore.R
@@ -1291,7 +1293,7 @@ fun SettingsScreen(
SettingsSection.entries.forEach { section ->
ListItem(
headlineContent = { Text(stringResource(section.title)) },
- modifier = Modifier.clickable { onSection(section) },
+ modifier = Modifier.clickable(role = Role.Button) { onSection(section) },
leadingContent = { Icon(painterResource(section.icon), contentDescription = null) },
colors = rowColors(),
)
@@ -1674,7 +1676,8 @@ fun SettingsSectionDestination(
if (prompting) return
prompting = true
BiometricAuthenticator.authenticate(activity, title) { result ->
- // Retry: a finger was not recognized, the prompt stays open.
+ // Retry: a finger was not recognized, the prompt stays open. Errors close it and are
+ // terminal (Failure, Canceled*, HardwareUnavailableOrDisabled).
if (result !is Result.Retry) prompting = false
onResult(result)
}
@@ -1690,14 +1693,19 @@ fun SettingsSectionDestination(
activity.autofillManager?.disableAutofillServices()
refresh()
}
- PreferenceKeys.BIOMETRIC_AUTH_2 ->
- authenticate(R.string.biometric_prompt_title) { result ->
- if (result is Result.Success) {
- viewModel.putBoolean(key, value)
- // Shortcuts were built for the old lock setting, as the old screen knew.
- activity.getSystemService<ShortcutManager>()?.removeAllDynamicShortcuts()
- }
+ PreferenceKeys.BIOMETRIC_AUTH_2 -> {
+ fun write() {
+ viewModel.putBoolean(key, value)
+ // Shortcuts were built for the old lock setting, as the old screen knew.
+ activity.getSystemService<ShortcutManager>()?.removeAllDynamicShortcuts()
}
+ // Without a screen lock no prompt can open: turning the app lock off needs none.
+ if (!value && !BiometricAuthenticator.canAuthenticate(activity)) write()
+ else
+ authenticate(R.string.biometric_prompt_title) { result ->
+ if (result is Result.Success) write()
+ }
+ }
Feature.EnablePGPPassphraseCache.configKey ->
if (!BiometricAuthenticator.canAuthenticate(activity)) viewModel.setPassphraseCache(false)
else