Improve MagiskHide app listing

- Prevent platform apps from showing up
- Add new option to toggle whether to show system apps
This commit is contained in:
topjohnwu 2019-01-31 23:40:33 -05:00
parent a60710e3bb
commit da13b5dbf2
5 changed files with 104 additions and 58 deletions

View File

@ -66,6 +66,7 @@ public class Config {
public static final String DARK_THEME = "dark_theme";
public static final String ETAG_KEY = "ETag";
public static final String REPO_ORDER = "repo_order";
public static final String SHOW_SYSTEM_APP = "show_system";
}
public static class Value {
@ -108,16 +109,17 @@ public class Config {
// prefs bool
defs.putBoolean(Key.CHECK_UPDATES, true);
// defs.putBoolean(Const.Key.DARK_THEME, false);
// defs.putBoolean(Const.Key.SU_REAUTH, false);
// defs.putBoolean(Const.Key.MAGISKHIDE, false);
// defs.putBoolean(Const.Key.COREONLY, false);
// defs.putBoolean(Key.DARK_THEME, false);
// defs.putBoolean(Key.SU_REAUTH, false);
// defs.putBoolean(Key.MAGISKHIDE, false);
// defs.putBoolean(Key.COREONLY, false);
// defs.putBoolean(Key.SHOW_SYSTEM_APP, false);
// prefs string
defs.putString(Key.CUSTOM_CHANNEL, "");
defs.putString(Key.BOOT_FORMAT, ".img");
defs.putString(Key.LOCALE, "");
// defs.putString(Const.Key.ETAG_KEY, null);
// defs.putString(Key.ETAG_KEY, null);
// db int
defs.putInt(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB);
@ -125,10 +127,10 @@ public class Config {
defs.putInt(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY);
// db bool
// defs.putBoolean(Const.Key.SU_FINGERPRINT, false);
// defs.putBoolean(Key.SU_FINGERPRINT, false);
// db strings
// defs.putString(Const.Key.SU_MANAGER, null);
// defs.putString(Key.SU_MANAGER, null);
}
public static void loadMagiskInfo() {
@ -245,6 +247,7 @@ public class Config {
case Key.CHECK_UPDATES:
case Key.MAGISKHIDE:
case Key.COREONLY:
case Key.SHOW_SYSTEM_APP:
return PREF_BOOL;
case Key.CUSTOM_CHANNEL:

View File

@ -2,14 +2,13 @@ package com.topjohnwu.magisk.adapters;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
@ -18,6 +17,7 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.internal.UiThreadHandler;
import java.util.ArrayList;
import java.util.Collections;
@ -25,22 +25,30 @@ import java.util.Iterator;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
private List<ApplicationInfo> fullList, showList;
private static PackageInfo PLATFORM;
private List<PackageInfo> fullList, showList;
private List<String> hideList;
private PackageManager pm;
private ApplicationFilter filter;
private boolean showSystem;
public ApplicationAdapter(Context context) {
fullList = showList = Collections.emptyList();
hideList = Collections.emptyList();
filter = new ApplicationFilter();
pm = context.getPackageManager();
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
showSystem = false;
if (PLATFORM == null) {
try {
PLATFORM = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException ignored) {}
}
AsyncTask.SERIAL_EXECUTOR.execute(this::loadApps);
}
@NonNull
@ -50,12 +58,17 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
return new ViewHolder(v);
}
@WorkerThread
private void loadApps() {
fullList = pm.getInstalledApplications(0);
fullList = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
hideList = Shell.su("magiskhide --ls").exec().getOut();
for (Iterator<ApplicationInfo> i = fullList.iterator(); i.hasNext(); ) {
ApplicationInfo info = i.next();
if (Const.HIDE_BLACKLIST.contains(info.packageName) || !info.enabled || info.uid == 1000) {
for (Iterator<PackageInfo> i = fullList.iterator(); i.hasNext(); ) {
PackageInfo info = i.next();
if (Const.HIDE_BLACKLIST.contains(info.packageName) ||
/* Do not show disabled apps */
!info.applicationInfo.enabled ||
/* Never show platform apps */
PLATFORM.signatures[0].equals(info.signatures[0])) {
i.remove();
}
}
@ -63,7 +76,8 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
boolean ah = hideList.contains(a.packageName);
boolean bh = hideList.contains(b.packageName);
if (ah == bh) {
return Utils.getAppLabel(a, pm).compareToIgnoreCase(Utils.getAppLabel(b, pm));
return Utils.getAppLabel(a.applicationInfo, pm)
.compareToIgnoreCase(Utils.getAppLabel(b.applicationInfo, pm));
} else if (ah) {
return -1;
} else {
@ -73,9 +87,13 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
Topic.publish(false, Topic.MAGISK_HIDE_DONE);
}
public void setShowSystem(boolean b) {
showSystem = b;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ApplicationInfo info = showList.get(position);
ApplicationInfo info = showList.get(position).applicationInfo;
holder.appIcon.setImageDrawable(info.loadIcon(pm));
holder.appName.setText(Utils.getAppLabel(info, pm));
@ -99,8 +117,37 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
return showList.size();
}
private boolean contains(String s, String filter) {
return s.toLowerCase().contains(filter);
}
// Show if have launch intent or not system app
private boolean systemFilter(PackageInfo info) {
if (showSystem)
return true;
return (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
pm.getLaunchIntentForPackage(info.packageName) != null;
}
public void filter(String constraint) {
filter.filter(constraint);
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
showList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
for (PackageInfo info : fullList) {
if (systemFilter(info))
showList.add(info);
}
} else {
String filter = constraint.toLowerCase();
for (PackageInfo info : fullList) {
if ((contains(Utils.getAppLabel(info.applicationInfo, pm), filter) ||
contains(info.packageName, filter)) && systemFilter(info)) {
showList.add(info);
}
}
}
UiThreadHandler.run(this::notifyDataSetChanged);
});
}
public void refresh() {
@ -119,33 +166,4 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
new ApplicationAdapter$ViewHolder_ViewBinding(this, itemView);
}
}
class ApplicationFilter extends Filter {
private boolean lowercaseContains(String s, CharSequence filter) {
return !TextUtils.isEmpty(s) && s.toLowerCase().contains(filter);
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint == null || constraint.length() == 0) {
showList = fullList;
} else {
showList = new ArrayList<>();
String filter = constraint.toString().toLowerCase();
for (ApplicationInfo info : fullList) {
if (lowercaseContains(Utils.getAppLabel(info, pm), filter)
|| lowercaseContains(info.packageName, filter)) {
showList.add(info);
}
}
}
return null;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyDataSetChanged();
}
}
}

View File

@ -4,10 +4,12 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SearchView;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.adapters.ApplicationAdapter;
import com.topjohnwu.magisk.components.BaseFragment;
@ -23,10 +25,9 @@ public class MagiskHideFragment extends BaseFragment implements Topic.Subscriber
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
SearchView search;
private ApplicationAdapter appAdapter;
private SearchView search;
private ApplicationAdapter adapter;
private SearchView.OnQueryTextListener searchListener;
@Override
@ -41,22 +42,22 @@ public class MagiskHideFragment extends BaseFragment implements Topic.Subscriber
View view = inflater.inflate(R.layout.fragment_magisk_hide, container, false);
unbinder = new MagiskHideFragment_ViewBinding(this, view);
appAdapter = new ApplicationAdapter(requireActivity());
recyclerView.setAdapter(appAdapter);
adapter = new ApplicationAdapter(requireActivity());
recyclerView.setAdapter(adapter);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(appAdapter::refresh);
mSwipeRefreshLayout.setOnRefreshListener(adapter::refresh);
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
appAdapter.filter(query);
adapter.filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
appAdapter.filter(newText);
adapter.filter(newText);
return false;
}
};
@ -71,6 +72,21 @@ public class MagiskHideFragment extends BaseFragment implements Topic.Subscriber
inflater.inflate(R.menu.menu_magiskhide, menu);
search = (SearchView) menu.findItem(R.id.app_search).getActionView();
search.setOnQueryTextListener(searchListener);
boolean showSystem = Config.get(Config.Key.SHOW_SYSTEM_APP);
menu.findItem(R.id.show_system).setChecked(showSystem);
adapter.setShowSystem(showSystem);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.show_system) {
boolean showSystem = !item.isChecked();
item.setChecked(showSystem);
Config.set(Config.Key.SHOW_SYSTEM_APP, showSystem);
adapter.setShowSystem(showSystem);
adapter.filter(search.getQuery().toString());
}
return true;
}
@Override
@ -81,6 +97,6 @@ public class MagiskHideFragment extends BaseFragment implements Topic.Subscriber
@Override
public void onPublish(int topic, Object[] result) {
mSwipeRefreshLayout.setRefreshing(false);
appAdapter.filter(search.getQuery().toString());
adapter.filter(search.getQuery().toString());
}
}

View File

@ -7,4 +7,10 @@
android:title=""
app:actionViewClass="android.widget.SearchView"
app:showAsAction="always"/>
<item
android:id="@+id/show_system"
android:title="@string/show_system_app"
android:checkable="true"/>
</menu>

View File

@ -232,4 +232,7 @@
<string name="target_uid">Target UID: %1$d</string>
<string name="command">Command: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Show system apps</string>
</resources>