mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Improve backup key password manager save error handling.
- Add "go to settings" button to missing credential manager error dialog. - Add handling for disabled password manager save prompt on Android API <= 33.
This commit is contained in:
committed by
Greyson Parrelli
parent
0a17cd1c99
commit
fdf1238905
@@ -33,6 +33,7 @@ import org.signal.core.util.getSerializableCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.backup.DeletionState
|
||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeyCredentialManagerHandler
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentCheckoutDelegate
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.compose.Nav
|
||||
@@ -150,7 +151,11 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
|
||||
},
|
||||
onRequestSaveToPasswordManager = viewModel::onBackupKeySaveRequested,
|
||||
onConfirmSaveToPasswordManager = viewModel::onBackupKeySaveConfirmed,
|
||||
onSaveToPasswordManagerComplete = viewModel::onBackupKeySaveCompleted
|
||||
onSaveToPasswordManagerComplete = viewModel::onBackupKeySaveCompleted,
|
||||
onGoToDeviceSettingsClick = {
|
||||
val intent = BackupKeyCredentialManagerHandler.getCredentialManagerSettingsIntent(requireContext())
|
||||
requireContext().startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.signal.core.ui.compose.Snackbars
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeyCredentialManagerHandler
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeySaveState
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.CredentialManagerError
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.CredentialManagerResult
|
||||
@@ -72,7 +73,8 @@ fun MessageBackupsKeyRecordScreen(
|
||||
onRequestSaveToPasswordManager: () -> Unit = {},
|
||||
onConfirmSaveToPasswordManager: () -> Unit = {},
|
||||
onSaveToPasswordManagerComplete: (CredentialManagerResult) -> Unit = {},
|
||||
onNextClick: () -> Unit = {}
|
||||
onNextClick: () -> Unit = {},
|
||||
onGoToDeviceSettingsClick: () -> Unit = {}
|
||||
) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val backupKeyString = remember(backupKey) {
|
||||
@@ -163,7 +165,7 @@ fun MessageBackupsKeyRecordScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (BackupKeyCredentialManagerHandler.isCredentialManagerSupported) {
|
||||
item {
|
||||
Buttons.Small(
|
||||
onClick = { onRequestSaveToPasswordManager() }
|
||||
@@ -220,13 +222,30 @@ fun MessageBackupsKeyRecordScreen(
|
||||
}
|
||||
|
||||
is BackupKeySaveState.Error -> {
|
||||
if (keySaveState.errorType is CredentialManagerError.MissingCredentialManager) {
|
||||
Dialogs.SimpleMessageDialog(
|
||||
title = stringResource(R.string.MessageBackupsKeyRecordScreen__missing_password_manager_title),
|
||||
message = stringResource(R.string.MessageBackupsKeyRecordScreen__missing_password_manager_message),
|
||||
dismiss = stringResource(android.R.string.ok),
|
||||
onDismiss = { onSaveToPasswordManagerComplete(CredentialManagerResult.UserCanceled) }
|
||||
)
|
||||
when (keySaveState.errorType) {
|
||||
is CredentialManagerError.MissingCredentialManager -> {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(R.string.MessageBackupsKeyRecordScreen__cant_save_to_password_manager_title),
|
||||
body = stringResource(R.string.MessageBackupsKeyRecordScreen__missing_password_manager_message),
|
||||
confirm = stringResource(R.string.MessageBackupsKeyRecordScreen__go_to_settings),
|
||||
onConfirm = { onGoToDeviceSettingsClick() },
|
||||
dismiss = stringResource(android.R.string.cancel),
|
||||
onDismiss = { onSaveToPasswordManagerComplete(CredentialManagerResult.UserCanceled) }
|
||||
)
|
||||
}
|
||||
|
||||
is CredentialManagerError.SavePromptDisabled -> {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(R.string.MessageBackupsKeyRecordScreen__cant_save_to_password_manager_title),
|
||||
body = stringResource(R.string.MessageBackupsKeyRecordScreen__missing_password_manager_message),
|
||||
confirm = stringResource(R.string.MessageBackupsKeyRecordScreen__go_to_settings),
|
||||
onConfirm = { onGoToDeviceSettingsClick() },
|
||||
dismiss = stringResource(android.R.string.cancel),
|
||||
onDismiss = { onSaveToPasswordManagerComplete(CredentialManagerResult.UserCanceled) }
|
||||
)
|
||||
}
|
||||
|
||||
is CredentialManagerError.Unexpected -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,6 +290,11 @@ private suspend fun saveKeyToCredentialManager(
|
||||
CredentialManagerError.MissingCredentialManager(e)
|
||||
}
|
||||
|
||||
e.message?.contains("[28435]") == true -> {
|
||||
Log.w(TAG, "CreateCredentialUnknownException: \"${e.message}\"")
|
||||
CredentialManagerError.SavePromptDisabled(e)
|
||||
}
|
||||
|
||||
else -> CredentialManagerError.Unexpected(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app.backups.remote
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.view.autofill.AutofillManager
|
||||
import androidx.core.content.getSystemService
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.logging.logW
|
||||
|
||||
@@ -14,6 +21,37 @@ import org.signal.core.util.logging.logW
|
||||
interface BackupKeyCredentialManagerHandler {
|
||||
companion object {
|
||||
private val TAG = Log.tag(BackupKeyCredentialManagerHandler::class)
|
||||
|
||||
val isCredentialManagerSupported: Boolean = Build.VERSION.SDK_INT >= 19
|
||||
|
||||
/**
|
||||
* Returns an [Intent] that can be used to launch the device's password manager settings.
|
||||
*/
|
||||
fun getCredentialManagerSettingsIntent(context: Context): Intent? {
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val intent = Intent(
|
||||
Settings.ACTION_CREDENTIAL_PROVIDER,
|
||||
Uri.fromParts("package", context.packageName, null)
|
||||
)
|
||||
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
val isAutofillSupported = context.getSystemService<AutofillManager>()?.isAutofillSupported() == true
|
||||
if (isAutofillSupported) {
|
||||
val intent = Intent(
|
||||
Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE,
|
||||
Uri.fromParts("package", context.packageName, null)
|
||||
)
|
||||
return intent.takeIf { it.resolveActivity(context.packageManager) != null }
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the [BackupKeySaveState]. Implementers must update their associated state to match [newState]. */
|
||||
@@ -48,6 +86,11 @@ interface BackupKeyCredentialManagerHandler {
|
||||
updateBackupKeySaveState(newState = BackupKeySaveState.Error(result))
|
||||
}
|
||||
|
||||
is CredentialManagerError.SavePromptDisabled -> {
|
||||
Log.w(TAG, "Error saving backup key to credential manager: the user has disabled the save prompt.", result.exception)
|
||||
updateBackupKeySaveState(newState = BackupKeySaveState.Error(result))
|
||||
}
|
||||
|
||||
is CredentialManagerError.Unexpected -> {
|
||||
throw result.exception.logW(TAG, "Unexpected error when saving backup key to credential manager.")
|
||||
}
|
||||
@@ -79,5 +122,9 @@ sealed class CredentialManagerError : CredentialManagerResult {
|
||||
|
||||
/** No password manager is configured on the device. */
|
||||
data class MissingCredentialManager(override val exception: Exception) : CredentialManagerError()
|
||||
|
||||
/** The user has added this app to the "never save" list in the smart lock for passwords settings. **/
|
||||
data class SavePromptDisabled(override val exception: Exception) : CredentialManagerError()
|
||||
|
||||
data class Unexpected(override val exception: Exception) : CredentialManagerError()
|
||||
}
|
||||
|
||||
@@ -38,7 +38,11 @@ class BackupKeyDisplayFragment : ComposeFragment() {
|
||||
onRequestSaveToPasswordManager = viewModel::onBackupKeySaveRequested,
|
||||
onConfirmSaveToPasswordManager = viewModel::onBackupKeySaveConfirmed,
|
||||
onSaveToPasswordManagerComplete = viewModel::onBackupKeySaveCompleted,
|
||||
onNextClick = { findNavController().popBackStack() }
|
||||
onNextClick = { findNavController().popBackStack() },
|
||||
onGoToDeviceSettingsClick = {
|
||||
val intent = BackupKeyCredentialManagerHandler.getCredentialManagerSettingsIntent(requireContext())
|
||||
requireContext().startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8360,10 +8360,14 @@
|
||||
<string name="MessageBackupsKeyRecordScreen__confirm_save_to_password_manager_body">Only store your backup key in a password manager that you trust is secure. Signal does not make a recommendation on which password manager is right for you.</string>
|
||||
<!-- Message shown after the backup key is successfully saved to the device password manager. -->
|
||||
<string name="MessageBackupsKeyRecordScreen__save_to_password_manager_success">Saved to your password manager</string>
|
||||
<!-- Dialog title shown when there is an error saving the backup key because no compatible password manager was detected. -->
|
||||
<string name="MessageBackupsKeyRecordScreen__missing_password_manager_title">Can\'t save to password manager</string>
|
||||
<!-- Dialog title shown when there is an error saving the backup key to the device password manager. -->
|
||||
<string name="MessageBackupsKeyRecordScreen__cant_save_to_password_manager_title">Can\'t save to password manager</string>
|
||||
<!-- Dialog message shown when there is an error saving the backup key because no compatible password manager was detected. -->
|
||||
<string name="MessageBackupsKeyRecordScreen__missing_password_manager_message">You don\'t have a password manager set up, or the password manager you\'re using isn\'t supported.</string>
|
||||
<!-- Dialog message shown when there is an error saving the backup key because the user previously chose not to save Signal passwords to their password manager. -->
|
||||
<string name="MessageBackupsKeyRecordScreen__password_save_prompt_disabled_message">You previously chose not to save passwords for Signal to Google Password Manager. In your Google Password Manager settings, remove Signal from \"Declined sites and apps\" and try again.</string>
|
||||
<!-- Label for a button that navigates to the device settings -->
|
||||
<string name="MessageBackupsKeyRecordScreen__go_to_settings">Go to settings</string>
|
||||
<!-- Action button label -->
|
||||
<string name="MessageBackupsKeyRecordScreen__next">Next</string>
|
||||
<!-- Bottom sheet title -->
|
||||
|
||||
Reference in New Issue
Block a user