Add workflow autofill response

This commit is contained in:
Jeremy
2017-11-24 22:01:18 +01:00
parent d20eef0922
commit 8f8b265d97
9 changed files with 137 additions and 36 deletions

View File

@@ -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);
}
}

View File

@@ -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, "");
}
}

View File

@@ -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<>();

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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>