From 12d143155fa6d4a0eb10d0ac446db43689e40cdb Mon Sep 17 00:00:00 2001 From: Adam Szalkowski Date: Thu, 31 Oct 2019 16:35:56 +0100 Subject: [PATCH] feature: filtering of activity list --- .../src/main/AndroidManifest.xml | 4 +- .../activitylauncher/AllTasksListAdapter.java | 91 +++++++++++++++++-- .../AllTasksListFragment.java | 23 ++++- .../activitylauncher/AsyncProvider.java | 4 +- .../IconPickerDialogFragment.java | 4 +- .../activitylauncher/IconPickerFragment.java | 4 +- .../activitylauncher/MainActivity.java | 34 ++++++- .../src/main/res/menu/main.xml | 11 ++- .../src/main/res/values/defaults.xml | 2 +- .../src/main/res/values/strings.xml | 2 + build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 12 files changed, 157 insertions(+), 28 deletions(-) diff --git a/ActivityLauncherApp/src/main/AndroidManifest.xml b/ActivityLauncherApp/src/main/AndroidManifest.xml index ff0981d..ec8167e 100644 --- a/ActivityLauncherApp/src/main/AndroidManifest.xml +++ b/ActivityLauncherApp/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="15" + android:versionName="1.9.0" > diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListAdapter.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListAdapter.java index d287957..78a42c2 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListAdapter.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListAdapter.java @@ -8,6 +8,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.ImageView; import android.widget.TextView; @@ -15,10 +17,34 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class AllTasksListAdapter extends BaseExpandableListAdapter { +public class AllTasksListAdapter extends BaseExpandableListAdapter implements Filterable { private PackageManager pm; private List packages; private LayoutInflater inflater; + private List filtered; + + private class MyPackageView { + private class Child { + MyActivityInfo child; + long id; + } + MyPackageInfo parent; + List children; + long id; + + MyPackageView(MyPackageInfo parent, long id) { + this.parent = parent; + this.id = id; + this.children = new ArrayList<>(); + } + + void add(MyActivityInfo activity, long id) { + Child child = new Child(); + child.child = activity; + child.id = id; + this.children.add(child); + } + } AllTasksListAdapter(Context context) { this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -46,16 +72,46 @@ public class AllTasksListAdapter extends BaseExpandableListAdapter { } Collections.sort(this.packages); + this.filtered = createFilterView(""); + + } + + private List createFilterView(String query) { + String q = query.toLowerCase(); + List result = new ArrayList<>(); + for (int j = 0; j < this.packages.size(); ++j) { + MyPackageInfo parent = this.packages.get(j); + MyPackageView entry = new MyPackageView(parent, j); + + for (int i = 0; i < parent.getActivitiesCount(); ++i) { + MyActivityInfo child = parent.getActivity(i); + if (child.name.toLowerCase().contains(q) || + child.component_name.flattenToString().toLowerCase().contains(q) || + child.icon_resource_name != null && child.icon_resource_name.toLowerCase().contains(q)) { + entry.add(child, i); + } + } + + if (!entry.children.isEmpty() || + parent.name.toLowerCase().contains(q) || + parent.package_name.toLowerCase().contains(q) || + parent.icon_resource_name != null && parent.icon_resource_name.contains(q) + ) { + result.add(entry); + } + } + + return result; } @Override public Object getChild(int groupPosition, int childPosition) { - return this.packages.get(groupPosition).getActivity(childPosition); + return this.filtered.get(groupPosition).children.get(childPosition).child; } @Override public long getChildId(int groupPosition, int childPosition) { - return childPosition; + return this.filtered.get(groupPosition).children.get(childPosition).id; } @Override @@ -77,22 +133,22 @@ public class AllTasksListAdapter extends BaseExpandableListAdapter { @Override public int getChildrenCount(int groupPosition) { - return this.packages.get(groupPosition).getActivitiesCount(); + return this.filtered.get(groupPosition).children.size(); } @Override public Object getGroup(int groupPosition) { - return this.packages.get(groupPosition); + return this.filtered.get(groupPosition).parent; } @Override public int getGroupCount() { - return this.packages.size(); + return this.filtered.size(); } @Override public long getGroupId(int groupPosition) { - return groupPosition; + return this.filtered.get(groupPosition).id; } @Override @@ -119,4 +175,25 @@ public class AllTasksListAdapter extends BaseExpandableListAdapter { return true; } + @Override + public Filter getFilter() { + return new Filter() { + @Override + protected FilterResults performFiltering(CharSequence constraint) { + List result = createFilterView(constraint.toString()); + FilterResults wrapped = new FilterResults(); + wrapped.values = result; + wrapped.count = result.size(); + return wrapped; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + if (results != null) { + filtered = (List) results.values; + notifyDataSetChanged(); + } + } + }; + } } diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListFragment.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListFragment.java index 6240af7..166b9c0 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListFragment.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AllTasksListFragment.java @@ -14,6 +14,8 @@ import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import android.widget.ExpandableListView.OnChildClickListener; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.Toast; import androidx.annotation.NonNull; @@ -22,8 +24,12 @@ import androidx.fragment.app.Fragment; import org.thirdparty.LauncherIconCreator; -public class AllTasksListFragment extends Fragment implements AllTasksListAsyncProvider.Listener { - protected ExpandableListView list; +public class AllTasksListFragment extends Fragment implements AllTasksListAsyncProvider.Listener, Filterable { + private ExpandableListView list; + + AllTasksListFragment() { + super(); + } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -41,6 +47,7 @@ public class AllTasksListFragment extends Fragment implements AllTasksListAsyncP return false; } }); + this.list.setTextFilterEnabled(true); AllTasksListAsyncProvider provider = new AllTasksListAsyncProvider(getActivity(), this); provider.execute(); @@ -129,11 +136,21 @@ public class AllTasksListFragment extends Fragment implements AllTasksListAsyncP } @Override - public void onProviderFininshed(AsyncProvider task, AllTasksListAdapter value) { + public void onProviderFinished(AsyncProvider task, AllTasksListAdapter value) { try { this.list.setAdapter(value); } catch (Exception e) { Toast.makeText(getActivity(), R.string.error_tasks, Toast.LENGTH_SHORT).show(); } } + + @Override + public Filter getFilter() { + AllTasksListAdapter adapter = (AllTasksListAdapter) this.list.getExpandableListAdapter(); + if (adapter != null) { + return adapter.getFilter(); + } else { + return null; + } + } } \ No newline at end of file diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AsyncProvider.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AsyncProvider.java index d760852..cb27f7e 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AsyncProvider.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/AsyncProvider.java @@ -51,7 +51,7 @@ public abstract class AsyncProvider extends AsyncTask extends AsyncTask { - void onProviderFininshed(AsyncProvider task, ReturnType value); + void onProviderFinished(AsyncProvider task, ReturnType value); } class Updater { diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerDialogFragment.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerDialogFragment.java index 03d7692..79f239a 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerDialogFragment.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerDialogFragment.java @@ -64,8 +64,8 @@ public class IconPickerDialogFragment extends DialogFragment implements IconList } @Override - public void onProviderFininshed(AsyncProvider task, - IconListAdapter value) { + public void onProviderFinished(AsyncProvider task, + IconListAdapter value) { try { this.grid.setAdapter(value); } catch (Exception e) { diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerFragment.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerFragment.java index 60c72da..fcfdcc2 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerFragment.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/IconPickerFragment.java @@ -42,8 +42,8 @@ public class IconPickerFragment extends Fragment implements IconListAsyncProvide } @Override - public void onProviderFininshed(AsyncProvider task, - IconListAdapter value) { + public void onProviderFinished(AsyncProvider task, + IconListAdapter value) { try { this.grid.setAdapter(value); } catch (Exception e) { diff --git a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/MainActivity.java b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/MainActivity.java index 717e549..a6f0675 100644 --- a/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/MainActivity.java +++ b/ActivityLauncherApp/src/main/java/de/szalkowski/activitylauncher/MainActivity.java @@ -9,14 +9,17 @@ import android.os.Build; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.SearchView; import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; public class MainActivity extends FragmentActivity { - protected final String LOG = "de.szalkowski.activitylauncher.MainActivity"; + private final String LOG = "de.szalkowski.activitylauncher.MainActivity"; + private Filterable filterTarget = null; @Override protected void onCreate(Bundle savedInstanceState) { @@ -28,9 +31,10 @@ public class MainActivity extends FragmentActivity { dialog.show(getSupportFragmentManager(), "DisclaimerDialogFragment"); } - Fragment fragment = new AllTasksListFragment(); + AllTasksListFragment fragment = new AllTasksListFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.container, fragment).commit(); + filterTarget = fragment; } /** @@ -57,9 +61,33 @@ public class MainActivity extends FragmentActivity { public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); + + SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView(); + searchView.setQueryHint(this.getText(R.string.filter_hint)); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + onFilter(query); + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + onFilter(newText); + return true; + } + }); + return true; } + private void onFilter(String query) { + Filter filter = filterTarget.getFilter(); + if (filter != null) { + filter.filter(query); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { diff --git a/ActivityLauncherApp/src/main/res/menu/main.xml b/ActivityLauncherApp/src/main/res/menu/main.xml index b8eef63..e387f17 100644 --- a/ActivityLauncherApp/src/main/res/menu/main.xml +++ b/ActivityLauncherApp/src/main/res/menu/main.xml @@ -1,14 +1,19 @@ + + android:title="@string/action_view_source" /> + android:title="@string/action_view_translation" /> + android:title="@string/action_view_bugs" /> \ No newline at end of file diff --git a/ActivityLauncherApp/src/main/res/values/defaults.xml b/ActivityLauncherApp/src/main/res/values/defaults.xml index 1bc4984..8aa8289 100644 --- a/ActivityLauncherApp/src/main/res/values/defaults.xml +++ b/ActivityLauncherApp/src/main/res/values/defaults.xml @@ -1,5 +1,5 @@ https://github.com/butzist/ActivityLauncher - http://crowdin.net/project/activitylauncher/invite + https://crowdin.net/project/activitylauncher/invite https://github.com/butzist/ActivityLauncher/issues diff --git a/ActivityLauncherApp/src/main/res/values/strings.xml b/ActivityLauncherApp/src/main/res/values/strings.xml index a6d2154..3b575f3 100644 --- a/ActivityLauncherApp/src/main/res/values/strings.xml +++ b/ActivityLauncherApp/src/main/res/values/strings.xml @@ -28,4 +28,6 @@ Help Translating! Report A Problem Package does not have a default activity - try to select one explicitly + Filter... + package/action diff --git a/build.gradle b/build.gradle index 3188740..31d8aaa 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:3.5.1' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a9e1d63..52c885a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Apr 20 11:06:49 CEST 2019 +#Thu Oct 31 11:15:14 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip