Let user select entry for autofill

This commit is contained in:
Ulrich Dürholz
2021-08-27 18:23:32 +02:00
parent e3adaba3b3
commit 39b817bc69
10 changed files with 79 additions and 3 deletions

View File

@@ -65,6 +65,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID) applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID)
webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN) webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN)
webScheme = intent.getStringExtra(KEY_SEARCH_SCHEME) webScheme = intent.getStringExtra(KEY_SEARCH_SCHEME)
manualSelection = intent.getBooleanExtra(KEY_MANUAL_SELECTION, false)
} }
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain -> SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain searchInfo.webDomain = concreteWebDomain
@@ -198,6 +199,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
companion object { companion object {
private const val KEY_MANUAL_SELECTION = "KEY_MANUAL_SELECTION"
private const val KEY_SEARCH_APPLICATION_ID = "KEY_SEARCH_APPLICATION_ID" private const val KEY_SEARCH_APPLICATION_ID = "KEY_SEARCH_APPLICATION_ID"
private const val KEY_SEARCH_DOMAIN = "KEY_SEARCH_DOMAIN" private const val KEY_SEARCH_DOMAIN = "KEY_SEARCH_DOMAIN"
private const val KEY_SEARCH_SCHEME = "KEY_SEARCH_SCHEME" private const val KEY_SEARCH_SCHEME = "KEY_SEARCH_SCHEME"
@@ -214,6 +216,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
putExtra(KEY_SEARCH_APPLICATION_ID, it.applicationId) putExtra(KEY_SEARCH_APPLICATION_ID, it.applicationId)
putExtra(KEY_SEARCH_DOMAIN, it.webDomain) putExtra(KEY_SEARCH_DOMAIN, it.webDomain)
putExtra(KEY_SEARCH_SCHEME, it.webScheme) putExtra(KEY_SEARCH_SCHEME, it.webScheme)
putExtra(KEY_MANUAL_SELECTION, it.manualSelection)
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
inlineSuggestionsRequest?.let { inlineSuggestionsRequest?.let {

View File

@@ -42,6 +42,7 @@ import androidx.autofill.inline.UiVersions
import androidx.autofill.inline.v1.InlineSuggestionUi import androidx.autofill.inline.v1.InlineSuggestionUi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.AutofillLauncherActivity
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
@@ -309,6 +310,26 @@ object AutofillHelper {
} }
} }
if (PreferencesUtil.isAutofillManualSelectionEnable(context)) {
val searchInfo = SearchInfo().apply {
applicationId = parseResult.applicationId
webDomain = parseResult.webDomain
webScheme = parseResult.webScheme
manualSelection = true
}
val manualSelectionView = newRemoteViews(context, database, context.getString(R.string.autofill_manual_selection_prompt), null)
val intentSender = AutofillLauncherActivity.getAuthIntentSenderForSelection(context,
searchInfo, null)
val builder = Dataset.Builder(manualSelectionView)
// enable manual selection only for the form field that has focus
parseResult.focusedId?.let { autofillId ->
builder.setValue(autofillId, AutofillValue.forText("dummy"))
builder.setAuthentication(intentSender)
responseBuilder.addDataset(builder.build())
}
}
return try { return try {
responseBuilder.build() responseBuilder.build()
} catch (e: Exception) { } catch (e: Exception) {

View File

@@ -44,6 +44,7 @@ class StructureParser(private val structure: AssistStructure) {
fun parse(saveValue: Boolean = false): Result? { fun parse(saveValue: Boolean = false): Result? {
try { try {
result = Result() result = Result()
result?.focusedId = getFocusedID()
result?.apply { result?.apply {
allowSaveValues = saveValue allowSaveValues = saveValue
usernameIdCandidate = null usernameIdCandidate = null
@@ -74,6 +75,35 @@ class StructureParser(private val structure: AssistStructure) {
} }
} }
/*
* Note: SDK >= Q provides this method...
* fillContext.getFocusedId()
*/
private fun getFocusedID(): AutofillId? {
for (i in 0 until structure.windowNodeCount) {
val windowNode = structure.getWindowNodeAt(i)
val autofillId = traverse(windowNode.rootViewNode)
if (autofillId != null) {
return autofillId
}
}
return null
}
private fun traverse(node: AssistStructure.ViewNode): AutofillId? {
if (node.visibility == View.VISIBLE && node.autofillHints != null) {
return node.autofillId
} else {
for (i in 0 until node.childCount) {
val autoFillId = traverse(node.getChildAt(i))
if (autoFillId != null) {
return autoFillId
}
}
}
return null
}
private fun parseViewNode(node: AssistStructure.ViewNode): Boolean { private fun parseViewNode(node: AssistStructure.ViewNode): Boolean {
// remember this // remember this
if (node.className == "android.webkit.WebView") { if (node.className == "android.webkit.WebView") {
@@ -399,7 +429,6 @@ class StructureParser(private val structure: AssistStructure) {
class Result { class Result {
var isWebView: Boolean = false var isWebView: Boolean = false
var applicationId: String? = null var applicationId: String? = null
var webDomain: String? = null var webDomain: String? = null
set(value) { set(value) {
if (field == null) if (field == null)
@@ -418,6 +447,9 @@ class StructureParser(private val structure: AssistStructure) {
var creditCardExpirationMonthOptions: Array<CharSequence>? = null var creditCardExpirationMonthOptions: Array<CharSequence>? = null
var creditCardExpirationDayOptions: Array<CharSequence>? = null var creditCardExpirationDayOptions: Array<CharSequence>? = null
// the AutofillId of the view that triggered autofill.
var focusedId: AutofillId? = null
var usernameId: AutofillId? = null var usernameId: AutofillId? = null
set(value) { set(value) {
if (field == null) if (field == null)

View File

@@ -106,7 +106,7 @@ class SearchHelper {
} else if (TimeoutHelper.checkTime(context)) { } else if (TimeoutHelper.checkTime(context)) {
var searchWithoutUI = false var searchWithoutUI = false
if (PreferencesUtil.isAutofillAutoSearchEnable(context) if (PreferencesUtil.isAutofillAutoSearchEnable(context)
&& searchInfo != null && searchInfo != null && !searchInfo.manualSelection
&& !searchInfo.containsOnlyNullValues()) { && !searchInfo.containsOnlyNullValues()) {
// If search provide results // If search provide results
database.createVirtualGroupFromSearchInfo( database.createVirtualGroupFromSearchInfo(

View File

@@ -14,7 +14,7 @@ import kotlinx.coroutines.launch
import mozilla.components.lib.publicsuffixlist.PublicSuffixList import mozilla.components.lib.publicsuffixlist.PublicSuffixList
class SearchInfo : ObjectNameResource, Parcelable { class SearchInfo : ObjectNameResource, Parcelable {
var manualSelection: Boolean = false
var applicationId: String? = null var applicationId: String? = null
set(value) { set(value) {
field = when { field = when {

View File

@@ -487,6 +487,12 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.autofill_inline_suggestions_default)) context.resources.getBoolean(R.bool.autofill_inline_suggestions_default))
} }
fun isAutofillManualSelectionEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_manual_selection_key),
context.resources.getBoolean(R.bool.autofill_manual_selection_default))
}
fun isAutofillSaveSearchInfoEnable(context: Context): Boolean { fun isAutofillSaveSearchInfoEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context) val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.autofill_save_search_info_key), return prefs.getBoolean(context.getString(R.string.autofill_save_search_info_key),
@@ -624,6 +630,7 @@ object PreferencesUtil {
context.getString(R.string.autofill_close_database_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_close_database_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.autofill_auto_search_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_auto_search_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.autofill_inline_suggestions_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())
context.getString(R.string.autofill_save_search_info_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_save_search_info_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.autofill_ask_to_save_data_key) -> editor.putBoolean(name, value.toBoolean()) context.getString(R.string.autofill_ask_to_save_data_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.autofill_application_id_blocklist_key) -> editor.putStringSet(name, getStringSetFromProperties(value)) context.getString(R.string.autofill_application_id_blocklist_key) -> editor.putStringSet(name, getStringSetFromProperties(value))

View File

@@ -448,6 +448,9 @@
<string name="validate">Validieren</string> <string name="validate">Validieren</string>
<string name="autofill_auto_search_summary">Suchergebnisse automatisch nach Web-Domain oder Anwendungs-ID vorschlagen</string> <string name="autofill_auto_search_summary">Suchergebnisse automatisch nach Web-Domain oder Anwendungs-ID vorschlagen</string>
<string name="autofill_auto_search_title">Automatische Suche</string> <string name="autofill_auto_search_title">Automatische Suche</string>
<string name="autofill_manual_selection_prompt">Eintrag auswählen...</string>
<string name="autofill_manual_selection_title">Manuelle Auswahl</string>
<string name="autofill_manual_selection_summary">Manuelle Auswahl des Datenbank-Eintrags ermöglichen</string>
<string name="lock_database_show_button_summary">Zeigt die Sperrtaste in der Benutzeroberfläche an</string> <string name="lock_database_show_button_summary">Zeigt die Sperrtaste in der Benutzeroberfläche an</string>
<string name="lock_database_show_button_title">Sperrtaste anzeigen</string> <string name="lock_database_show_button_title">Sperrtaste anzeigen</string>
<string name="autofill_preference_title">Einstellungen für automatisches Ausfüllen</string> <string name="autofill_preference_title">Einstellungen für automatisches Ausfüllen</string>

View File

@@ -159,6 +159,8 @@
<bool name="autofill_auto_search_default" translatable="false">true</bool> <bool name="autofill_auto_search_default" translatable="false">true</bool>
<string name="autofill_inline_suggestions_key" translatable="false">autofill_inline_suggestions_key</string> <string name="autofill_inline_suggestions_key" translatable="false">autofill_inline_suggestions_key</string>
<bool name="autofill_inline_suggestions_default" translatable="false">false</bool> <bool name="autofill_inline_suggestions_default" translatable="false">false</bool>
<string name="autofill_manual_selection_key" translatable="false">autofill_manual_selection_key</string>
<bool name="autofill_manual_selection_default" translatable="false">false</bool>
<string name="autofill_save_search_info_key" translatable="false">autofill_save_search_info_key</string> <string name="autofill_save_search_info_key" translatable="false">autofill_save_search_info_key</string>
<bool name="autofill_save_search_info_default" translatable="false">true</bool> <bool name="autofill_save_search_info_default" translatable="false">true</bool>
<string name="autofill_ask_to_save_data_key" translatable="false">autofill_ask_to_save_data_key</string> <string name="autofill_ask_to_save_data_key" translatable="false">autofill_ask_to_save_data_key</string>

View File

@@ -487,6 +487,9 @@
<string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application ID</string> <string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application ID</string>
<string name="autofill_inline_suggestions_title">Inline suggestions</string> <string name="autofill_inline_suggestions_title">Inline suggestions</string>
<string name="autofill_inline_suggestions_summary">Attempt to display autofill suggestions directly from a compatible keyboard</string> <string name="autofill_inline_suggestions_summary">Attempt to display autofill suggestions directly from a compatible keyboard</string>
<string name="autofill_manual_selection_prompt">Choose entry...</string>
<string name="autofill_manual_selection_title">Manual selection</string>
<string name="autofill_manual_selection_summary">Display option to let the user select database entry</string>
<string name="autofill_save_search_info_title">Save search info</string> <string name="autofill_save_search_info_title">Save search info</string>
<string name="autofill_save_search_info_summary">Try to save search information when making a manual entry selection</string> <string name="autofill_save_search_info_summary">Try to save search information when making a manual entry selection</string>
<string name="autofill_ask_to_save_data_title">Ask to save data</string> <string name="autofill_ask_to_save_data_title">Ask to save data</string>

View File

@@ -35,6 +35,11 @@
android:title="@string/autofill_inline_suggestions_title" android:title="@string/autofill_inline_suggestions_title"
android:summary="@string/autofill_inline_suggestions_summary" android:summary="@string/autofill_inline_suggestions_summary"
android:defaultValue="@bool/autofill_inline_suggestions_default"/> android:defaultValue="@bool/autofill_inline_suggestions_default"/>
<SwitchPreference
android:key="@string/autofill_manual_selection_key"
android:title="@string/autofill_manual_selection_title"
android:summary="@string/autofill_manual_selection_summary"
android:defaultValue="@bool/autofill_manual_selection_default"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/save"> android:title="@string/save">