diff --git a/app/src/main/java/deltazero/amarok/ui/AppListAdapter.java b/app/src/main/java/deltazero/amarok/ui/AppListAdapter.java index 20565093..f578875a 100644 --- a/app/src/main/java/deltazero/amarok/ui/AppListAdapter.java +++ b/app/src/main/java/deltazero/amarok/ui/AppListAdapter.java @@ -20,9 +20,7 @@ import com.google.android.material.checkbox.MaterialCheckBox; -import java.util.List; import java.util.Objects; -import java.util.Set; import deltazero.amarok.PrefMgr; import deltazero.amarok.R; @@ -30,12 +28,10 @@ public class AppListAdapter extends ListAdapter { - private final PackageManager pkgMgr; private final PrefMgr prefMgr; private final AppInfoUtil appInfoUtil; private final LayoutInflater inflater; - private Set hiddenApps; private static final HandlerThread backgroundThread = new HandlerThread("APP_ADAPTER_THREAD"); private final Handler backgroundHandler; @@ -63,14 +59,13 @@ public boolean areContentsTheSame(@NonNull AppInfo oldItem, @NonNull AppInfo new backgroundThread.start(); backgroundHandler = new Handler(backgroundThread.getLooper()); - pkgMgr = activity.getPackageManager(); prefMgr = new PrefMgr(activity); appInfoUtil = new AppInfoUtil(activity); this.activity = activity; this.srLayout = srLayout; - update(null, true); + update(null, true, false); } @NonNull @@ -92,7 +87,7 @@ public void onBindViewHolder(@NonNull AppListAdapter.AppListHolder holder, int p } - public void update(String query, boolean fullUpdate) { + public void update(String query, boolean fullUpdate, boolean includeSystemApps) { // Refreshing thread lock if (isRefreshing) return; @@ -102,21 +97,10 @@ public void update(String query, boolean fullUpdate) { backgroundHandler.post(() -> { // Refresh installed apps - if (fullUpdate) appInfoUtil.update(); - // Get app info - List lsAppInfo = appInfoUtil.getInstalledApps(query); - // Sort with app name - hiddenApps = prefMgr.getHideApps(); - lsAppInfo.sort((o1, o2) -> { - if (hiddenApps.contains(o1.packageName) && !hiddenApps.contains(o2.packageName)) - return -1; - if (hiddenApps.contains(o2.packageName) && !hiddenApps.contains(o1.packageName)) - return 1; - return (o1.label.compareTo(o2.label)); - }); + if (fullUpdate) appInfoUtil.refresh(); // Notify update activity.runOnUiThread(() -> { - submitList(lsAppInfo); + submitList(appInfoUtil.getFilteredApps(query, includeSystemApps)); srLayout.setRefreshing(false); isRefreshing = false; }); @@ -146,7 +130,7 @@ public AppListHolder(View view) { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { String appPkgName = getCurrentList().get(getLayoutPosition()).packageName; - hiddenApps = prefMgr.getHideApps(); + var hiddenApps = prefMgr.getHideApps(); if (buttonView.isChecked()) { hiddenApps.add(appPkgName); diff --git a/app/src/main/java/deltazero/amarok/ui/SetHideAppActivity.java b/app/src/main/java/deltazero/amarok/ui/SetHideAppActivity.java index 8bab8284..0a159496 100644 --- a/app/src/main/java/deltazero/amarok/ui/SetHideAppActivity.java +++ b/app/src/main/java/deltazero/amarok/ui/SetHideAppActivity.java @@ -1,10 +1,15 @@ package deltazero.amarok.ui; import android.os.Bundle; +import android.util.Log; import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; +import androidx.core.view.MenuProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -20,6 +25,8 @@ public class SetHideAppActivity extends AppCompatActivity { private MaterialToolbar tbToolBar; private SwipeRefreshLayout srLayout; + private boolean showSystemApps = false; + private String query = null; @Override @@ -41,36 +48,51 @@ protected void onCreate(Bundle savedInstanceState) { tbToolBar.setNavigationOnClickListener(v -> finish()); // Setup onRefresh listener - srLayout.setOnRefreshListener(() -> adapter.update(query, true)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_hideapp, menu); - - SearchView searchView = (SearchView) menu.findItem(R.id.action_search_app).getActionView(); - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - private boolean once = false; + srLayout.setOnRefreshListener(() -> adapter.update(query, true, showSystemApps)); + // Setup menu + addMenuProvider(new MenuProvider() { @Override - public boolean onQueryTextSubmit(String query) { - return true; + public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) { + menuInflater.inflate(R.menu.menu_hideapp, menu); + + menu.findItem(R.id.display_system_apps).setChecked(showSystemApps); + + SearchView searchView = (SearchView) menu.findItem(R.id.action_search_app).getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + private boolean once = false; + + @Override + public boolean onQueryTextSubmit(String query) { + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + query = newText.isEmpty() ? null : newText; + if (once) adapter.update(newText, false, showSystemApps); + else once = true; + return true; + } + }); + searchView.setOnCloseListener(() -> { + query = null; + adapter.update(null, false, showSystemApps); + return true; + }); } @Override - public boolean onQueryTextChange(String newText) { - query = newText.isEmpty() ? null : newText; - if (once) adapter.update(newText, false); - else once = true; - return true; + public boolean onMenuItemSelected(@NonNull MenuItem menuItem) { + if (menuItem.getItemId() == R.id.display_system_apps) { + showSystemApps = !showSystemApps; + menuItem.setChecked(showSystemApps); + adapter.update(query, false, showSystemApps); + return true; + } + return false; } }); - searchView.setOnCloseListener(() -> { - query = null; - adapter.update(null, false); - return true; - }); - - return super.onCreateOptionsMenu(menu); } + } \ No newline at end of file diff --git a/app/src/main/java/deltazero/amarok/utils/AppInfoUtil.java b/app/src/main/java/deltazero/amarok/utils/AppInfoUtil.java index 93e959d0..7c8f8c9e 100644 --- a/app/src/main/java/deltazero/amarok/utils/AppInfoUtil.java +++ b/app/src/main/java/deltazero/amarok/utils/AppInfoUtil.java @@ -8,18 +8,24 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.util.Log; import androidx.annotation.NonNull; import java.util.ArrayList; import java.util.List; +import java.util.Set; + +import deltazero.amarok.PrefMgr; public class AppInfoUtil { private final PackageManager pkgMgr; - private List appInfoList = new ArrayList<>(); + private final PrefMgr prefMgr; + private final List appInfoList = new ArrayList<>(); public AppInfoUtil(Context context) { pkgMgr = context.getPackageManager(); + prefMgr = new PrefMgr(context); } private static boolean containsIgnoreCase(String str, String searchStr) { @@ -36,37 +42,53 @@ private static boolean containsIgnoreCase(String str, String searchStr) { return false; } - public void update() { + public void refresh() { appInfoList.clear(); + Set hiddenApps = prefMgr.getHideApps(); + // Get applications info List installedApplications = pkgMgr.getInstalledApplications(GET_META_DATA | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES); for (ApplicationInfo applicationInfo : installedApplications) { - // Ignore system application - if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo.FLAG_SYSTEM) - continue; - - // Ignore Amarok itself + // Filter out Amarok itself if (applicationInfo.packageName.contains("deltazero.amarok")) continue; var appInfo = new AppInfo( applicationInfo.packageName, pkgMgr.getApplicationLabel(applicationInfo).toString(), + (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo.FLAG_SYSTEM, pkgMgr.getApplicationIcon(applicationInfo) ); appInfoList.add(appInfo); } + + // Sort with app name, and stick the hidden apps to the top + appInfoList.sort((o1, o2) -> { + if (hiddenApps.contains(o1.packageName) && !hiddenApps.contains(o2.packageName)) + return -1; + if (hiddenApps.contains(o2.packageName) && !hiddenApps.contains(o1.packageName)) + return 1; + return (o1.label.compareTo(o2.label)); + }); } - public List getInstalledApps(String query) { + public List getFilteredApps(String query, boolean includeSystemApps) { + Set hiddenApps = prefMgr.getHideApps(); + Log.d("AppInfoUtil", "Hidden apps: " + hiddenApps.toString()); List queryAppInfoList = new ArrayList<>(); - for (AppInfo appInfo: appInfoList) { - // Apply query filter - if (query == null || query.isEmpty() || - containsIgnoreCase(appInfo.packageName, query) || containsIgnoreCase(appInfo.label, query)) + for (AppInfo appInfo : appInfoList) { + + boolean query_filter_result = (query == null || query.isEmpty()) + || containsIgnoreCase(appInfo.packageName, query) || containsIgnoreCase(appInfo.label, query); + + boolean system_filter_result = hiddenApps.contains(appInfo.packageName) /* If the app is hidden, show it regardless of whether it is a system app or not. */ + || includeSystemApps /* Skip this filter if user enable `Display system apps` */ + || !appInfo.isSystemApp; + + if (query_filter_result && system_filter_result) queryAppInfoList.add(appInfo); } return queryAppInfoList; @@ -77,11 +99,13 @@ public static class AppInfo { public String packageName; @NonNull public String label; + public boolean isSystemApp; public Drawable icon; - public AppInfo(@NonNull String packageName, @NonNull String label, Drawable icon) { + public AppInfo(@NonNull String packageName, @NonNull String label, boolean isSystemApp, Drawable icon) { this.packageName = packageName; this.label = label; + this.isSystemApp = isSystemApp; this.icon = icon; } } diff --git a/app/src/main/res/drawable/ic_filter.xml b/app/src/main/res/drawable/ic_filter.xml new file mode 100644 index 00000000..7a836d5a --- /dev/null +++ b/app/src/main/res/drawable/ic_filter.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml index 8f2078c3..e437f2c9 100644 --- a/app/src/main/res/drawable/ic_search.xml +++ b/app/src/main/res/drawable/ic_search.xml @@ -1,10 +1,10 @@ - + android:pathData="M796,839L533,576Q503,602 463.04,616.5Q423.08,631 378,631Q269.84,631 194.92,556Q120,481 120,375Q120,269 195,194Q270,119 376.5,119Q483,119 557.5,194Q632,269 632,375.15Q632,418 618,458Q604,498 576,533L840,795L796,839ZM377,571Q458.25,571 515.13,513.5Q572,456 572,375Q572,294 515.13,236.5Q458.25,179 377,179Q294.92,179 237.46,236.5Q180,294 180,375Q180,456 237.46,513.5Q294.92,571 377,571Z"/> + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_hideapp.xml b/app/src/main/res/menu/menu_hideapp.xml index abe89e43..40d63e63 100644 --- a/app/src/main/res/menu/menu_hideapp.xml +++ b/app/src/main/res/menu/menu_hideapp.xml @@ -5,7 +5,21 @@ android:id="@+id/action_search_app" android:icon="@drawable/ic_search" android:title="@string/search" - app:showAsAction="always|collapseActionView" - app:actionViewClass="androidx.appcompat.widget.SearchView" /> + app:actionViewClass="androidx.appcompat.widget.SearchView" + app:showAsAction="always|collapseActionView" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index ed79b389..70c5c82c 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -130,4 +130,6 @@ 尝试恢复所有隐藏的文件与应用。仅在出现问题时使用。 尝试恢复所有隐藏的文件与应用?\n\n警告:此功能可能导致文件损坏。请仅当无法正常取消隐藏时使用。 正在尝试取消隐藏。请稍后。 + 筛选 + 显示系统应用 \ 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 582c3770..0ea23b09 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -141,4 +141,6 @@ Try to restore everything. Use this option only when you run into troubles. Try to restore everything?\n\nWARNING: This option may corrupt your files. Only use it when you encounter trouble and cannot perform the \"unhide\" function normally. Executing force unhide. Please sit tight. + Filter + Display system apps \ No newline at end of file