mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add workflow autofill response
This commit is contained in:
@@ -23,12 +23,26 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
public class AutoFillAuthActivity extends PasswordActivity {
|
||||
import com.keepassdroid.fileselect.FileSelectActivity;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
|
||||
import static com.keepassdroid.PasswordActivity.KEY_AUTOFILL_RESPONSE;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class AutoFillAuthActivity extends KeePass {
|
||||
|
||||
public static IntentSender getAuthIntentSenderForResponse(Context context) {
|
||||
final Intent intent = new Intent(context, PasswordActivity.class);
|
||||
final Intent intent = new Intent(context, AutoFillAuthActivity.class);
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
|
||||
.getIntentSender();
|
||||
}
|
||||
|
||||
protected void startFileSelectActivity() {
|
||||
Intent intent = new Intent(this, FileSelectActivity.class);
|
||||
intent.putExtra(KEY_AUTOFILL_RESPONSE, true);
|
||||
startActivityForResult(intent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
package com.keepassdroid;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
@@ -37,6 +39,7 @@ import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -47,8 +50,6 @@ import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.compat.BackupManagerCompat;
|
||||
import com.keepassdroid.compat.ClipDataCompat;
|
||||
@@ -65,6 +66,8 @@ import com.keepassdroid.utils.Interaction;
|
||||
import com.keepassdroid.utils.MenuUtil;
|
||||
import com.keepassdroid.utils.UriUtil;
|
||||
import com.keepassdroid.utils.Util;
|
||||
import com.kunzisoft.keepass.KeePass;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -77,6 +80,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
private static final String KEY_FILENAME = "fileName";
|
||||
private static final String KEY_KEYFILE = "keyFile";
|
||||
private static final String KEY_PASSWORD = "password";
|
||||
public static final String KEY_AUTOFILL_RESPONSE = "KEY_AUTOFILL_RESPONSE";
|
||||
private static final String KEY_LAUNCH_IMMEDIATELY = "launchImmediately";
|
||||
private static final String VIEW_INTENT = "android.intent.action.VIEW";
|
||||
|
||||
@@ -101,16 +105,20 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
private EditText passwordView;
|
||||
private Button confirmButton;
|
||||
|
||||
private Intent mReplyIntent;
|
||||
|
||||
public static void Launch(
|
||||
Activity act,
|
||||
String fileName) throws FileNotFoundException {
|
||||
Launch(act, fileName, "");
|
||||
String fileName,
|
||||
boolean autoFillResponse) throws FileNotFoundException {
|
||||
Launch(act, fileName, "", autoFillResponse);
|
||||
}
|
||||
|
||||
public static void Launch(
|
||||
Activity act,
|
||||
String fileName,
|
||||
String keyFile) throws FileNotFoundException {
|
||||
String keyFile,
|
||||
boolean autoFillResponse) throws FileNotFoundException {
|
||||
if (EmptyUtils.isNullOrEmpty(fileName)) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
@@ -128,9 +136,13 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
Intent i = new Intent(act, PasswordActivity.class);
|
||||
i.putExtra(KEY_FILENAME, fileName);
|
||||
i.putExtra(KEY_KEYFILE, keyFile);
|
||||
i.putExtra(KEY_AUTOFILL_RESPONSE, autoFillResponse);
|
||||
|
||||
act.startActivityForResult(i, 0);
|
||||
|
||||
if(autoFillResponse)
|
||||
act.finish();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -391,9 +403,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
else if (!fingerPrintHelper.hasEnrolledFingerprints()) {
|
||||
|
||||
setFingerPrintVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
fingerprintView.setAlpha(0.3f);
|
||||
}
|
||||
fingerprintView.setAlpha(0.3f);
|
||||
// This happens when no fingerprints are registered. Listening won't start
|
||||
confirmationView.setText(R.string.configure_fingerprint);
|
||||
}
|
||||
@@ -401,9 +411,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
else {
|
||||
fingerprintMustBeConfigured = false;
|
||||
setFingerPrintVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
fingerprintView.setAlpha(1f);
|
||||
}
|
||||
fingerprintView.setAlpha(1f);
|
||||
// fingerprint available but no stored password found yet for this DB so show info don't listen
|
||||
if (prefsNoBackup.getString(getPreferenceKeyValue(), null) == null) {
|
||||
confirmationView.setText(R.string.no_password_stored);
|
||||
@@ -510,7 +518,17 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
App.clearShutdown();
|
||||
|
||||
Handler handler = new Handler();
|
||||
LoadDB task = new LoadDB(db, PasswordActivity.this, mDbUri, pass, keyfile, new AfterLoad(handler, db));
|
||||
AfterLoad afterLoad;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& getIntent().getExtras() != null
|
||||
&& getIntent().getExtras().containsKey(KEY_AUTOFILL_RESPONSE)
|
||||
&& getIntent().getBooleanExtra(KEY_AUTOFILL_RESPONSE, false)) {
|
||||
afterLoad = new AfterLoadAutofill(handler, db);
|
||||
} else {
|
||||
afterLoad = new AfterLoad(handler, db);
|
||||
}
|
||||
|
||||
LoadDB task = new LoadDB(db, PasswordActivity.this, mDbUri, pass, keyfile, afterLoad);
|
||||
ProgressTask pt = new ProgressTask(PasswordActivity.this, task, R.string.loading_database);
|
||||
pt.run();
|
||||
}
|
||||
@@ -550,9 +568,9 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private final class AfterLoad extends OnFinish {
|
||||
private class AfterLoad extends OnFinish {
|
||||
|
||||
private Database db;
|
||||
protected Database db;
|
||||
|
||||
public AfterLoad(
|
||||
Handler handler,
|
||||
@@ -584,6 +602,24 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private class AfterLoadAutofill extends AfterLoad {
|
||||
|
||||
public AfterLoadAutofill(Handler handler, Database db) {
|
||||
super(handler, db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSuccess) {
|
||||
onAutofillResponseSuccess();
|
||||
} else {
|
||||
onAutofillResponseFailure();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private class InitTask extends AsyncTask<Intent, Void, Integer> {
|
||||
|
||||
String password = "";
|
||||
@@ -725,4 +761,51 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static IntentSender getAuthIntentSenderForResponse(Context context) {
|
||||
final Intent intent = new Intent(context, AutoFillAuthActivity.class);
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
|
||||
.getIntentSender();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (mReplyIntent != null) {
|
||||
setResult(RESULT_OK, mReplyIntent);
|
||||
} else {
|
||||
setResult(RESULT_CANCELED);
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private void onAutofillResponseFailure() {
|
||||
Log.w(getClass().getName(), "Failed Autofill auth.");
|
||||
mReplyIntent = null;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private void onAutofillResponseSuccess() {
|
||||
/*
|
||||
Intent intent = getIntent();
|
||||
Bundle clientState = intent.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE);
|
||||
AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
|
||||
StructureParser parser = new StructureParser(getApplicationContext(), structure);
|
||||
parser.parseForFill();
|
||||
AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
|
||||
*/
|
||||
mReplyIntent = new Intent();
|
||||
/*
|
||||
HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
|
||||
SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection
|
||||
(this, autofillFields.getFocusedHints(), autofillFields.getAllHints());
|
||||
|
||||
// TODO Add success results
|
||||
mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, AutofillHelper.newResponse
|
||||
(this, clientState, false, autofillFields, clientFormDataMap));
|
||||
*/
|
||||
mReplyIntent.putExtra(android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.autofill.AutofillId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -26,6 +28,7 @@ import java.util.List;
|
||||
* Data structure that stores a collection of {@code AutofillFieldMetadata}s. Contains all of the
|
||||
* client's {@code View} hierarchy autofill-relevant metadata.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public final class AutofillFieldMetadataCollection {
|
||||
|
||||
private final List<AutofillId> mAutofillIds = new ArrayList<>();
|
||||
|
||||
@@ -22,7 +22,6 @@ package com.keepassdroid.autofill;
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.service.autofill.AutofillService;
|
||||
import android.service.autofill.FillCallback;
|
||||
@@ -51,8 +50,6 @@ public class KeeAutofillService extends AutofillService {
|
||||
AssistStructure structure = request.getFillContexts()
|
||||
.get(request.getFillContexts().size() - 1).getStructure();
|
||||
|
||||
final Bundle clientState = request.getClientState();
|
||||
|
||||
cancellationSignal.setOnCancelListener(() ->
|
||||
Log.e(TAG, "Cancel autofill not implemented in this sample.")
|
||||
);
|
||||
@@ -77,11 +74,8 @@ public class KeeAutofillService extends AutofillService {
|
||||
// If the entire Autofill Response is authenticated, AuthActivity is used
|
||||
// to generate Response.
|
||||
IntentSender sender = AutoFillAuthActivity.getAuthIntentSenderForResponse(this);
|
||||
|
||||
RemoteViews presentation =
|
||||
new RemoteViews(getPackageName(), R.layout.autofill_service_unlock);
|
||||
presentation.setTextViewText(R.id.text, getString(R.string.autofill_sign_in_prompt));
|
||||
|
||||
responseBuilder
|
||||
.setAuthentication(autofillIds, sender, presentation);
|
||||
callback.onSuccess(responseBuilder.build());
|
||||
|
||||
@@ -33,14 +33,14 @@ import com.kunzisoft.keepass.R;
|
||||
* parses the hierarchy and collects autofill metadata from {@link ViewNode}s along the way.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
final class StructureParser {
|
||||
final public class StructureParser {
|
||||
private final AutofillFieldMetadataCollection mAutofillFields =
|
||||
new AutofillFieldMetadataCollection();
|
||||
private final Context mContext;
|
||||
private final AssistStructure mStructure;
|
||||
private FilledAutofillFieldCollection mFilledAutofillFieldCollection;
|
||||
|
||||
StructureParser(Context context, AssistStructure structure) {
|
||||
public StructureParser(Context context, AssistStructure structure) {
|
||||
mContext = context;
|
||||
mStructure = structure;
|
||||
}
|
||||
|
||||
@@ -91,11 +91,17 @@ public class FileSelectActivity extends StylishActivity {
|
||||
private RecentFileHistory fileHistory;
|
||||
|
||||
private boolean recentMode = false;
|
||||
private boolean autofillResponse = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
if(getIntent().getExtras() != null) {
|
||||
autofillResponse = getIntent().getExtras().
|
||||
getBoolean(PasswordActivity.KEY_AUTOFILL_RESPONSE, autofillResponse);
|
||||
}
|
||||
|
||||
fileHistory = App.getFileHistory();
|
||||
|
||||
if (fileHistory.hasRecentFiles()) {
|
||||
@@ -129,7 +135,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
R.id.file_filename);
|
||||
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName);
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName, autofillResponse);
|
||||
}
|
||||
catch (ContentFileNotFoundException e) {
|
||||
Toast.makeText(FileSelectActivity.this,
|
||||
@@ -286,7 +292,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
if (db.exists()) {
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, path);
|
||||
PasswordActivity.Launch(FileSelectActivity.this, path, autofillResponse);
|
||||
} catch (Exception e) {
|
||||
// Ignore exception
|
||||
}
|
||||
@@ -294,7 +300,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, dbUri.toString());
|
||||
PasswordActivity.Launch(FileSelectActivity.this, dbUri.toString(), autofillResponse);
|
||||
} catch (Exception e) {
|
||||
// Ignore exception
|
||||
}
|
||||
@@ -359,7 +365,7 @@ public class FileSelectActivity extends StylishActivity {
|
||||
|
||||
protected void onPostExecute(Void v) {
|
||||
try {
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName, keyFile);
|
||||
PasswordActivity.Launch(FileSelectActivity.this, fileName, keyFile, autofillResponse);
|
||||
}
|
||||
catch (ContentFileNotFoundException e) {
|
||||
Toast.makeText(FileSelectActivity.this, R.string.file_not_found_content, Toast.LENGTH_LONG)
|
||||
|
||||
@@ -40,10 +40,10 @@ public class KeePass extends Activity {
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
startFileSelect();
|
||||
startFileSelectActivity();
|
||||
}
|
||||
|
||||
private void startFileSelect() {
|
||||
protected void startFileSelectActivity() {
|
||||
Intent intent = new Intent(this, FileSelectActivity.class);
|
||||
startActivityForResult(intent, 0);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/autofill_sign_in_prompt"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:layout_gravity="center"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
@@ -33,11 +35,10 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_lock_white_24dp"
|
||||
android:tint="?attr/colorPrimary"/>
|
||||
android:src="@mipmap/ic_launcher"/>
|
||||
</LinearLayout>
|
||||
@@ -205,7 +205,7 @@
|
||||
<string name="general">General</string>
|
||||
<string name="autofill">Autofill</string>
|
||||
<string name="autofill_service_name">KeepassDX Autofill Service</string>
|
||||
<string name="autofill_sign_in_prompt">Tap to sign in.</string>
|
||||
<string name="autofill_sign_in_prompt">Sign in with KeepassDX</string>
|
||||
<string name="set_autofill_service">Set default Autofill service</string>
|
||||
<string name="invalid_link_association">Could not associate web domain %1$s with app %2$s</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user