mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Let user select entry for autofill
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user