Improve magisk hide app list's adapter, better thread safety
This commit is contained in:
parent
b91919bffa
commit
2a70619577
@ -1,7 +1,6 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
@ -20,7 +19,6 @@ import com.topjohnwu.magisk.utils.Async;
|
|||||||
import com.topjohnwu.magisk.utils.CallbackHandler;
|
import com.topjohnwu.magisk.utils.CallbackHandler;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -32,10 +30,8 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
|
|
||||||
public static List<ApplicationInfo> listApps, fListApps = new ArrayList<>();
|
|
||||||
public static List<String> hideList = new ArrayList<>();
|
|
||||||
// Don't show in list...
|
// Don't show in list...
|
||||||
public static final List<String> blacklist = Arrays.asList(
|
public static final List<String> BLACKLIST = Arrays.asList(
|
||||||
"android",
|
"android",
|
||||||
"com.topjohnwu.magisk",
|
"com.topjohnwu.magisk",
|
||||||
"com.google.android.gms",
|
"com.google.android.gms",
|
||||||
@ -46,7 +42,7 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
|
|
||||||
private PackageManager packageManager;
|
private PackageManager packageManager;
|
||||||
private View mView;
|
private View mView;
|
||||||
private ApplicationAdapter appAdapter = new ApplicationAdapter(fListApps, hideList);
|
private ApplicationAdapter appAdapter = new ApplicationAdapter();
|
||||||
|
|
||||||
private SearchView.OnQueryTextListener searchListener;
|
private SearchView.OnQueryTextListener searchListener;
|
||||||
|
|
||||||
@ -69,13 +65,13 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
searchListener = new SearchView.OnQueryTextListener() {
|
searchListener = new SearchView.OnQueryTextListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextSubmit(String query) {
|
public boolean onQueryTextSubmit(String query) {
|
||||||
new FilterApps().exec(query);
|
appAdapter.filter(query);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextChange(String newText) {
|
public boolean onQueryTextChange(String newText) {
|
||||||
new FilterApps().exec(newText);
|
appAdapter.filter(newText);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,33 +107,9 @@ public class MagiskHideFragment extends Fragment implements CallbackHandler.Even
|
|||||||
@Override
|
@Override
|
||||||
public void onTrigger(CallbackHandler.Event event) {
|
public void onTrigger(CallbackHandler.Event event) {
|
||||||
Logger.dev("MagiskHideFragment: UI refresh");
|
Logger.dev("MagiskHideFragment: UI refresh");
|
||||||
updateUI();
|
Async.LoadApps.Result result = (Async.LoadApps.Result) event.getResult();
|
||||||
}
|
appAdapter.setLists(result.listApps, result.hideList);
|
||||||
|
|
||||||
private class FilterApps extends Async.NormalTask<String, Void, Void> {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(String... strings) {
|
|
||||||
String newText = strings[0];
|
|
||||||
fListApps.clear();
|
|
||||||
for (ApplicationInfo info : listApps) {
|
|
||||||
if (info.loadLabel(packageManager).toString().toLowerCase().contains(newText.toLowerCase())
|
|
||||||
|| info.packageName.toLowerCase().contains(newText.toLowerCase())) {
|
|
||||||
fListApps.add(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
appAdapter.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateUI() {
|
|
||||||
appAdapter.notifyDataSetChanged();
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -10,12 +10,16 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.Filter;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.utils.Async;
|
import com.topjohnwu.magisk.utils.Async;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
@ -23,16 +27,21 @@ import butterknife.ButterKnife;
|
|||||||
|
|
||||||
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
||||||
|
|
||||||
private List<ApplicationInfo> mList;
|
private List<ApplicationInfo> mOriginalList, mList;
|
||||||
private List<String> mHideList;
|
private List<String> mHideList;
|
||||||
private Context context;
|
private Context context;
|
||||||
private PackageManager packageManager;
|
private PackageManager packageManager;
|
||||||
|
private ApplicationFilter filter;
|
||||||
|
|
||||||
|
public ApplicationAdapter() {
|
||||||
|
mOriginalList = mList = Collections.emptyList();
|
||||||
|
mHideList = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLists(List<ApplicationInfo> listApps, List<String> hideList) {
|
||||||
public ApplicationAdapter(List<ApplicationInfo> list, List<String> hideList) {
|
mOriginalList = mList = Collections.unmodifiableList(listApps);
|
||||||
mList = list;
|
mHideList = new ArrayList<>(hideList);
|
||||||
mHideList = hideList;
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -78,7 +87,14 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
return mList.size();
|
return mList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder {
|
public void filter(String constraint) {
|
||||||
|
if (filter == null) {
|
||||||
|
filter = new ApplicationFilter();
|
||||||
|
}
|
||||||
|
filter.filter(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
@BindView(R.id.app_icon) ImageView appIcon;
|
@BindView(R.id.app_icon) ImageView appIcon;
|
||||||
@BindView(R.id.app_name) TextView appName;
|
@BindView(R.id.app_name) TextView appName;
|
||||||
@ -93,4 +109,36 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
|||||||
windowmanager.getDefaultDisplay().getMetrics(dimension);
|
windowmanager.getDefaultDisplay().getMetrics(dimension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApplicationFilter extends Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FilterResults performFiltering(CharSequence constraint) {
|
||||||
|
List<ApplicationInfo> filteredApps;
|
||||||
|
if (constraint == null || constraint.length() == 0) {
|
||||||
|
filteredApps = mOriginalList;
|
||||||
|
} else {
|
||||||
|
filteredApps = new ArrayList<>();
|
||||||
|
String filter = constraint.toString().toLowerCase();
|
||||||
|
for (ApplicationInfo info : mOriginalList) {
|
||||||
|
if (Utils.lowercaseContains(info.loadLabel(packageManager), filter)
|
||||||
|
|| Utils.lowercaseContains(info.packageName, filter)) {
|
||||||
|
filteredApps.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterResults results = new FilterResults();
|
||||||
|
results.values = filteredApps;
|
||||||
|
results.count = filteredApps.size();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||||
|
mList = (List<ApplicationInfo>) results.values;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -117,7 +117,7 @@ public class Async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LoadApps extends RootTask<Void, Void, Void> {
|
public static class LoadApps extends RootTask<Void, Void, LoadApps.Result> {
|
||||||
|
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
|
|
||||||
@ -126,25 +126,33 @@ public class Async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Result doInBackground(Void... voids) {
|
||||||
MagiskHideFragment.hideList.clear();
|
List<ApplicationInfo> listApps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||||
MagiskHideFragment.fListApps.clear();
|
for (Iterator<ApplicationInfo> i = listApps.iterator(); i.hasNext(); ) {
|
||||||
MagiskHideFragment.listApps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
|
|
||||||
for (Iterator<ApplicationInfo> i = MagiskHideFragment.listApps.iterator(); i.hasNext(); ) {
|
|
||||||
ApplicationInfo info = i.next();
|
ApplicationInfo info = i.next();
|
||||||
if (MagiskHideFragment.blacklist.contains(info.packageName) || !info.enabled)
|
if (MagiskHideFragment.BLACKLIST.contains(info.packageName) || !info.enabled)
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
Collections.sort(MagiskHideFragment.listApps, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
Collections.sort(listApps, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
|
||||||
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
|
||||||
MagiskHideFragment.hideList.addAll(Shell.su(Async.MAGISK_HIDE_PATH + "list"));
|
List<String> hideList = Shell.su(Async.MAGISK_HIDE_PATH + "list");
|
||||||
MagiskHideFragment.fListApps.addAll(MagiskHideFragment.listApps);
|
return new Result(listApps, hideList);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void aVoid) {
|
protected void onPostExecute(Result result) {
|
||||||
MagiskHideFragment.packageLoadDone.trigger();
|
MagiskHideFragment.packageLoadDone.trigger(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Result {
|
||||||
|
|
||||||
|
public final List<ApplicationInfo> listApps;
|
||||||
|
public final List<String> hideList;
|
||||||
|
|
||||||
|
Result(List<ApplicationInfo> listApps, List<String> hideList) {
|
||||||
|
this.listApps = listApps;
|
||||||
|
this.hideList = hideList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,23 @@ public class CallbackHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Event {
|
public static class Event {
|
||||||
|
|
||||||
public boolean isTriggered = false;
|
public boolean isTriggered = false;
|
||||||
|
private Object result;
|
||||||
|
|
||||||
public void trigger() {
|
public void trigger() {
|
||||||
|
trigger(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trigger(Object result) {
|
||||||
|
this.result = result;
|
||||||
isTriggered = true;
|
isTriggered = true;
|
||||||
triggerCallback(this);
|
triggerCallback(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface EventListener {
|
public interface EventListener {
|
||||||
|
@ -9,6 +9,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@ -144,6 +145,10 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean lowercaseContains(CharSequence string, CharSequence nonNullLowercaseSearch) {
|
||||||
|
return !TextUtils.isEmpty(string) && string.toString().toLowerCase().contains(nonNullLowercaseSearch);
|
||||||
|
}
|
||||||
|
|
||||||
public static class ByteArrayInOutStream extends ByteArrayOutputStream {
|
public static class ByteArrayInOutStream extends ByteArrayOutputStream {
|
||||||
public ByteArrayInputStream getInputStream() {
|
public ByteArrayInputStream getInputStream() {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(buf, 0, count);
|
ByteArrayInputStream in = new ByteArrayInputStream(buf, 0, count);
|
||||||
|
Loading…
Reference in New Issue
Block a user