mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
175 lines
6.7 KiB
Java
175 lines
6.7 KiB
Java
/*
|
|
* Copyright 2017 Brian Pellin, 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.Nullable;
|
|
import android.support.annotation.RequiresApi;
|
|
import android.util.Log;
|
|
import android.view.autofill.AutofillId;
|
|
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 java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
public class AutofillHelper {
|
|
|
|
public static final int AUTOFILL_RESPONSE_REQUEST_CODE = 8165;
|
|
|
|
private AssistStructure assistStructure = null;
|
|
|
|
public AssistStructure retrieveAssistStructure(Intent intent) {
|
|
if (intent != null && intent.getExtras() != null) {
|
|
assistStructure = intent.getParcelableExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE);
|
|
}
|
|
return assistStructure;
|
|
}
|
|
|
|
/**
|
|
* Call retrieveAssistStructure before
|
|
*/
|
|
public AssistStructure getAssistStructure() {
|
|
return assistStructure;
|
|
}
|
|
|
|
public static void addAssistStructureExtraInIntent(Intent intent, AssistStructure assistStructure) {
|
|
if (assistStructure != null) {
|
|
intent.putExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE, assistStructure);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Define if android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE is an extra bundle key present in the Intent
|
|
*/
|
|
public static boolean isIntentContainsExtraAssistStructureKey(Intent intent) {
|
|
return (intent != null
|
|
&& intent.getExtras() != null
|
|
&& intent.getExtras().containsKey(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE));
|
|
}
|
|
|
|
private @Nullable Dataset buildDataset(Context context, PwEntry entry,
|
|
StructureParser.Result struct) {
|
|
String title = makeEntryTitle(entry);
|
|
RemoteViews views = newRemoteViews(context.getPackageName(), title);
|
|
Dataset.Builder builder = new Dataset.Builder(views);
|
|
builder.setId(entry.getUUID().toString());
|
|
|
|
if (entry.getPassword() != null) {
|
|
AutofillValue value = AutofillValue.forText(entry.getPassword());
|
|
struct.password.forEach(id -> builder.setValue(id, value));
|
|
}
|
|
if (entry.getUsername() != null) {
|
|
AutofillValue value = AutofillValue.forText(entry.getUsername());
|
|
List<AutofillId> ids = new ArrayList<>(struct.username);
|
|
if (entry.getUsername().contains("@") || struct.username.isEmpty())
|
|
ids.addAll(struct.email);
|
|
ids.forEach(id -> builder.setValue(id, value));
|
|
}
|
|
try {
|
|
return builder.build();
|
|
} catch (IllegalArgumentException e) {
|
|
// if not value be set
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static private String makeEntryTitle(PwEntry entry) {
|
|
if (!entry.getTitle().isEmpty() && !entry.getUsername().isEmpty())
|
|
return String.format("%s (%s)", entry.getTitle(), entry.getUsername());
|
|
if (!entry.getTitle().isEmpty())
|
|
return entry.getTitle();
|
|
if (!entry.getUsername().isEmpty())
|
|
return entry.getUsername();
|
|
if (!entry.getNotes().isEmpty())
|
|
return entry.getNotes().trim();
|
|
return ""; // TODO No title
|
|
}
|
|
|
|
/**
|
|
* Method to hit when right key is selected
|
|
*/
|
|
public void buildResponseWhenEntrySelected(Activity activity, PwEntry entry) {
|
|
Intent mReplyIntent;
|
|
Intent intent = activity.getIntent();
|
|
if (isIntentContainsExtraAssistStructureKey(intent)) {
|
|
AssistStructure structure = intent.getParcelableExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE);
|
|
StructureParser.Result result = new StructureParser(structure).parse();
|
|
|
|
// New Response
|
|
FillResponse.Builder responseBuilder = new FillResponse.Builder();
|
|
Dataset dataset = buildDataset(activity, entry, result);
|
|
responseBuilder.addDataset(dataset);
|
|
mReplyIntent = new Intent();
|
|
Log.d(activity.getClass().getName(), "Successed Autofill auth.");
|
|
mReplyIntent.putExtra(
|
|
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
|
|
responseBuilder.build());
|
|
activity.setResult(Activity.RESULT_OK, mReplyIntent);
|
|
} else {
|
|
Log.w(activity.getClass().getName(), "Failed Autofill auth.");
|
|
activity.setResult(Activity.RESULT_CANCELED);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility method to loop and close each activity with return data
|
|
*/
|
|
public static void onActivityResultSetResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility method to loop and close each activity with return data
|
|
*/
|
|
public static void onActivityResultSetResultAndFinish(Activity activity, int requestCode, int resultCode, Intent data) {
|
|
if (requestCode == AUTOFILL_RESPONSE_REQUEST_CODE) {
|
|
onActivityResultSetResult(activity, requestCode, resultCode, data);
|
|
activity.finish();
|
|
}
|
|
}
|
|
|
|
private static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
|
|
RemoteViews presentation =
|
|
new RemoteViews(packageName, R.layout.autofill_service_list_item);
|
|
presentation.setTextViewText(R.id.text, remoteViewsText);
|
|
return presentation;
|
|
}
|
|
}
|