fix: Autofill implementation

This commit is contained in:
J-Jamet
2023-09-04 19:16:16 +02:00
parent 1e77a42c93
commit 6d633c9986
4 changed files with 122 additions and 64 deletions

View File

@@ -1,7 +1,6 @@
package com.kunzisoft.keepass.autofill
import android.app.assist.AssistStructure
import android.view.inputmethod.InlineSuggestionsRequest
data class AutofillComponent(val assistStructure: AssistStructure,
val compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest?)

View File

@@ -119,7 +119,7 @@ object AutofillHelper {
setField(
id, autofillValue?.let {
Field.Builder()
.setValue(autofillValue)
.setValue(it)
.build()
}
)
@@ -127,6 +127,7 @@ object AutofillHelper {
@Suppress("DEPRECATION")
setValue(id, autofillValue)
}
Log.d(TAG, "Set Autofill value $autofillValue for id $id")
return this
}
@@ -134,8 +135,8 @@ object AutofillHelper {
database: ContextualDatabase,
entryInfo: EntryInfo,
struct: StructureParser.Result,
inlinePresentation: InlinePresentation?): Dataset.Builder {
val remoteViews = newRemoteViews(context, database, makeEntryTitle(entryInfo), entryInfo.icon)
inlinePresentation: InlinePresentation?): Dataset {
val remoteViews: RemoteViews = newRemoteViews(context, database, makeEntryTitle(entryInfo), entryInfo.icon)
val datasetBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Dataset.Builder(Presentations.Builder()
@@ -145,6 +146,7 @@ object AutofillHelper {
}
}
.setDialogPresentation(remoteViews)
.setMenuPresentation(remoteViews)
.build())
} else {
@Suppress("DEPRECATION")
@@ -160,10 +162,16 @@ object AutofillHelper {
datasetBuilder.setId(entryInfo.id.toString())
struct.usernameId?.let { usernameId ->
datasetBuilder.addValueToDatasetBuilder(usernameId, AutofillValue.forText(entryInfo.username))
datasetBuilder.addValueToDatasetBuilder(
usernameId,
AutofillValue.forText(entryInfo.username)
)
}
struct.passwordId?.let { passwordId ->
datasetBuilder.addValueToDatasetBuilder(passwordId, AutofillValue.forText(entryInfo.password))
datasetBuilder.addValueToDatasetBuilder(
passwordId,
AutofillValue.forText(entryInfo.password)
)
}
if (entryInfo.expires) {
@@ -176,9 +184,15 @@ object AutofillHelper {
struct.creditCardExpirationDateId?.let {
if (struct.isWebView) {
// set date string as defined in https://html.spec.whatwg.org
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText("$year\u002D$monthString"))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText("$year\u002D$monthString")
)
} else {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forDate(entryInfo.expiryTime.date.time))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forDate(entryInfo.expiryTime.date.time)
)
}
}
struct.creditCardExpirationYearId?.let {
@@ -192,34 +206,58 @@ object AutofillHelper {
}
if (yearIndex != -1) {
autofillValue = AutofillValue.forList(yearIndex)
datasetBuilder.addValueToDatasetBuilder(it, autofillValue)
datasetBuilder.addValueToDatasetBuilder(
it,
autofillValue
)
}
}
if (autofillValue == null) {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText(year.toString()))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(year.toString())
)
}
}
struct.creditCardExpirationMonthId?.let {
if (struct.isWebView) {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText(monthString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(monthString)
)
} else {
if (struct.creditCardExpirationMonthOptions != null) {
// index starts at 0
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forList(month - 1))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forList(month - 1)
)
} else {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText(monthString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(monthString)
)
}
}
}
struct.creditCardExpirationDayId?.let {
if (struct.isWebView) {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText(dayString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(dayString)
)
} else {
if (struct.creditCardExpirationDayOptions != null) {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forList(day - 1))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forList(day - 1)
)
} else {
datasetBuilder.addValueToDatasetBuilder(it, AutofillValue.forText(dayString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(dayString)
)
}
}
}
@@ -227,22 +265,32 @@ object AutofillHelper {
for (field in entryInfo.customFields) {
if (field.name == TemplateField.LABEL_HOLDER) {
struct.creditCardHolderId?.let { ccNameId ->
datasetBuilder.addValueToDatasetBuilder(ccNameId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
ccNameId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
if (field.name == TemplateField.LABEL_NUMBER) {
struct.creditCardNumberId?.let { ccnId ->
datasetBuilder.addValueToDatasetBuilder(ccnId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
ccnId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
if (field.name == TemplateField.LABEL_CVV) {
struct.cardVerificationValueId?.let { cvvId ->
datasetBuilder.addValueToDatasetBuilder(cvvId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
cvvId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
}
return datasetBuilder
val dataset = datasetBuilder.build()
Log.d(TAG, "Autofill Dataset $dataset created")
return dataset
}
/**
@@ -388,7 +436,7 @@ object AutofillHelper {
}
// Create dataset for each entry
responseBuilder.addDataset(
buildDatasetForEntry(context, database, entry, parseResult, inlinePresentation).build()
buildDatasetForEntry(context, database, entry, parseResult, inlinePresentation)
)
} catch (e: Exception) {
Log.e(TAG, "Unable to add dataset")
@@ -407,9 +455,6 @@ object AutofillHelper {
val pendingIntent = AutofillLauncherActivity.getPendingIntentForSelection(context,
searchInfo, compatInlineSuggestionsRequest)
parseResult.allAutofillIds().let { autofillIds ->
autofillIds.forEach { id ->
var inlinePresentation: InlinePresentation? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
compatInlineSuggestionsRequest?.inlineSuggestionsRequest?.let { inlineSuggestionsRequest ->
@@ -426,6 +471,7 @@ object AutofillHelper {
}
}
.setDialogPresentation(manualSelectionView)
.setMenuPresentation(manualSelectionView)
.build())
} else {
@Suppress("DEPRECATION")
@@ -438,21 +484,21 @@ object AutofillHelper {
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
datasetBuilder.setField(id, null)
} else {
@Suppress("DEPRECATION")
parseResult.allAutofillIds().let { autofillIds ->
autofillIds.forEach { id ->
datasetBuilder.addValueToDatasetBuilder(id, null)
}
datasetBuilder.setAuthentication(pendingIntent.intentSender)
responseBuilder.addDataset(datasetBuilder.build())
}
val dataset = datasetBuilder.build()
Log.d(TAG, "Autofill Dataset for manual selection $dataset created")
responseBuilder.addDataset(dataset)
}
}
return try {
responseBuilder.build()
} catch (e: Exception) {
Log.e(TAG, "Unable to create Autofill response", e)
null
}
}
@@ -489,7 +535,7 @@ object AutofillHelper {
buildResponse(activity, database, entriesInfo, result, null)
}
val mReplyIntent = Intent()
Log.d(activity.javaClass.name, "Successed Autofill auth.")
Log.d(activity.javaClass.name, "Success Autofill auth.")
mReplyIntent.putExtra(
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
response)

View File

@@ -90,6 +90,12 @@ class KeeAutofillService : AutofillService() {
cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill.") }
if (request.flags and FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST != 0) {
Log.d(TAG, "Autofill requested in compatibility mode")
} else {
Log.d(TAG, "Autofill requested in native mode")
}
// Lock
if (!mLock.get()) {
mLock.set(true)
@@ -157,6 +163,7 @@ class KeeAutofillService : AutofillService() {
searchInfo: SearchInfo,
inlineSuggestionsRequest: CompatInlineSuggestionsRequest?,
callback: FillCallback) {
var success = false
parseResult.allAutofillIds().let { autofillIds ->
if (autofillIds.isNotEmpty()) {
// If the entire Autofill Response is authenticated, AuthActivity is used
@@ -299,12 +306,16 @@ class KeeAutofillService : AutofillService() {
@Suppress("DEPRECATION")
responseBuilder.setAuthentication(autofillIds, intentSender, remoteViewsUnlock)
}
success = true
callback.onSuccess(responseBuilder.build())
}
}
if (!success)
callback.onFailure("Unable to get Autofill ids for UI selection")
}
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
var success = false
if (askToSaveData) {
val latestStructure = request.fillContexts.last().structure
StructureParser(latestStructure).parse(true)?.let { parseResult ->
@@ -348,14 +359,16 @@ class KeeAutofillService : AutofillService() {
// registerInfo))
//} else {
AutofillLauncherActivity.launchForRegistration(this, registerInfo)
success = true
callback.onSuccess()
//}
return
}
}
}
if (!success) {
callback.onFailure("Saving form values is not allowed")
}
}
override fun onConnected() {
Log.d(TAG, "onConnected")

View File

@@ -36,7 +36,7 @@
android:minHeight="48dp"
android:hint="@string/password"
android:inputType="textPassword"
android:importantForAutofill="yes"
android:importantForAutofill="no"
android:focusable="true"
android:focusableInTouchMode="true"
android:autofillHints="password"