feature: filtering of activity list

This commit is contained in:
Adam Szalkowski 2019-10-31 16:35:56 +01:00
parent 0bef8138b6
commit 12d143155f
12 changed files with 157 additions and 28 deletions

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.szalkowski.activitylauncher"
android:versionCode="14"
android:versionName="1.8.2" >
android:versionCode="15"
android:versionName="1.9.0" >
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />

View file

@ -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<MyPackageInfo> packages;
private LayoutInflater inflater;
private List<MyPackageView> filtered;
private class MyPackageView {
private class Child {
MyActivityInfo child;
long id;
}
MyPackageInfo parent;
List<Child> 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<MyPackageView> createFilterView(String query) {
String q = query.toLowerCase();
List<MyPackageView> 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<MyPackageView> 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<MyPackageView>) results.values;
notifyDataSetChanged();
}
}
};
}
}

View file

@ -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<AllTasksListAdapter> {
protected ExpandableListView list;
public class AllTasksListFragment extends Fragment implements AllTasksListAsyncProvider.Listener<AllTasksListAdapter>, 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<AllTasksListAdapter> task, AllTasksListAdapter value) {
public void onProviderFinished(AsyncProvider<AllTasksListAdapter> 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;
}
}
}

View file

@ -51,7 +51,7 @@ public abstract class AsyncProvider<ReturnType> extends AsyncTask<Void, Integer,
protected void onPostExecute(ReturnType result) {
super.onPostExecute(result);
if (this.listener != null) {
this.listener.onProviderFininshed(this, result);
this.listener.onProviderFinished(this, result);
}
if (this.progress != null) {
@ -70,7 +70,7 @@ public abstract class AsyncProvider<ReturnType> extends AsyncTask<Void, Integer,
}
public interface Listener<ReturnType> {
void onProviderFininshed(AsyncProvider<ReturnType> task, ReturnType value);
void onProviderFinished(AsyncProvider<ReturnType> task, ReturnType value);
}
class Updater {

View file

@ -64,8 +64,8 @@ public class IconPickerDialogFragment extends DialogFragment implements IconList
}
@Override
public void onProviderFininshed(AsyncProvider<IconListAdapter> task,
IconListAdapter value) {
public void onProviderFinished(AsyncProvider<IconListAdapter> task,
IconListAdapter value) {
try {
this.grid.setAdapter(value);
} catch (Exception e) {

View file

@ -42,8 +42,8 @@ public class IconPickerFragment extends Fragment implements IconListAsyncProvide
}
@Override
public void onProviderFininshed(AsyncProvider<IconListAdapter> task,
IconListAdapter value) {
public void onProviderFinished(AsyncProvider<IconListAdapter> task,
IconListAdapter value) {
try {
this.grid.setAdapter(value);
} catch (Exception e) {

View file

@ -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()) {

View file

@ -1,14 +1,19 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/search"
android:title="@string/action_filter"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="collapseActionView|ifRoom"
android:actionViewClass="android.widget.SearchView" />
<item
android:id="@+id/action_view_source"
android:showAsAction="never"
android:title="@string/action_view_source"></item>
android:title="@string/action_view_source" />
<item
android:id="@+id/action_view_translation"
android:showAsAction="never"
android:title="@string/action_view_translation"></item>
android:title="@string/action_view_translation" />
<item
android:id="@+id/action_view_bugs"
android:showAsAction="never"
android:title="@string/action_view_bugs"></item>
android:title="@string/action_view_bugs" />
</menu>

View file

@ -1,5 +1,5 @@
<resources>
<string name="url_source" translatable="false">https://github.com/butzist/ActivityLauncher</string>
<string name="url_translation" translatable="false">http://crowdin.net/project/activitylauncher/invite</string>
<string name="url_translation" translatable="false">https://crowdin.net/project/activitylauncher/invite</string>
<string name="url_bugs" translatable="false">https://github.com/butzist/ActivityLauncher/issues</string>
</resources>

View file

@ -28,4 +28,6 @@
<string name="action_view_translation">Help Translating!</string>
<string name="action_view_bugs">Report A Problem</string>
<string name="error_no_default_activity">Package does not have a default activity - try to select one explicitly</string>
<string name="action_filter">Filter...</string>
<string name="filter_hint">package/action</string>
</resources>

View file

@ -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'
}
}

View file

@ -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