From 5cb380bf471c6c7db1d165183296176d564c1ad3 Mon Sep 17 00:00:00 2001 From: Matthew Wong Date: Sun, 27 Dec 2015 06:00:06 -0500 Subject: Don't use ResolveInfo for app settings ui --- .../autofill/AutofillPreferenceActivity.java | 37 ++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java') diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java index adfce0b1..0c721012 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java @@ -1,12 +1,14 @@ package com.zeapo.pwdstore.autofill; import android.app.DialogFragment; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; import android.support.v4.app.NavUtils; import android.support.v4.app.TaskStackBuilder; import android.support.v4.view.MenuItemCompat; @@ -14,15 +16,15 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; -import android.util.Pair; import android.view.Menu; import android.view.MenuItem; import android.view.View; import com.zeapo.pwdstore.R; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; +import java.util.Map; public class AutofillPreferenceActivity extends AppCompatActivity { @@ -58,6 +60,13 @@ public class AutofillPreferenceActivity extends AppCompatActivity { } setTitle("Autofill Apps"); + + final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + } + }); } private class populateTask extends AsyncTask { @@ -70,15 +79,25 @@ public class AutofillPreferenceActivity extends AppCompatActivity { protected Void doInBackground(Void... params) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); - List allApps = pm.queryIntentActivities(intent, 0); + List allAppsResolveInfo = pm.queryIntentActivities(intent, 0); + List allApps = new ArrayList<>(); - HashMap> iconMap = new HashMap<>(allApps.size()); - for (ResolveInfo app : allApps) { - iconMap.put(app.activityInfo.packageName - , Pair.create(app.loadIcon(pm), app.loadLabel(pm).toString())); + for (ResolveInfo app : allAppsResolveInfo) { + allApps.add(new AutofillRecyclerAdapter.AppInfo(app.loadLabel(pm).toString() + , app.activityInfo.packageName, app.loadIcon(pm))); + } + + SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE); + Map prefsMap = prefs.getAll(); + for (String key : prefsMap.keySet()) { + try { + allApps.add(new AutofillRecyclerAdapter.AppInfo(null, key, pm.getApplicationIcon("com.android.browser"))); + } catch (PackageManager.NameNotFoundException e) { + allApps.add(new AutofillRecyclerAdapter.AppInfo(null, key, null)); + } } - recyclerAdapter = new AutofillRecyclerAdapter(allApps, iconMap, pm, AutofillPreferenceActivity.this); + recyclerAdapter = new AutofillRecyclerAdapter(allApps, pm, AutofillPreferenceActivity.this); return null; } -- cgit v1.2.3 From 8c884bcba8a39531dc5c16dab2caebf11760708c Mon Sep 17 00:00:00 2001 From: Matthew Wong Date: Wed, 30 Dec 2015 00:15:08 -0500 Subject: Add websites to autofill preferences --- .../zeapo/pwdstore/autofill/AutofillFragment.java | 95 ++++++++++++++++++---- .../autofill/AutofillPreferenceActivity.java | 11 +-- .../pwdstore/autofill/AutofillRecyclerAdapter.java | 87 +++++++++++++------- .../zeapo/pwdstore/autofill/AutofillService.java | 21 +++-- app/src/main/res/layout/fragment_autofill.xml | 13 +++ app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values/strings.xml | 3 +- 7 files changed, 169 insertions(+), 63 deletions(-) (limited to 'app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java') 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 4a5a37cd..1c4c2076 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java @@ -16,6 +16,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.EditText; import android.widget.ListView; import android.widget.RadioButton; import android.widget.RadioGroup; @@ -39,18 +40,28 @@ public class AutofillFragment extends DialogFragment { final AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); LayoutInflater inflater = callingActivity.getLayoutInflater(); - // if... hide textview final View view = inflater.inflate(R.layout.fragment_autofill, null); builder.setView(view); - final String packageName = getArguments().getString("packageName"); - String appName = getArguments().getString("appName"); + String packageName = getArguments().getString("packageName", ""); + String appName = getArguments().getString("appName", ""); - builder.setTitle(appName); + final boolean isWebsite = appName.equals(packageName); + + // set the dialog icon and title or webName editText + String iconPackageName; + if (!isWebsite) { + iconPackageName = packageName; + builder.setTitle(appName); + view.findViewById(R.id.webName).setVisibility(View.GONE); + } else { + iconPackageName = "com.android.browser"; + builder.setTitle("Website"); + ((EditText) view.findViewById(R.id.webName)).setText(packageName); + } try { - // since we can't (easily?) pass the drawable as an argument - builder.setIcon(callingActivity.getPackageManager().getApplicationIcon(packageName)); + builder.setIcon(callingActivity.getPackageManager().getApplicationIcon(iconPackageName)); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } @@ -76,10 +87,15 @@ public class AutofillFragment extends DialogFragment { } }); - // if... autofill_web - SharedPreferences prefs - = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); - String preference = prefs.getString(packageName, ""); + // set the existing preference, if any + SharedPreferences prefs; + String preference; + if (!isWebsite) { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); + } else { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE); + } + preference = prefs.getString(packageName, ""); switch (preference) { case "": ((RadioButton) view.findViewById(R.id.use_default)).toggle(); @@ -108,20 +124,43 @@ public class AutofillFragment extends DialogFragment { }; view.findViewById(R.id.matchButton).setOnClickListener(matchPassword); + // write to preferences when OK clicked final SharedPreferences.Editor editor = prefs.edit(); builder.setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { + String key; + String packageName = getArguments().getString("packageName", ""); + + if (!isWebsite) { + key = packageName; + } else { + key = ((EditText) view.findViewById(R.id.webName)).getText().toString(); + // if key.equals("") show error + + // if new packageName/appName/website name/website title/key + // is different than old, remove the old one. Basically, + // "edit" the old one. + if (!key.equals(packageName) && !packageName.equals("")) { + editor.remove(packageName); + if (callingActivity.recyclerAdapter != null) { + if (callingActivity.recyclerAdapter.getPosition(packageName) != -1) { + callingActivity.recyclerAdapter.removeWebsite(packageName); + } + } + } + } + RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.autofill_radiogroup); switch (radioGroup.getCheckedRadioButtonId()) { case R.id.use_default: - editor.remove(packageName); + editor.remove(key); break; case R.id.first: - editor.putString(packageName, "/first"); + editor.putString(key, "/first"); break; case R.id.never: - editor.putString(packageName, "/never"); + editor.putString(key, "/never"); break; default: StringBuilder paths = new StringBuilder(); @@ -131,14 +170,36 @@ public class AutofillFragment extends DialogFragment { paths.append("\n"); } } - editor.putString(packageName, paths.toString()); + editor.putString(key, paths.toString()); } editor.apply(); - // if recyclerAdapter has not loaded yet, there is no need to notifyItemChanged + // if recyclerAdapter has not loaded yet, there is no need to notify if (callingActivity.recyclerAdapter != null) { - int position = callingActivity.recyclerAdapter.getPosition(packageName); - callingActivity.recyclerAdapter.notifyItemChanged(position); + int position; + if (!isWebsite) { + String appName = getArguments().getString("appName", ""); + position = callingActivity.recyclerAdapter.getPosition(appName); + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else { + String appName = ((EditText) view.findViewById(R.id.webName)).getText().toString(); + position = callingActivity.recyclerAdapter.getPosition(appName); + switch (radioGroup.getCheckedRadioButtonId()) { + // remove if existed, else do nothing + case R.id.use_default: + if (position != -1) { + callingActivity.recyclerAdapter.removeWebsite(appName); + } + break; + // change if existed, else add + default: + if (position != -1) { + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else { + callingActivity.recyclerAdapter.addWebsite(appName); + } + } + } } } }); diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java index 0c721012..7b8a3ba5 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java @@ -65,6 +65,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + showDialog("", ""); } }); } @@ -83,17 +84,17 @@ public class AutofillPreferenceActivity extends AppCompatActivity { List allApps = new ArrayList<>(); for (ResolveInfo app : allAppsResolveInfo) { - allApps.add(new AutofillRecyclerAdapter.AppInfo(app.loadLabel(pm).toString() - , app.activityInfo.packageName, app.loadIcon(pm))); + allApps.add(new AutofillRecyclerAdapter.AppInfo(app.activityInfo.packageName + , app.loadLabel(pm).toString(), app.loadIcon(pm))); } SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE); Map prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { try { - allApps.add(new AutofillRecyclerAdapter.AppInfo(null, key, pm.getApplicationIcon("com.android.browser"))); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, pm.getApplicationIcon("com.android.browser"))); } catch (PackageManager.NameNotFoundException e) { - allApps.add(new AutofillRecyclerAdapter.AppInfo(null, key, null)); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, null)); } } @@ -108,7 +109,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { recyclerView.setAdapter(recyclerAdapter); Bundle extras = getIntent().getExtras(); if (extras != null) { - recyclerView.scrollToPosition(recyclerAdapter.getPosition(extras.getString("packageName"))); + recyclerView.scrollToPosition(recyclerAdapter.getPosition(extras.getString("appName"))); } } } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java index e00f1c5b..2a567254 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java @@ -21,7 +21,7 @@ import java.util.List; public class AutofillRecyclerAdapter extends RecyclerView.Adapter { private SortedList apps; - private ArrayList allApps; + private ArrayList allApps; // for filtering, maintain a list of all private PackageManager pm; private AutofillPreferenceActivity activity; @@ -31,6 +31,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter allApps, final PackageManager pm , AutofillPreferenceActivity activity) { - SortedList.Callback callback = new SortedListAdapterCallback(this) { - @Override - public int compare(AppInfo o1, AppInfo o2) { - return o1.label.toLowerCase().compareTo(o2.label.toLowerCase()); - } - - @Override - public boolean areContentsTheSame(AppInfo oldItem, AppInfo newItem) { - return oldItem.label.equals(newItem.label); - } - - @Override - public boolean areItemsTheSame(AppInfo item1, AppInfo item2) { - return item1.packageName.equals(item2.packageName); - } + SortedList.Callback callback = new SortedListAdapterCallback(this) { + // don't take into account secondary text. This is good enough + // for the limited add/remove usage for websites + @Override + public int compare(AppInfo o1, AppInfo o2) { + return o1.appName.toLowerCase().compareTo(o2.appName.toLowerCase()); + } + + @Override + public boolean areContentsTheSame(AppInfo oldItem, AppInfo newItem) { + return oldItem.appName.equals(newItem.appName); + } + + @Override + public boolean areItemsTheSame(AppInfo item1, AppInfo item2) { + return item1.appName.equals(item2.appName); + } }; this.apps = new SortedList<>(AppInfo.class, callback); this.apps.addAll(allApps); @@ -96,15 +104,20 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter 0) { holder.secondary.append(" and " + (preference.trim().split("\n").length - 1) + " more"); @@ -132,13 +146,24 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { if (webViewTitle.toLowerCase().contains(key.toLowerCase())) { getPreferredPasswords(prefs.getString(key, "")); - return; + return key; } } // possible user-defined match not found, try default setting @@ -238,6 +236,7 @@ public class AutofillService extends AccessibilityService { } else { items.clear(); } + return webViewTitle; } // Put the newline separated list of passwords from the SharedPreferences @@ -295,11 +294,16 @@ public class AutofillService extends AccessibilityService { // the user will have to return to the app themselves. Intent intent = new Intent(AutofillService.this, AutofillPreferenceActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - intent.putExtra("packageName", info.getPackageName()); + if (webViewTitle == null) { + intent.putExtra("packageName", info.getPackageName()); + } else { + intent.putExtra("packageName", appName); + } intent.putExtra("appName", appName); startActivity(intent); } }); + CharSequence itemNames[] = new CharSequence[items.size()]; for (int i = 0; i < items.size(); i++) { itemNames[i] = items.get(i).getName().replace(".gpg", ""); @@ -312,12 +316,13 @@ public class AutofillService extends AccessibilityService { bindDecryptAndVerify(); } }); + 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 = 160; + int height = 144; if (items.size() > 1) { height += 48; } diff --git a/app/src/main/res/layout/fragment_autofill.xml b/app/src/main/res/layout/fragment_autofill.xml index 007147da..4ac1fc56 100644 --- a/app/src/main/res/layout/fragment_autofill.xml +++ b/app/src/main/res/layout/fragment_autofill.xml @@ -9,6 +9,19 @@ android:paddingRight="24dp" android:paddingTop="20dp"> + + + + + Vyplnit Použít výchozí nastavení Automaticky spárovat - Spárovat s… + Spárovat s Nikdy nepárovat \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4047691f..188bf947 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -167,6 +167,7 @@ Fill Use default setting Automatically match - Match with… + Match with Never match + Name -- cgit v1.2.3 From 1c3a4fe763e6722d7398afe518f22c66254c356e Mon Sep 17 00:00:00 2001 From: Matthew Wong Date: Thu, 31 Dec 2015 03:47:51 -0500 Subject: Use URL as package name for app/website settings and match Chrome using URL. But use site title for automatching attempts when URL match not found --- .../zeapo/pwdstore/autofill/AutofillFragment.java | 184 ++++++++++++--------- .../autofill/AutofillPreferenceActivity.java | 15 +- .../pwdstore/autofill/AutofillRecyclerAdapter.java | 41 +++-- .../zeapo/pwdstore/autofill/AutofillService.java | 33 ++-- app/src/main/res/layout/fragment_autofill.xml | 132 +++++++-------- app/src/main/res/values/strings.xml | 2 +- 6 files changed, 222 insertions(+), 185 deletions(-) (limited to 'app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java') 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 1c4c2076..dfe4f3c0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java @@ -16,6 +16,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.RadioButton; @@ -27,7 +28,8 @@ import com.zeapo.pwdstore.R; public class AutofillFragment extends DialogFragment { private static final int MATCH_WITH = 777; - ArrayAdapter adapter; + private ArrayAdapter adapter; + private boolean isWeb; public AutofillFragment() { } @@ -37,28 +39,27 @@ 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 - final AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); + AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); LayoutInflater inflater = callingActivity.getLayoutInflater(); final View view = inflater.inflate(R.layout.fragment_autofill, null); builder.setView(view); - String packageName = getArguments().getString("packageName", ""); - String appName = getArguments().getString("appName", ""); - - final boolean isWebsite = appName.equals(packageName); + String packageName = getArguments().getString("packageName"); + String appName = getArguments().getString("appName"); + isWeb = getArguments().getBoolean("isWeb"); // set the dialog icon and title or webName editText String iconPackageName; - if (!isWebsite) { + if (!isWeb) { iconPackageName = packageName; builder.setTitle(appName); - view.findViewById(R.id.webName).setVisibility(View.GONE); + view.findViewById(R.id.webURL).setVisibility(View.GONE); } else { iconPackageName = "com.android.browser"; builder.setTitle("Website"); - ((EditText) view.findViewById(R.id.webName)).setText(packageName); + ((EditText) view.findViewById(R.id.webURL)).setText(packageName); } try { builder.setIcon(callingActivity.getPackageManager().getApplicationIcon(iconPackageName)); @@ -89,13 +90,12 @@ public class AutofillFragment extends DialogFragment { // set the existing preference, if any SharedPreferences prefs; - String preference; - if (!isWebsite) { + if (!isWeb) { prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); } else { prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE); } - preference = prefs.getString(packageName, ""); + String preference = prefs.getString(packageName, ""); switch (preference) { case "": ((RadioButton) view.findViewById(R.id.use_default)).toggle(); @@ -125,86 +125,106 @@ public class AutofillFragment extends DialogFragment { view.findViewById(R.id.matchButton).setOnClickListener(matchPassword); // write to preferences when OK clicked - final SharedPreferences.Editor editor = prefs.edit(); builder.setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - String key; - String packageName = getArguments().getString("packageName", ""); - - if (!isWebsite) { - key = packageName; - } else { - key = ((EditText) view.findViewById(R.id.webName)).getText().toString(); - // if key.equals("") show error - - // if new packageName/appName/website name/website title/key - // is different than old, remove the old one. Basically, - // "edit" the old one. - if (!key.equals(packageName) && !packageName.equals("")) { - editor.remove(packageName); - if (callingActivity.recyclerAdapter != null) { - if (callingActivity.recyclerAdapter.getPosition(packageName) != -1) { - callingActivity.recyclerAdapter.removeWebsite(packageName); - } - } + + } + }); + builder.setNegativeButton(R.string.dialog_cancel, null); + return builder.create(); + } + + // need to the onClick here for buttons to dismiss dialog only when wanted + @Override + public void onStart() { + super.onStart(); + AlertDialog ad = (AlertDialog) getDialog(); + if(ad != null) { + Button positiveButton = ad.getButton(Dialog.BUTTON_POSITIVE); + positiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity(); + Dialog dialog = getDialog(); + + SharedPreferences prefs; + if (!isWeb) { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); + } else { + prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE); } - } + SharedPreferences.Editor editor = prefs.edit(); - RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.autofill_radiogroup); - switch (radioGroup.getCheckedRadioButtonId()) { - case R.id.use_default: - editor.remove(key); - break; - case R.id.first: - editor.putString(key, "/first"); - break; - case R.id.never: - editor.putString(key, "/never"); - break; - default: - StringBuilder paths = new StringBuilder(); - for (int i = 0; i < adapter.getCount(); i++) { - paths.append(adapter.getItem(i)); - if (i != adapter.getCount()) { - paths.append("\n"); - } + String packageName = getArguments().getString("packageName", ""); + if (isWeb) { + packageName = ((EditText) dialog.findViewById(R.id.webURL)).getText().toString(); + + // handle some errors + EditText webURL = (EditText) dialog.findViewById(R.id.webURL); + if (packageName.equals("")) { + webURL.setError("URL cannot be blank"); + return; } - editor.putString(key, paths.toString()); - } - editor.apply(); - - // if recyclerAdapter has not loaded yet, there is no need to notify - if (callingActivity.recyclerAdapter != null) { - int position; - if (!isWebsite) { - String appName = getArguments().getString("appName", ""); - position = callingActivity.recyclerAdapter.getPosition(appName); - callingActivity.recyclerAdapter.notifyItemChanged(position); - } else { - String appName = ((EditText) view.findViewById(R.id.webName)).getText().toString(); - position = callingActivity.recyclerAdapter.getPosition(appName); - switch (radioGroup.getCheckedRadioButtonId()) { - // remove if existed, else do nothing - case R.id.use_default: - if (position != -1) { - callingActivity.recyclerAdapter.removeWebsite(appName); - } - break; - // change if existed, else add - default: - if (position != -1) { - callingActivity.recyclerAdapter.notifyItemChanged(position); - } else { - callingActivity.recyclerAdapter.addWebsite(appName); + String oldPackageName = getArguments().getString("packageName", ""); + int position = callingActivity.recyclerAdapter.getPosition(packageName); + if (!oldPackageName.equals(packageName) && position != -1) { + webURL.setError("URL already exists"); + return; + } + } + RadioGroup radioGroup = (RadioGroup) dialog.findViewById(R.id.autofill_radiogroup); + switch (radioGroup.getCheckedRadioButtonId()) { + case R.id.use_default: + if (!isWeb) { + editor.remove(packageName); + } else { + editor.putString(packageName, ""); + } + break; + case R.id.first: + editor.putString(packageName, "/first"); + break; + case R.id.never: + editor.putString(packageName, "/never"); + break; + default: + StringBuilder paths = new StringBuilder(); + for (int i = 0; i < adapter.getCount(); i++) { + paths.append(adapter.getItem(i)); + if (i != adapter.getCount()) { + paths.append("\n"); } + } + editor.putString(packageName, paths.toString()); + } + editor.apply(); + + // if recyclerAdapter has not loaded yet, there is no need to notify + if (callingActivity.recyclerAdapter != null) { + int position; + if (!isWeb) { + String appName = getArguments().getString("appName", ""); + position = callingActivity.recyclerAdapter.getPosition(appName); + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else { + position = callingActivity.recyclerAdapter.getPosition(packageName); + String oldPackageName = getArguments().getString("packageName", ""); + if (oldPackageName.equals(packageName)) { + callingActivity.recyclerAdapter.notifyItemChanged(position); + } else if (oldPackageName.equals("")){ + callingActivity.recyclerAdapter.addWebsite(packageName); + } else { + editor.remove(oldPackageName); + callingActivity.recyclerAdapter.updateWebsite(oldPackageName, packageName); + } } } + + dismiss(); } - } - }); - builder.setNegativeButton(R.string.dialog_cancel, null); - return builder.create(); + }); + } } @Override diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java index 7b8a3ba5..81d0ddde 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java @@ -28,7 +28,7 @@ import java.util.Map; public class AutofillPreferenceActivity extends AppCompatActivity { - private RecyclerView recyclerView; + RecyclerView recyclerView; AutofillRecyclerAdapter recyclerAdapter; // let fragment have access private RecyclerView.LayoutManager layoutManager; @@ -56,7 +56,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { if (extras != null) { recreate = true; - showDialog(extras.getString("packageName"), extras.getString("appName")); + showDialog(extras.getString("packageName"), extras.getString("appName"), extras.getBoolean("isWeb")); } setTitle("Autofill Apps"); @@ -65,7 +65,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - showDialog("", ""); + showDialog("", "", true); } }); } @@ -85,16 +85,16 @@ public class AutofillPreferenceActivity extends AppCompatActivity { for (ResolveInfo app : allAppsResolveInfo) { allApps.add(new AutofillRecyclerAdapter.AppInfo(app.activityInfo.packageName - , app.loadLabel(pm).toString(), app.loadIcon(pm))); + , app.loadLabel(pm).toString(), false, app.loadIcon(pm))); } SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE); Map prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { try { - allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, pm.getApplicationIcon("com.android.browser"))); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, pm.getApplicationIcon("com.android.browser"))); } catch (PackageManager.NameNotFoundException e) { - allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, null)); + allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, null)); } } @@ -158,11 +158,12 @@ public class AutofillPreferenceActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - public void showDialog(String packageName, String appName) { + public void showDialog(String packageName, String appName, boolean isWeb) { DialogFragment df = new AutofillFragment(); Bundle args = new Bundle(); args.putString("packageName", packageName); args.putString("appName", appName); + args.putBoolean("isWeb", isWeb); df.setArguments(args); df.show(getFragmentManager(), "autofill_dialog"); } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java index 2a567254..901ff903 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java @@ -24,6 +24,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter allApps; // for filtering, maintain a list of all private PackageManager pm; private AutofillPreferenceActivity activity; + Drawable browserIcon = null; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public View view; @@ -32,6 +33,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter(allApps); this.pm = pm; this.activity = activity; + try { + browserIcon = activity.getPackageManager().getApplicationIcon("com.android.browser"); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } } @Override @@ -105,6 +114,7 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter prefsMap = prefs.getAll(); for (String key : prefsMap.keySet()) { - if (webViewTitle.toLowerCase().contains(key.toLowerCase())) { + if (webViewURL.toLowerCase().contains(key.toLowerCase())) { getPreferredPasswords(prefs.getString(key, "")); return key; } } - // possible user-defined match not found, try default setting + + // no user-defined match found, maybe auto match using title, not URL if (settings.getBoolean("autofill_default", true)) { if (!PasswordRepository.isInitialized()) { PasswordRepository.initialize(this); @@ -263,7 +269,7 @@ public class AutofillService extends AccessibilityService { } else { items = new ArrayList<>(); } - return webViewTitle; + return webViewURL; } // Put the newline separated list of passwords from the SharedPreferences @@ -305,7 +311,7 @@ public class AutofillService extends AccessibilityService { return items; } - private void showDialog(final String appName) { + private void showDialog(final String packageName, final String appName) { AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog); builder.setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() { @Override @@ -320,12 +326,11 @@ public class AutofillService extends AccessibilityService { // the user will have to return to the app themselves. Intent intent = new Intent(AutofillService.this, AutofillPreferenceActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - if (webViewTitle == null) { - intent.putExtra("packageName", info.getPackageName()); - } else { - intent.putExtra("packageName", appName); - } + intent.putExtra("packageName", packageName); intent.putExtra("appName", appName); + if (webViewTitle != null) { + intent.putExtra("isWeb", true); + } startActivity(intent); } }); diff --git a/app/src/main/res/layout/fragment_autofill.xml b/app/src/main/res/layout/fragment_autofill.xml index 4ac1fc56..1f6aeba2 100644 --- a/app/src/main/res/layout/fragment_autofill.xml +++ b/app/src/main/res/layout/fragment_autofill.xml @@ -1,79 +1,79 @@ - + - + - - - - + android:layout_height="wrap_content" + android:hint="@string/autofill_webURL_hint" + android:inputType="textUri"/> + + + - + - + - + - + -