From 075f54b286511b85636fa70db42c495d5a54d849 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 30 Sep 2025 15:19:05 +0200 Subject: [PATCH] feat: passkey selection after close database setting #2187 --- CHANGELOG | 2 +- .../activities/legacy/DatabaseModeActivity.kt | 2 +- .../credentialprovider/EntrySelectionHelper.kt | 16 +++------------- .../activity/AutofillLauncherActivity.kt | 3 +-- .../activity/PasskeyLauncherActivity.kt | 1 - .../viewmodel/AutofillLauncherViewModel.kt | 11 +++++++++-- .../viewmodel/CredentialLauncherViewModel.kt | 9 ++++----- .../viewmodel/PasskeyLauncherViewModel.kt | 6 ++++-- .../keepass/settings/PreferencesUtil.kt | 10 ++++++++++ app/src/main/res/values/donottranslate.xml | 4 +++- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences_passkeys.xml | 8 ++++++++ .../metadata/android/en-US/changelogs/143.txt | 1 + .../metadata/android/fr-FR/changelogs/143.txt | 1 + 14 files changed, 48 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 726d2c312..e47f809a7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ KeePassDX(4.2.0) * Dialog to manage missing signature #2152 #2155 #2161 #2160 * Capture error #2159 * Change Passkey Backup Eligibility & Backup State #2135 #2150 - * Search settings #2112 #2181 + * Search settings #2112 #2181 #2187 * Autofill refactoring #765 * Small fixes #2157 #2164 #2171 diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseModeActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseModeActivity.kt index 0faaf8868..f3643c526 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseModeActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseModeActivity.kt @@ -34,7 +34,7 @@ abstract class DatabaseModeActivity : DatabaseActivity() { private var mToolbarSpecial: ToolbarSpecial? = null protected open var mCredentialActivityResultLauncher: ActivityResultLauncher? = - this.buildActivityResultLauncher(mTypeMode) + this.buildActivityResultLauncher() open fun onDatabaseBackPressed() { if (mSpecialMode != SpecialMode.DEFAULT) diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/EntrySelectionHelper.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/EntrySelectionHelper.kt index 97abc4b18..384d5a8b2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/EntrySelectionHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/EntrySelectionHelper.kt @@ -38,7 +38,6 @@ import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.SearchInfo -import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.utils.LOCK_ACTION import com.kunzisoft.keepass.utils.getEnumExtra import com.kunzisoft.keepass.utils.getParcelableExtraCompat @@ -60,10 +59,9 @@ object EntrySelectionHelper { * Finish the activity by passing the result code and by locking the database if necessary */ fun Activity.setActivityResult( - typeMode: TypeMode, lockDatabase: Boolean = false, resultCode: Int, - data: Intent? = null, + data: Intent? = null ) { when (resultCode) { Activity.RESULT_OK -> @@ -74,14 +72,8 @@ object EntrySelectionHelper { this.finish() if (lockDatabase) { - when (typeMode) { - TypeMode.DEFAULT -> // Close the database - this.sendBroadcast(Intent(LOCK_ACTION)) - TypeMode.MAGIKEYBOARD -> { } - TypeMode.PASSKEY -> { } - TypeMode.AUTOFILL -> if (PreferencesUtil.isAutofillCloseDatabaseEnable(this)) - this.sendBroadcast(Intent(LOCK_ACTION)) - } + // Close the database + this.sendBroadcast(Intent(LOCK_ACTION)) } } @@ -90,7 +82,6 @@ object EntrySelectionHelper { * Used recursively, close each activity with return data */ fun AppCompatActivity.buildActivityResultLauncher( - typeMode: TypeMode, lockDatabase: Boolean = false, dataTransformation: (data: Intent?) -> Intent? = { it }, ): ActivityResultLauncher { @@ -98,7 +89,6 @@ object EntrySelectionHelper { ActivityResultContracts.StartActivityForResult() ) { setActivityResult( - typeMode, lockDatabase, it.resultCode, dataTransformation(it.data) diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt index 85849b53c..ec8304161 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt @@ -40,7 +40,6 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addSearchIn import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addSpecialMode import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.setActivityResult import com.kunzisoft.keepass.credentialprovider.SpecialMode -import com.kunzisoft.keepass.credentialprovider.TypeMode import com.kunzisoft.keepass.credentialprovider.autofill.AutofillComponent import com.kunzisoft.keepass.credentialprovider.autofill.AutofillHelper.addAutofillComponent import com.kunzisoft.keepass.credentialprovider.viewmodel.AutofillLauncherViewModel @@ -78,6 +77,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + autofillLauncherViewModel.initialize() lifecycleScope.launch { // Initialize the parameters autofillLauncherViewModel.uiState.collect { uiState -> @@ -138,7 +138,6 @@ class AutofillLauncherActivity : DatabaseModeActivity() { } is CredentialLauncherViewModel.UIState.SetActivityResult -> { setActivityResult( - typeMode = TypeMode.AUTOFILL, lockDatabase = uiState.lockDatabase, resultCode = uiState.resultCode, data = uiState.data diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt index 47eda6671..d77d5de0e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt @@ -119,7 +119,6 @@ class PasskeyLauncherActivity : DatabaseLockActivity() { is CredentialLauncherViewModel.UIState.Loading -> {} is CredentialLauncherViewModel.UIState.SetActivityResult -> { setActivityResult( - typeMode = TypeMode.PASSKEY, lockDatabase = uiState.lockDatabase, resultCode = uiState.resultCode, data = uiState.data diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/AutofillLauncherViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/AutofillLauncherViewModel.kt index 1e43514e5..e611e1ac1 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/AutofillLauncherViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/AutofillLauncherViewModel.kt @@ -25,6 +25,7 @@ import com.kunzisoft.keepass.database.element.node.NodeIdUUID import com.kunzisoft.keepass.database.helper.SearchHelper import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.SearchInfo +import com.kunzisoft.keepass.settings.PreferencesUtil import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -39,9 +40,15 @@ class AutofillLauncherViewModel(application: Application): CredentialLauncherVie private var mAutofillComponent: AutofillComponent? = null private var mSelectionResult: ActivityResult? = null + private var mLockDatabaseAfterSelection: Boolean = false + private val mUiState = MutableStateFlow(UIState.Loading) val uiState: StateFlow = mUiState + fun initialize() { + mLockDatabaseAfterSelection = PreferencesUtil.isAutofillCloseDatabaseEnable(getApplication()) + } + override fun onResult() { super.onResult() mAutofillComponent = null @@ -117,7 +124,7 @@ class AutofillLauncherViewModel(application: Application): CredentialLauncherVie database = openedDatabase, entriesInfo = items ) { intent -> - setResult(intent) + setResult(intent, lockDatabase = mLockDatabaseAfterSelection) } }, onItemNotFound = { openedDatabase -> @@ -193,7 +200,7 @@ class AutofillLauncherViewModel(application: Application): CredentialLauncherVie database = database, entriesInfo = entries ) { intent -> - setResult(intent) + setResult(intent, lockDatabase = mLockDatabaseAfterSelection) } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/CredentialLauncherViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/CredentialLauncherViewModel.kt index 31b7b59b4..91d0a2146 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/CredentialLauncherViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/CredentialLauncherViewModel.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.launch abstract class CredentialLauncherViewModel(application: Application): AndroidViewModel(application) { protected var mDatabase: ContextualDatabase? = null - protected var mLockDatabase: Boolean = true protected var isResultLauncherRegistered: Boolean = false @@ -37,20 +36,20 @@ abstract class CredentialLauncherViewModel(application: Application): AndroidVie isResultLauncherRegistered = false } - fun setResult(intent: Intent) { + fun setResult(intent: Intent, lockDatabase: Boolean = false) { // Remove the launcher register onResult() mCredentialUiState.value = UIState.SetActivityResult( - lockDatabase = mLockDatabase, + lockDatabase = lockDatabase, resultCode = RESULT_OK, data = intent ) } - fun cancelResult() { + fun cancelResult(lockDatabase: Boolean = false) { onResult() mCredentialUiState.value = UIState.SetActivityResult( - lockDatabase = mLockDatabase, + lockDatabase = lockDatabase, resultCode = RESULT_CANCELED ) } diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt index f1e8b0942..ba3e0bf61 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt @@ -61,6 +61,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView private var mCreationParameters: PublicKeyCredentialCreationParameters? = null private var mPasskey: Passkey? = null + private var mLockDatabaseAfterSelection: Boolean = false private var mBackupEligibility: Boolean = true private var mBackupState: Boolean = false @@ -68,6 +69,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView val uiState: StateFlow = mUiState fun initialize() { + mLockDatabaseAfterSelection = PreferencesUtil.isPasskeyCloseDatabaseEnable(getApplication()) mBackupEligibility = PreferencesUtil.isPasskeyBackupEligibilityEnable(getApplication()) mBackupState = PreferencesUtil.isPasskeyBackupStateEnable(getApplication()) } @@ -294,7 +296,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView ) ) ) - setResult(result) + setResult(result, lockDatabase = mLockDatabaseAfterSelection) } catch (e: SignatureNotFoundException) { // Request the dialog if signature exception showAppSignatureDialog(e.temptingApp, nodeId) @@ -350,7 +352,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView throw IOException("Usage parameters is null") } withContext(Dispatchers.Main) { - setResult(responseIntent) + setResult(responseIntent, lockDatabase = mLockDatabaseAfterSelection) } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt index e817718ce..5604a4a6c 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt @@ -690,6 +690,12 @@ object PreferencesUtil { context.resources.getBoolean(R.bool.keyboard_previous_lock_default)) } + fun isPasskeyCloseDatabaseEnable(context: Context): Boolean { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + return prefs.getBoolean(context.getString(R.string.passkeys_close_database_key), + context.resources.getBoolean(R.bool.passkeys_close_database_default)) + } + fun isPasskeyBackupEligibilityEnable(context: Context): Boolean { val prefs = PreferenceManager.getDefaultSharedPreferences(context) return prefs.getBoolean(context.getString(R.string.passkeys_backup_eligibility_key), @@ -858,6 +864,10 @@ object PreferencesUtil { context.getString(R.string.keyboard_previous_search_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.keyboard_previous_fill_in_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.keyboard_previous_lock_key) -> editor.putBoolean(name, value.toBoolean()) + context.getString(R.string.passkeys_close_database_key) -> editor.putBoolean(name, value.toBoolean()) + context.getString(R.string.passkeys_auto_select_key) -> editor.putBoolean(name, value.toBoolean()) + context.getString(R.string.passkeys_backup_eligibility_key) -> editor.putBoolean(name, value.toBoolean()) + context.getString(R.string.passkeys_backup_state_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_close_database_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_inline_suggestions_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_manual_selection_key) -> editor.putBoolean(name, value.toBoolean()) diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index dd0b7553b..ce1d86c36 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -134,9 +134,11 @@ settings_autofill_key passkeys_explanation_key settings_passkeys_key + passkeys_close_database_key + true passkeys_privileged_apps_key passkeys_auto_select_key - false + true passkeys_backup_eligibility_key true passkeys_backup_state_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bcb360531..31471e994 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -422,6 +422,8 @@ Passkeys Configure Passkeys for fast and secure passwordless login Passkeys settings + Close database + Close the database after a passkey selection Privileged apps Manage browsers in the custom list of privileged apps WARNING: A privileged app acts as a gateway to retrieve the origin of an authentication. Ensure its legitimacy to avoid security issues. diff --git a/app/src/main/res/xml/preferences_passkeys.xml b/app/src/main/res/xml/preferences_passkeys.xml index 2bf319d8d..de459cf24 100644 --- a/app/src/main/res/xml/preferences_passkeys.xml +++ b/app/src/main/res/xml/preferences_passkeys.xml @@ -20,6 +20,11 @@ + + +