diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java index db3812b..a4a514b 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java @@ -221,7 +221,12 @@ public class AppListAdapter extends RecyclerView.Adapter mOrigList = new ArrayList<>(); + // The list of applications that is ACTUALLY displayed + // (after filtering by search query if applicable) private List mList = new ArrayList<>(); + private String mSearchQuery = null; private IShelterService mService; private Drawable mDefaultIcon; private String mLabelDisabled; @@ -281,9 +286,33 @@ public class AppListAdapter extends RecyclerView.Adapter apps) { + mOrigList.clear(); mList.clear(); mIconCache.clear(); - mList.addAll(apps); + mOrigList.addAll(apps); + notifyChange(); + } + + // null = clear search query + void setSearchQuery(String query) { + mSearchQuery = query; + notifyChange(); + } + + // Call this on ACTUAL data set change and/or search query change + private void notifyChange() { + mList.clear(); + if (mSearchQuery == null) { + // No search query, do not filter + mList.addAll(mOrigList); + } else { + // Filter by search query + mList.addAll(mOrigList.stream() + .filter((app) -> + app.getPackageName().toLowerCase().contains(mSearchQuery) + || app.getLabel().toLowerCase().contains(mSearchQuery)) + .collect(Collectors.toList())); + } notifyDataSetChanged(); } diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java index 89cdc77..0dc9a7a 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java @@ -93,6 +93,19 @@ public class AppListFragment extends BaseFragment { } }; + // Receiver for search event + private BroadcastReceiver mSearchReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String query = intent.getStringExtra("text"); + if (query == "") { + // Consider empty query as null + query = null; + } + mAdapter.setSearchQuery(query); + } + }; + static AppListFragment newInstance(IShelterService service, boolean isRemote) { AppListFragment fragment = new AppListFragment(); Bundle args = new Bundle(); @@ -119,6 +132,9 @@ public class AppListFragment extends BaseFragment { LocalBroadcastManager.getInstance(getContext()) .registerReceiver(mContextMenuClosedReceiver, new IntentFilter(MainActivity.BROADCAST_CONTEXT_MENU_CLOSED)); + LocalBroadcastManager.getInstance(getContext()) + .registerReceiver(mSearchReceiver, + new IntentFilter(MainActivity.BROADCAST_SEARCH_FILTER_CHANGED)); refresh(); } @@ -130,6 +146,8 @@ public class AppListFragment extends BaseFragment { .unregisterReceiver(mRefreshReceiver); LocalBroadcastManager.getInstance(getContext()) .unregisterReceiver(mContextMenuClosedReceiver); + LocalBroadcastManager.getInstance(getContext()) + .unregisterReceiver(mSearchReceiver); } @Nullable diff --git a/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java b/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java index d501d0a..5d0b320 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java +++ b/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java @@ -18,6 +18,7 @@ import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.SearchView; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; @@ -40,6 +41,7 @@ import net.typeblog.shelter.util.Utility; public class MainActivity extends AppCompatActivity { public static final String BROADCAST_CONTEXT_MENU_CLOSED = "net.typeblog.shelter.broadcast.CONTEXT_MENU_CLOSED"; + public static final String BROADCAST_SEARCH_FILTER_CHANGED = "net.typeblog.shelter.broadcast.SEARCH_FILTER_CHANGED"; private static final int REQUEST_PROVISION_PROFILE = 1; private static final int REQUEST_START_SERVICE_IN_WORK_PROFILE = 2; @@ -330,6 +332,24 @@ public class MainActivity extends AppCompatActivity { public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_activity_menu, menu); + + // Initialize the search button + SearchView searchView = (SearchView) menu.findItem(R.id.main_menu_search).getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + Intent intent = new Intent(BROADCAST_SEARCH_FILTER_CHANGED); + intent.putExtra("text", newText.toLowerCase().trim()); + LocalBroadcastManager.getInstance(MainActivity.this) + .sendBroadcast(intent); + return true; + } + }); return true; } diff --git a/app/src/main/res/drawable/ic_search_tinted_24dp.xml b/app/src/main/res/drawable/ic_search_tinted_24dp.xml new file mode 100644 index 0000000..d45fcbb --- /dev/null +++ b/app/src/main/res/drawable/ic_search_tinted_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/main_activity_menu.xml b/app/src/main/res/menu/main_activity_menu.xml index 3c3ec15..76b9e05 100644 --- a/app/src/main/res/menu/main_activity_menu.xml +++ b/app/src/main/res/menu/main_activity_menu.xml @@ -1,6 +1,13 @@ + + 批量操作 + 搜索 克隆到 Shelter (工作用户) 克隆到主用户 卸载 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b1e8647..d362d3a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,6 +33,7 @@ Allow Widgets in Main Profile + Search Batch Freeze Create Batch Freeze Shortcut Freeze