diff --git a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java index 35f8e0bc..d0d54209 100644 --- a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java +++ b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java @@ -31,14 +31,17 @@ import android.content.pm.PackageManager; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -84,16 +87,21 @@ import rikka.core.res.ResourcesKt; import rikka.widget.switchbar.SwitchBar; @SuppressLint("NotifyDataSetChanged") -public class ScopeAdapter extends RecyclerView.Adapter implements Filterable { +public class ScopeAdapter extends RecyclerView.Adapter implements Filterable, Handler.Callback { private final AppListActivity activity; private final PackageManager pm; private final SharedPreferences preferences; + private final Handler loadAppListHandler; + private final String modulePackageName; private final String moduleName; + private final HashSet recommendedList = new HashSet<>(); private final HashSet checkedList = new HashSet<>(); private final List searchList = new ArrayList<>(); + private List showList = new ArrayList<>(); + private final SwitchBar.OnCheckedChangeListener switchBarOnCheckedChangeListener = new SwitchBar.OnCheckedChangeListener() { @Override public boolean onCheckedChanged(SwitchBar view, boolean isChecked) { @@ -105,7 +113,19 @@ public class ScopeAdapter extends RecyclerView.Adapter return true; } }; - private List showList = new ArrayList<>(); + private final Runnable dataReadyRunnable = new Runnable() { + @Override + public void run() { + synchronized (this) { + activity.binding.progress.setIndeterminate(false); + activity.binding.swipeRefreshLayout.setRefreshing(false); + String queryStr = activity.searchView != null ? activity.searchView.getQuery().toString() : ""; + getFilter().filter(queryStr); + this.notify(); + } + } + }; + private ApplicationInfo selectedInfo; private boolean refreshing = false; private boolean enabled = true; @@ -114,6 +134,9 @@ public class ScopeAdapter extends RecyclerView.Adapter this.activity = activity; this.moduleName = moduleName; this.modulePackageName = modulePackageName; + HandlerThread handlerThread = new HandlerThread("appList"); + handlerThread.start(); + loadAppListHandler = new Handler(handlerThread.getLooper(), this); preferences = App.getPreferences(); pm = activity.getPackageManager(); refresh(false); @@ -126,57 +149,6 @@ public class ScopeAdapter extends RecyclerView.Adapter return new ViewHolder(v); } - private void loadApps(boolean force) { - List appList = AppHelper.getAppList(force); - checkedList.clear(); - recommendedList.clear(); - searchList.clear(); - showList.clear(); - - checkedList.addAll(ConfigManager.getModuleScope(modulePackageName)); - HashSet installedList = new HashSet<>(); - List scopeList = ModuleUtil.getInstance().getModule(modulePackageName).getScopeList(); - boolean emptyCheckedList = checkedList.isEmpty(); - for (PackageInfo info : appList) { - int uid = info.applicationInfo.uid; - if (info.packageName.equals("android") && uid / 100000 != 0) { - continue; - } - - ApplicationWithEquals application = new ApplicationWithEquals(info.packageName, uid / 100000); - - installedList.add(application); - - if (scopeList != null && scopeList.contains(info.packageName)) { - recommendedList.add(application); - if (emptyCheckedList) { - checkedList.add(application); - } - } - - if (shouldHideApp(info, application)) { - continue; - } - - AppInfo appInfo = new AppInfo(); - appInfo.packageInfo = info; - appInfo.label = getAppLabel(info.applicationInfo, pm); - appInfo.application = application; - appInfo.packageName = info.packageName; - appInfo.applicationInfo = info.applicationInfo; - searchList.add(appInfo); - } - checkedList.retainAll(installedList); - if (emptyCheckedList) { - ConfigManager.setModuleScope(modulePackageName, checkedList); - } - showList = sortApps(searchList); - synchronized (this) { - refreshing = false; - } - activity.onDataReady(); - } - private boolean shouldHideApp(PackageInfo info, ApplicationWithEquals app) { if (info.packageName.equals(this.modulePackageName)) { return true; @@ -491,6 +463,7 @@ public class ScopeAdapter extends RecyclerView.Adapter } refreshing = true; } + loadAppListHandler.removeMessages(0); if (!force) { activity.binding.progress.setVisibility(View.INVISIBLE); activity.binding.progress.setIndeterminate(true); @@ -500,7 +473,7 @@ public class ScopeAdapter extends RecyclerView.Adapter activity.binding.masterSwitch.setOnCheckedChangeListener(null); activity.binding.masterSwitch.setChecked(enabled); activity.binding.masterSwitch.setOnCheckedChangeListener(switchBarOnCheckedChangeListener); - AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> loadApps(force)); + loadAppListHandler.sendMessage(Message.obtain(loadAppListHandler, 0, force)); } protected void onCheckedChange(CompoundButton buttonView, boolean isChecked, AppInfo appInfo) { @@ -524,6 +497,70 @@ public class ScopeAdapter extends RecyclerView.Adapter } } + @Override + public boolean handleMessage(@NonNull Message msg) { + if (msg.what != 0) { + return false; + } + try { + List appList = AppHelper.getAppList((Boolean) msg.obj); + checkedList.clear(); + recommendedList.clear(); + searchList.clear(); + showList.clear(); + + checkedList.addAll(ConfigManager.getModuleScope(modulePackageName)); + HashSet installedList = new HashSet<>(); + List scopeList = ModuleUtil.getInstance().getModule(modulePackageName).getScopeList(); + boolean emptyCheckedList = checkedList.isEmpty(); + for (PackageInfo info : appList) { + int uid = info.applicationInfo.uid; + if (info.packageName.equals("android") && uid / 100000 != 0) { + continue; + } + + ApplicationWithEquals application = new ApplicationWithEquals(info.packageName, uid / 100000); + + installedList.add(application); + + if (scopeList != null && scopeList.contains(info.packageName)) { + recommendedList.add(application); + if (emptyCheckedList) { + checkedList.add(application); + } + } + + if (shouldHideApp(info, application)) { + continue; + } + + AppInfo appInfo = new AppInfo(); + appInfo.packageInfo = info; + appInfo.label = info.applicationInfo.loadLabel(pm); + appInfo.application = application; + appInfo.packageName = info.packageName; + appInfo.applicationInfo = info.applicationInfo; + searchList.add(appInfo); + } + checkedList.retainAll(installedList); + if (emptyCheckedList) { + ConfigManager.setModuleScope(modulePackageName, checkedList); + } + showList = sortApps(searchList); + synchronized (dataReadyRunnable) { + synchronized (this) { + refreshing = false; + } + activity.runOnUiThread(dataReadyRunnable); + dataReadyRunnable.wait(); + } + return true; + } catch (Exception e) { + Log.e(App.TAG, Log.getStackTraceString(e)); + return false; + } + } + static class ViewHolder extends RecyclerView.ViewHolder { View root; @@ -597,10 +634,6 @@ public class ScopeAdapter extends RecyclerView.Adapter } } - public static String getAppLabel(ApplicationInfo info, PackageManager pm) { - return info.loadLabel(pm).toString(); - } - public static class AppInfo { public PackageInfo packageInfo; public ApplicationWithEquals application; diff --git a/app/src/main/java/org/lsposed/manager/ui/activity/AppListActivity.java b/app/src/main/java/org/lsposed/manager/ui/activity/AppListActivity.java index 75dbb1d6..c42a2a60 100644 --- a/app/src/main/java/org/lsposed/manager/ui/activity/AppListActivity.java +++ b/app/src/main/java/org/lsposed/manager/ui/activity/AppListActivity.java @@ -44,10 +44,11 @@ import org.lsposed.manager.databinding.ActivityAppListBinding; import org.lsposed.manager.ui.activity.base.BaseActivity; import org.lsposed.manager.util.BackupUtils; import org.lsposed.manager.util.LinearLayoutManagerFix; + import rikka.recyclerview.RecyclerViewKt; public class AppListActivity extends BaseActivity { - private SearchView searchView; + public SearchView searchView; private ScopeAdapter scopeAdapter; private SearchView.OnQueryTextListener searchListener; @@ -164,15 +165,6 @@ public class AppListActivity extends BaseActivity { return super.onCreateOptionsMenu(menu); } - public void onDataReady() { - runOnUiThread(() -> { - binding.progress.setIndeterminate(false); - binding.swipeRefreshLayout.setRefreshing(false); - String queryStr = searchView != null ? searchView.getQuery().toString() : ""; - scopeAdapter.getFilter().filter(queryStr); - }); - } - @Override public boolean onContextItemSelected(@NonNull MenuItem item) { if (scopeAdapter.onContextItemSelected(item)) {