summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorMatthew Wong <wongma@protonmail.ch>2015-12-31 18:26:43 -0500
committerMatthew Wong <wongma@protonmail.ch>2015-12-31 18:26:43 -0500
commit963859b3476b330445e8e0d1ded0553b0a2cc18a (patch)
tree862836a91c673ff3c6235937b748b8be0d97b533 /app/src/main/java
parenta3e10d3ca83c78f19d342a76caebefa924b8d705 (diff)
Fix settings and add "pick and match" option
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java54
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java9
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java133
3 files changed, 126 insertions, 70 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
index 0f184bb7..2ddcfa02 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
@@ -1,18 +1,27 @@
package com.zeapo.pwdstore.autofill;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.zeapo.pwdstore.PasswordStore;
+import org.eclipse.jgit.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
// blank activity started by service for calling startIntentSenderForResult
public class AutofillActivity extends AppCompatActivity {
public static final int REQUEST_CODE_DECRYPT_AND_VERIFY = 9913;
- public static final int REQUEST_CODE_MATCH_WITH = 777;
+ public static final int REQUEST_CODE_PICK = 777;
+ public static final int REQUEST_CODE_PICK_MATCH_WITH = 778;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -30,10 +39,14 @@ public class AutofillActivity extends AppCompatActivity {
} catch (IntentSender.SendIntentException e) {
Log.e(AutofillService.Constants.TAG, "SendIntentException", e);
}
- } else if (extras != null && extras.containsKey("matchWith")) {
+ } else if (extras != null && extras.containsKey("pick")) {
+ Intent intent = new Intent(getApplicationContext(), PasswordStore.class);
+ intent.putExtra("matchWith", true);
+ startActivityForResult(intent, REQUEST_CODE_PICK);
+ } else if (extras != null && extras.containsKey("pickMatchWith")) {
Intent intent = new Intent(getApplicationContext(), PasswordStore.class);
intent.putExtra("matchWith", true);
- startActivityForResult(intent, REQUEST_CODE_MATCH_WITH);
+ startActivityForResult(intent, REQUEST_CODE_PICK_MATCH_WITH);
}
}
@@ -46,10 +59,43 @@ public class AutofillActivity extends AppCompatActivity {
AutofillService.getInstance().setResultData(data); // report the result to service
}
break;
- case REQUEST_CODE_MATCH_WITH:
+ case REQUEST_CODE_PICK:
if (resultCode == RESULT_OK) {
AutofillService.getInstance().setPickedPassword(data.getStringExtra("path"));
}
+ break;
+ case REQUEST_CODE_PICK_MATCH_WITH:
+ if (resultCode == RESULT_OK) {
+ Bundle extras = getIntent().getExtras();
+ String packageName = extras.getString("packageName");
+ boolean isWeb = extras.getBoolean("isWeb");
+
+ String path = data.getStringExtra("path");
+ AutofillService.getInstance().setPickedPassword(data.getStringExtra("path"));
+
+ SharedPreferences prefs;
+ if (!isWeb) {
+ prefs = getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE);
+ } else {
+ prefs = getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
+ }
+ SharedPreferences.Editor editor = prefs.edit();
+ String preference = prefs.getString(packageName, "");
+ switch (preference) {
+ case "":
+ case "/first":
+ case "/never":
+ editor.putString(packageName, path);
+ break;
+ default:
+ List<String> matches = new ArrayList<>(Arrays.asList(preference.trim().split("\n")));
+ matches.add(path);
+ String paths = StringUtils.join(matches, "\n");
+ editor.putString(packageName, paths);
+ }
+ editor.apply();
+ }
+ break;
}
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
index 474c3e35..0ad28a31 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
@@ -39,7 +39,7 @@ public class AutofillFragment extends DialogFragment {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// this fragment is only created from the settings page (AutofillPreferenceActivity)
// need to interact with the recyclerAdapter which is a member of activity
- AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity();
+ final AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity();
LayoutInflater inflater = callingActivity.getLayoutInflater();
final View view = inflater.inflate(R.layout.fragment_autofill, null);
@@ -137,10 +137,10 @@ public class AutofillFragment extends DialogFragment {
builder.setNeutralButton(R.string.autofill_apps_delete, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (((AutofillPreferenceActivity) getActivity()).recyclerAdapter != null
+ if (callingActivity.recyclerAdapter != null
&& packageName != null && !packageName.equals("")) {
editor.remove(packageName);
- ((AutofillPreferenceActivity) getActivity()).recyclerAdapter.removeWebsite(packageName);
+ callingActivity.recyclerAdapter.removeWebsite(packageName);
editor.apply();
}
}
@@ -181,8 +181,7 @@ public class AutofillFragment extends DialogFragment {
return;
}
String oldPackageName = getArguments().getString("packageName", "");
- int position = callingActivity.recyclerAdapter.getPosition(packageName);
- if (!oldPackageName.equals(packageName) && position != -1) {
+ if (!oldPackageName.equals(packageName) && prefs.getAll().containsKey(packageName)) {
webURL.setError("URL already exists");
return;
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
index 305dfdfa..e6a49bb9 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
@@ -110,11 +110,12 @@ public class AutofillService extends AccessibilityService {
webViewTitle = searchWebView(getRootInActiveWindow());
webViewURL = null;
- if (webViewTitle != null) {
+ if (webViewTitle != null && getRootInActiveWindow() != null) {
List<AccessibilityNodeInfo> nodes = getRootInActiveWindow()
.findAccessibilityNodeInfosByViewId("com.android.chrome:id/url_bar");
- if (nodes.size() == 0) {
- nodes = getRootInActiveWindow().findAccessibilityNodeInfosByViewId("com.android.browser:id/url");
+ if (nodes.isEmpty()) {
+ nodes = getRootInActiveWindow()
+ .findAccessibilityNodeInfosByViewId("com.android.browser:id/url");
}
for (AccessibilityNodeInfo node : nodes)
if (node.getText() != null) {
@@ -178,7 +179,11 @@ public class AutofillService extends AccessibilityService {
String packageName;
String appName;
- if (webViewTitle == null) {
+ boolean isWeb;
+
+ // Match with the app if a webview was not found or one was found but
+ // there's no title or url to go by
+ if (webViewTitle == null || (webViewTitle.equals("") && webViewURL == null)) {
packageName = info.getPackageName().toString();
// get the app name and find a corresponding password
@@ -191,11 +196,13 @@ public class AutofillService extends AccessibilityService {
}
appName = (applicationInfo != null ? packageManager.getApplicationLabel(applicationInfo) : "").toString();
- setMatchingPasswords(appName, info.getPackageName().toString());
- } else {
- packageName = setMatchingPasswordsWeb(webViewTitle, webViewURL);
+ isWeb = false;
+ setMatchingPasswords(appName, packageName, false);
+ } else {
+ packageName = setMatchingPasswords(webViewTitle, webViewURL, true);
appName = packageName;
+ isWeb = true;
}
// if autofill_always checked, show dialog even if no matches (automatic
@@ -203,7 +210,7 @@ public class AutofillService extends AccessibilityService {
if (items.isEmpty() && !settings.getBoolean("autofill_always", false)) {
return;
}
- showDialog(packageName, appName);
+ showDialog(packageName, appName, isWeb);
}
private String searchWebView(AccessibilityNodeInfo source) {
@@ -248,11 +255,35 @@ public class AutofillService extends AccessibilityService {
}
}
- private void setMatchingPasswords(String appName, String packageName) {
+ private String setMatchingPasswords(String appName, String packageName, boolean isWeb) {
+ // Return the URL needed to open the corresponding Settings.
+ String settingsURL = packageName;
+
// if autofill_default is checked and prefs.getString DNE, 'Automatically match with password'/"first" otherwise "never"
String defValue = settings.getBoolean("autofill_default", true) ? "/first" : "/never";
- SharedPreferences prefs = getSharedPreferences("autofill", Context.MODE_PRIVATE);
- String preference = prefs.getString(packageName, defValue);
+ SharedPreferences prefs;
+ String preference;
+ if (!isWeb) {
+ prefs = getSharedPreferences("autofill", Context.MODE_PRIVATE);
+ preference = prefs.getString(packageName, defValue);
+ } else {
+ prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
+ preference = defValue;
+ }
+
+ // for websites unlike apps there can be blank preference of "" which
+ // means use default, so ignore it.
+ if (isWeb) {
+ Map<String, ?> prefsMap = prefs.getAll();
+ for (String key : prefsMap.keySet()) {
+ if ((webViewURL.toLowerCase().contains(key.toLowerCase()) || key.toLowerCase().contains(webViewURL.toLowerCase()))
+ && !prefs.getString(key, null).equals("")) {
+ preference = prefs.getString(key, null);
+ settingsURL = key;
+ }
+ }
+ }
+
switch (preference) {
case "/first":
if (!PasswordRepository.isInitialized()) {
@@ -262,34 +293,12 @@ public class AutofillService extends AccessibilityService {
break;
case "/never":
items = new ArrayList<>();
- return;
+ break;
default:
getPreferredPasswords(preference);
}
- }
-
- // Return the the matched preference's key, which isn't necessarily equal to
- // the URL, if a preference is matched so it can be accessed with Settings.
- private String setMatchingPasswordsWeb(String webViewTitle, String webViewURL) {
- SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
- Map<String, ?> prefsMap = prefs.getAll();
- for (String key : prefsMap.keySet()) {
- if (webViewURL.toLowerCase().contains(key.toLowerCase())) {
- getPreferredPasswords(prefs.getString(key, ""));
- return key;
- }
- }
- // no user-defined match found, maybe auto match using title, not URL
- if (settings.getBoolean("autofill_default", true)) {
- if (!PasswordRepository.isInitialized()) {
- PasswordRepository.initialize(this);
- }
- items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), webViewTitle);
- } else {
- items = new ArrayList<>();
- }
- return webViewURL;
+ return settingsURL;
}
// Put the newline separated list of passwords from the SharedPreferences
@@ -331,7 +340,7 @@ public class AutofillService extends AccessibilityService {
return items;
}
- private void showDialog(final String packageName, final String appName) {
+ private void showDialog(final String packageName, final String appName, final boolean isWeb) {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog);
builder.setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
@Override
@@ -348,46 +357,48 @@ public class AutofillService extends AccessibilityService {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra("packageName", packageName);
intent.putExtra("appName", appName);
- if (webViewTitle != null) {
- intent.putExtra("isWeb", true);
- }
+ intent.putExtra("isWeb", isWeb);
startActivity(intent);
}
});
- if (!items.isEmpty()) {
- CharSequence itemNames[] = new CharSequence[items.size()];
- for (int i = 0; i < items.size(); i++) {
- itemNames[i] = items.get(i).getName().replace(".gpg", "");
- }
- builder.setItems(itemNames, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- lastWhichItem = which;
+ CharSequence itemNames[] = new CharSequence[items.size() + 2];
+ for (int i = 0; i < items.size(); i++) {
+ itemNames[i] = items.get(i).getName().replace(".gpg", "");
+ }
+ itemNames[items.size()] = "Pick...";
+ itemNames[items.size() + 1] = "Pick and match...";
+ builder.setItems(itemNames, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ lastWhichItem = which;
+ if (which < items.size()) {
bindDecryptAndVerify();
- }
- });
- } else {
- builder.setItems(new CharSequence[]{"Pick a password..."}, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- lastWhichItem = which; // always 0
- // TODO option to remember a pick for the future when possible? or option to have this always visible?
+ } else if (which == items.size()){
+ Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra("pick", true);
+ startActivity(intent);
+ } else {
+ lastWhichItem--;
Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.putExtra("matchWith", true);
+ intent.putExtra("pickMatchWith", true);
+ intent.putExtra("packageName", packageName);
+ intent.putExtra("isWeb", isWeb);
startActivity(intent);
}
- });
- }
+ }
+ });
+
dialog = builder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
// arbitrary non-annoying size
int height = 154;
- if (items.size() > 1) {
- height += 33;
+ if (itemNames.length > 1) {
+ height += 46;
}
dialog.getWindow().setLayout((int) (240 * getApplicationContext().getResources().getDisplayMetrics().density)
, (int) (height * getApplicationContext().getResources().getDisplayMetrics().density));