From ec07e1eea69a69e9579ddfb44fdbee3535bcf6ad Mon Sep 17 00:00:00 2001 From: Matthew Wong Date: Thu, 13 Aug 2015 15:18:47 -0400 Subject: [PATCH] Preference activity overhaul --- .../pwdstore/autofill/AutofillFragment.java | 31 ++-- .../autofill/AutofillPreferenceActivity.java | 144 ++++++------------ .../autofill/AutofillRecyclerAdapter.java | 132 +++------------- .../pwdstore/autofill/AutofillService.java | 3 +- .../res/layout/autofill_recycler_view.xml | 11 +- .../main/res/layout/autofill_row_layout.xml | 5 +- app/src/main/res/layout/fragment_autofill.xml | 15 +- app/src/main/res/menu/autofill_preference.xml | 12 ++ app/src/main/res/xml/preference.xml | 2 +- 9 files changed, 119 insertions(+), 236 deletions(-) create mode 100644 app/src/main/res/menu/autofill_preference.xml 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 ea4b0a2f..c2a30ffe 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java @@ -3,7 +3,7 @@ package com.zeapo.pwdstore.autofill; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; -import android.preference.PreferenceManager; +import android.content.pm.PackageManager; import android.support.v7.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -40,15 +40,20 @@ public class AutofillFragment extends DialogFragment { String appName = getArguments().getString("appName"); builder.setTitle(appName); + try { + // since we can't (easily?) pass the drawable as an argument + builder.setIcon(callingActivity.getPackageManager().getApplicationIcon(packageName)); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } - // when an app is added for the first time, the radio button selection should reflect - // the autofill_default setting: hence, defValue - SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(callingActivity); - String defValue = settings.getBoolean("autofill_default", true) ? "first" : "never"; SharedPreferences prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE); - String preference = prefs.getString(packageName, defValue); + String preference = prefs.getString(packageName, ""); switch (preference) { + case "": + ((RadioButton) view.findViewById(R.id.use_default)).toggle(); + break; case "first": ((RadioButton) view.findViewById(R.id.first)).toggle(); break; @@ -77,6 +82,9 @@ public class AutofillFragment extends DialogFragment { public void onClick(DialogInterface dialog, int which) { RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.autofill_radiogroup); switch (radioGroup.getCheckedRadioButtonId()) { + case R.id.use_default: + editor.remove(packageName); + break; case R.id.first: editor.putString(packageName, "first"); break; @@ -90,10 +98,10 @@ public class AutofillFragment extends DialogFragment { } editor.apply(); int position = getArguments().getInt("position"); - if (position == -1) { - callingActivity.recyclerAdapter.add(packageName); - } else { - callingActivity.recyclerAdapter.notifyItemChanged(position); + callingActivity.recyclerAdapter.notifyItemChanged(position); + + if (getArguments().getBoolean("finish")) { + callingActivity.finish(); } } }); @@ -105,7 +113,8 @@ public class AutofillFragment extends DialogFragment { public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { ((EditText) getDialog().findViewById(R.id.matched)).setText(data.getStringExtra("path")); + } else { + ((RadioButton) getDialog().findViewById(R.id.use_default)).toggle(); } - } } 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 abf1f320..91131956 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java @@ -1,22 +1,17 @@ package com.zeapo.pwdstore.autofill; import android.app.DialogFragment; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; +import android.content.Intent; import android.content.pm.PackageManager; -import android.database.Cursor; -import android.database.MatrixCursor; +import android.content.pm.ResolveInfo; import android.os.Bundle; +import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.SearchView; -import android.widget.SimpleCursorAdapter; -import android.widget.TextView; +import android.support.v7.widget.SearchView; +import android.view.Menu; +import android.view.MenuItem; import com.zeapo.pwdstore.R; @@ -24,7 +19,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; public class AutofillPreferenceActivity extends AppCompatActivity { @@ -43,104 +37,64 @@ public class AutofillPreferenceActivity extends AppCompatActivity { layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); - - // apps for which the user has custom settings should be in the recycler + + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + List allApps = getPackageManager().queryIntentActivities(intent, 0); final PackageManager pm = getPackageManager(); - SharedPreferences prefs - = getSharedPreferences("autofill", Context.MODE_PRIVATE); - Map prefApps = prefs.getAll(); - ArrayList apps = new ArrayList<>(); - for (String packageName : prefApps.keySet()) { - try { - apps.add(pm.getApplicationInfo(packageName, 0)); - } catch (PackageManager.NameNotFoundException e) { - // remove invalid entries (from uninstalled apps?) - SharedPreferences.Editor editor = prefs.edit(); - editor.remove(packageName).apply(); - } - } - Collections.sort(apps, new Comparator() { + Collections.sort(allApps, new Comparator() { @Override - public int compare(ApplicationInfo lhs, ApplicationInfo rhs) { + public int compare(ResolveInfo lhs, ResolveInfo rhs) { return lhs.loadLabel(pm).toString().compareTo(rhs.loadLabel(pm).toString()); } }); - recyclerAdapter = new AutofillRecyclerAdapter(apps, pm, this); + recyclerAdapter = new AutofillRecyclerAdapter(new ArrayList<>(allApps), pm, this); recyclerView.setAdapter(recyclerAdapter); - // show the search bar by default but don't open the keyboard - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - final SearchView searchView = (SearchView) findViewById(R.id.app_search); - searchView.clearFocus(); - - // create search suggestions of apps with icons & names - final SimpleCursorAdapter.ViewBinder viewBinder = new SimpleCursorAdapter.ViewBinder() { - @Override - public boolean setViewValue(View view, Cursor cursor, int columnIndex) { - if (view instanceof TextView) { - ((TextView) view).setText(cursor.getString(columnIndex)); - } else if (view instanceof ImageView) { - try { - ((ImageView) view).setImageDrawable(pm.getApplicationIcon(cursor.getString(columnIndex))); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - return false; - } - } - return true; - } - }; - - final List allApps = pm.getInstalledApplications(0); - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - return false; - } - - @Override - public boolean onQueryTextChange(String newText) { - // should be a better/faster way to do this? - // TODO do this async probably. it lags. - MatrixCursor matrixCursor = new MatrixCursor(new String[]{"_id", "package", "label"}); - for (ApplicationInfo applicationInfo : allApps) { - if (applicationInfo.loadLabel(pm).toString().toLowerCase().contains(newText.toLowerCase())) { - matrixCursor.addRow(new Object[]{0, applicationInfo.packageName, applicationInfo.loadLabel(pm)}); - } - } - SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(AutofillPreferenceActivity.this - , R.layout.app_list_item, matrixCursor, new String[]{"package", "label"} - , new int[]{android.R.id.icon1, android.R.id.text1}, 0); - simpleCursorAdapter.setViewBinder(viewBinder); - searchView.setSuggestionsAdapter(simpleCursorAdapter); - return false; - } - }); - - searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { - @Override - public boolean onSuggestionSelect(int position) { - return false; - } - - @Override - public boolean onSuggestionClick(int position) { - Cursor cursor = searchView.getSuggestionsAdapter().getCursor(); - String packageName = cursor.getString(1); - String appName = cursor.getString(2); - showDialog(packageName, appName); - return true; - } - }); - setTitle("Autofill Apps"); Bundle extras = getIntent().getExtras(); if (extras != null) { + recyclerView.scrollToPosition(recyclerAdapter.getPosition(extras.getString("packageName"))); showDialog(extras.getString("packageName"), extras.getString("appName")); } } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.autofill_preference, menu); + MenuItem searchItem = menu.findItem(R.id.action_search); + SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + return true; + } + }); + + // When using the support library, the setOnActionExpandListener() method is + // static and accepts the MenuItem object as an argument + MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + }); + return super.onCreateOptionsMenu(menu); + } + public void showDialog(String packageName, String appName) { DialogFragment df = new AutofillFragment(); Bundle args = new Bundle(); 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 14530879..7c735f18 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java @@ -2,14 +2,11 @@ package com.zeapo.pwdstore.autofill; import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.preference.PreferenceManager; +import android.content.pm.ResolveInfo; import android.support.v7.view.ActionMode; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -18,19 +15,14 @@ import android.widget.TextView; import com.zeapo.pwdstore.R; import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; public class AutofillRecyclerAdapter extends RecyclerView.Adapter { - private ArrayList apps; + private ArrayList apps; private PackageManager pm; private AutofillPreferenceActivity activity; - private final Set selectedItems; private ActionMode actionMode; - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public View view; public TextView name; public TextView secondary; @@ -44,38 +36,19 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter apps, PackageManager pm, AutofillPreferenceActivity activity) { + public AutofillRecyclerAdapter(ArrayList apps, PackageManager pm, AutofillPreferenceActivity activity) { this.apps = apps; this.pm = pm; this.activity = activity; - this.selectedItems = new TreeSet<>(Collections.reverseOrder()); } @Override @@ -87,30 +60,33 @@ public class AutofillRecyclerAdapter extends RecyclerView.Adapter - - + android:layout_height="match_parent"> + android:id="@+id/secondary_text" + android:textColor="@color/grey_600"/> diff --git a/app/src/main/res/layout/fragment_autofill.xml b/app/src/main/res/layout/fragment_autofill.xml index 6ad44a0d..e5534f41 100644 --- a/app/src/main/res/layout/fragment_autofill.xml +++ b/app/src/main/res/layout/fragment_autofill.xml @@ -13,11 +13,18 @@ android:layout_height="wrap_content" android:id="@+id/autofill_radiogroup" > + @@ -29,7 +36,7 @@ android:id="@+id/match" android:layout_gravity="center_vertical" android:checked="false" - android:layout_marginTop="8dp"/> + /> + /> diff --git a/app/src/main/res/menu/autofill_preference.xml b/app/src/main/res/menu/autofill_preference.xml new file mode 100644 index 00000000..77ce95f4 --- /dev/null +++ b/app/src/main/res/menu/autofill_preference.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index 44e38916..e8ba80cc 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -79,7 +79,7 @@