Fill in field immediately after user unlocks

This commit is contained in:
Matthew Wong
2015-07-28 09:15:41 -04:00
parent e937ddf111
commit 8c266187cb
3 changed files with 40 additions and 33 deletions

View File

@@ -7,7 +7,7 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
// blank activity started by service for calling startIntentSenderForResult
public class AutofillActivity extends AppCompatActivity {
public static final int REQUEST_CODE_DECRYPT_AND_VERIFY = 9913;
private boolean bound = false;
@@ -27,9 +27,9 @@ public class AutofillActivity extends AppCompatActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
finish();
finish(); // go back to the password field app
if (resultCode == RESULT_OK) {
AutofillService.getService().decryptAndVerify();
AutofillService.setUnlockOK(); // report the result to service
}
}
}

View File

@@ -40,29 +40,40 @@ public class AutofillService extends AccessibilityService {
private OpenPgpServiceConnection serviceConnection;
private SharedPreferences settings;
private AccessibilityNodeInfo info; // the original source of the event (the edittext field)
private ArrayList<PasswordItem> items;
private static AutofillService service;
private ArrayList<PasswordItem> items; // password choices
private AlertDialog dialog;
private static boolean unlockOK = false; // if openkeychain user interaction was successful
private static CharSequence packageName;
private static boolean ignoreActionFocus = false;
public final class Constants {
public static final String TAG = "Keychain";
}
public static void setUnlockOK() { unlockOK = true; }
@Override
protected void onServiceConnected() {
super.onServiceConnected();
serviceConnection = new OpenPgpServiceConnection(AutofillService.this, "org.sufficientlysecure.keychain");
serviceConnection.bindToService();
settings = PreferenceManager.getDefaultSharedPreferences(this);
service = this;
}
public static AutofillService getService() {
return service;
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (!event.isPassword() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
&& event.getPackageName().equals(packageName) && unlockOK) {
decryptAndVerify();
}
if (!event.isPassword()
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2
|| (dialog != null && dialog.isShowing())
|| event.getPackageName().equals("org.sufficientlysecure.keychain")) {
return;
}
if (ignoreActionFocus) {
ignoreActionFocus = false;
return;
}
info = event.getSource();
@@ -74,29 +85,23 @@ public class AutofillService extends AccessibilityService {
applicationInfo = null;
}
String appName = (applicationInfo != null ? packageManager.getApplicationLabel(applicationInfo) : "").toString();
if (appName.equals("OpenKeychain")) {
return;
}
items = recursiveFilter(appName, null);
if (items.isEmpty()) {
return;
}
ArrayList<CharSequence> itemNames = new ArrayList<>();
for (PasswordItem item : items) {
itemNames.add(item.toString());
}
if (dialog == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert);
builder.setNegativeButton("Cancel", null);
builder.setView(R.layout.autofill_layout);
final AlertDialog dialog = builder.create();
dialog = builder.create();
dialog.setTitle("Fill with Password Store");
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
dialog.show();
((Button) dialog.findViewById(R.id.button)).setText(itemNames.get(0).toString());
((Button) dialog.findViewById(R.id.button)).setText(items.get(0).getName());
dialog.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -131,6 +136,8 @@ public class AutofillService extends AccessibilityService {
}
public void decryptAndVerify() {
unlockOK = false;
packageName = info.getPackageName();
Intent data = new Intent();
data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
InputStream is = null;
@@ -147,16 +154,16 @@ public class AutofillService extends AccessibilityService {
case OpenPgpApi.RESULT_CODE_SUCCESS: {
try {
String[] passContent = os.toString("UTF-8").split("\n");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// if the user focused on something else, take focus back
// but this will open another dialog...
// but this will open another dialog...hack to ignore this
ignoreActionFocus = true;
info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Bundle args = new Bundle();
args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
passContent[0]);
info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
} else {
info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("autofill_pm", passContent[0]);
clipboard.setPrimaryClip(clip);

View File

@@ -1,6 +1,6 @@
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/autofill_description"
android:accessibilityEventTypes="typeViewFocused"
android:accessibilityEventTypes="typeViewFocused|typeWindowStateChanged"
android:accessibilityFlags="flagDefault"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"