From c66fc102ee16d916e5d92cd1143ae4b8ad17a007 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Thu, 1 Oct 2020 18:55:29 +0200 Subject: [PATCH] First commit for save --- .../keepass/autofill/KeeAutofillService.kt | 20 +++++++++++++++++-- .../keepass/autofill/StructureParser.kt | 16 ++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt index eaef31622..d74d1c976 100644 --- a/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt @@ -110,6 +110,13 @@ class KeeAutofillService : AutofillService() { } else { RemoteViews(packageName, R.layout.item_autofill_unlock) } + // Tell to service the interest to save credentials + responseBuilder.setSaveInfo( + SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_USERNAME + or SaveInfo.SAVE_DATA_TYPE_PASSWORD, + arrayOf(parseResult.usernameId, parseResult.passwordId) + ).build() + ) responseBuilder.setAuthentication(autofillIds, sender, remoteViewsUnlock) callback.onSuccess(responseBuilder.build()) } @@ -117,8 +124,17 @@ class KeeAutofillService : AutofillService() { } override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) { - // TODO Save autofill - //callback.onFailure(getString(R.string.autofill_not_support_save)); + val fillContexts = request.fillContexts + val latestStructure = fillContexts[fillContexts.size - 1].structure + + StructureParser(latestStructure, true).parse()?.let { parseResult -> + parseResult.passwordValue?.let { autofillPasswordValue -> + Log.d(TAG, "autofill onSaveRequest password ${autofillPasswordValue.textValue}") + callback.onSuccess() + return + } + } + callback.onFailure("Unable to save values from form") } override fun onConnected() { diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt index ef5e53186..48d7ee94b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt +++ b/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt @@ -25,6 +25,7 @@ import androidx.annotation.RequiresApi import android.util.Log import android.view.View import android.view.autofill.AutofillId +import android.view.autofill.AutofillValue import java.util.* @@ -32,7 +33,8 @@ import java.util.* * Parse AssistStructure and guess username and password fields. */ @RequiresApi(api = Build.VERSION_CODES.O) -internal class StructureParser(private val structure: AssistStructure) { +internal class StructureParser(private val structure: AssistStructure, + private val retrieveValues: Boolean = false) { private var result: Result? = null private var usernameCandidate: AutofillId? = null private var usernameNeeded = true @@ -41,6 +43,7 @@ internal class StructureParser(private val structure: AssistStructure) { try { result = Result() result?.apply { + allowValues = true usernameCandidate = null mainLoop@ for (i in 0 until structure.windowNodeCount) { val windowNode = structure.getWindowNodeAt(i) @@ -111,6 +114,7 @@ internal class StructureParser(private val structure: AssistStructure) { } it.contains(View.AUTOFILL_HINT_PASSWORD, true) -> { result?.passwordId = autofillId + result?.passwordValue = node.autofillValue Log.d(TAG, "Autofill password hint") // Username not needed in this case usernameNeeded = false @@ -148,6 +152,7 @@ internal class StructureParser(private val structure: AssistStructure) { } "password" -> { result?.passwordId = autofillId + result?.passwordValue = node.autofillValue Log.d(TAG, "Autofill password web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}") return true } @@ -196,6 +201,7 @@ internal class StructureParser(private val structure: AssistStructure) { InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD, InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD) -> { result?.passwordId = autofillId + result?.passwordValue = node.autofillValue Log.d(TAG, "Autofill password android text type: ${showHexInputType(inputType)}") usernameNeeded = false return true @@ -259,6 +265,14 @@ internal class StructureParser(private val structure: AssistStructure) { field = value } + var allowValues = false + + var passwordValue: AutofillValue? = null + set(value) { + if (allowValues && field == null) + field = value + } + fun allAutofillIds(): Array { val all = ArrayList() usernameId?.let {