Refactor Autofill and Keyboard selection

This commit is contained in:
J-Jamet
2019-02-22 13:34:07 +01:00
parent ff7f0e0a60
commit da86a971b5
21 changed files with 441 additions and 559 deletions

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.autofill
import android.app.Activity
import android.app.assist.AssistStructure
import android.content.Context
import android.content.Intent
import android.os.Build
import android.service.autofill.Dataset
import android.service.autofill.FillResponse
import android.support.annotation.RequiresApi
import android.util.Log
import android.view.autofill.AutofillManager
import android.view.autofill.AutofillValue
import android.widget.RemoteViews
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.PwEntry
import com.kunzisoft.keepass.selection.EntrySelectionHelper
import java.util.*
@RequiresApi(api = Build.VERSION_CODES.O)
object AutofillHelper {
private const val AUTOFILL_RESPONSE_REQUEST_CODE = 8165
private const val ASSIST_STRUCTURE = android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE
fun retrieveAssistStructure(intent: Intent?): AssistStructure? {
intent?.let {
return it.getParcelableExtra(ASSIST_STRUCTURE)
}
return null
}
private fun makeEntryTitle(entry: PwEntry<*>): String {
if (!entry.title.isEmpty() && !entry.username.isEmpty())
return String.format("%s (%s)", entry.title, entry.username)
if (!entry.title.isEmpty())
return entry.title
if (!entry.username.isEmpty())
return entry.username
return if (!entry.notes.isEmpty()) entry.notes.trim { it <= ' ' } else ""
// TODO No title
}
private fun buildDataset(context: Context, entry: PwEntry<*>,
struct: StructureParser.Result): Dataset? {
val title = makeEntryTitle(entry)
val views = newRemoteViews(context.packageName, title)
val builder = Dataset.Builder(views)
builder.setId(entry.uuid.toString())
if (entry.password != null) {
val value = AutofillValue.forText(entry.password)
struct.password.forEach { id -> builder.setValue(id, value) }
}
if (entry.username != null) {
val value = AutofillValue.forText(entry.username)
val ids = ArrayList(struct.username)
if (entry.username.contains("@") || struct.username.isEmpty())
ids.addAll(struct.email)
ids.forEach { id -> builder.setValue(id, value) }
}
return try {
builder.build()
} catch (e: IllegalArgumentException) {
// if not value be set
null
}
}
/**
* Method to hit when right key is selected
*/
fun buildResponseWhenEntrySelected(activity: Activity, entry: PwEntry<*>) {
val mReplyIntent: Intent
activity.intent?.let { intent ->
if (intent.extras.containsKey(ASSIST_STRUCTURE)) {
val structure = intent.getParcelableExtra<AssistStructure>(ASSIST_STRUCTURE)
val result = StructureParser(structure).parse()
// New Response
val responseBuilder = FillResponse.Builder()
val dataset = buildDataset(activity, entry, result)
responseBuilder.addDataset(dataset)
mReplyIntent = Intent()
Log.d(activity.javaClass.name, "Successed Autofill auth.")
mReplyIntent.putExtra(
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
responseBuilder.build())
activity.setResult(Activity.RESULT_OK, mReplyIntent)
} else {
Log.w(activity.javaClass.name, "Failed Autofill auth.")
activity.setResult(Activity.RESULT_CANCELED)
}
}
}
/**
* Utility method to start an activity with an Autofill for result
*/
fun startActivityForAutofillResult(activity: Activity, intent: Intent, assistStructure: AssistStructure) {
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent)
intent.putExtra(ASSIST_STRUCTURE, assistStructure)
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE)
}
/**
* Utility method to loop and close each activity with return data
*/
fun onActivityResultSetResultAndFinish(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == AUTOFILL_RESPONSE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
activity.setResult(resultCode, data)
}
if (resultCode == Activity.RESULT_CANCELED) {
activity.setResult(Activity.RESULT_CANCELED)
}
activity.finish()
}
}
private fun newRemoteViews(packageName: String, remoteViewsText: String): RemoteViews {
val presentation = RemoteViews(packageName, R.layout.autofill_service_list_item)
presentation.setTextViewText(R.id.text, remoteViewsText)
return presentation
}
}