Add support for module scope
This commit is contained in:
parent
3a8bd8cb3e
commit
4ce6cb558b
|
|
@ -38,6 +38,9 @@
|
|||
<activity
|
||||
android:name=".DownloadActivity"
|
||||
android:label="@string/Downloads" />
|
||||
<activity
|
||||
android:name=".ModuleScopeActivity"
|
||||
android:label="@string/menu_scope"/>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:theme="@style/AppTheme.ActivityMain"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import org.meowcat.edxposed.manager.adapters.AppAdapter;
|
||||
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
||||
import org.meowcat.edxposed.manager.adapters.ScopeAdapter;
|
||||
import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding;
|
||||
|
||||
public class ModuleScopeActivity extends BaseActivity implements AppAdapter.Callback {
|
||||
private SearchView searchView;
|
||||
private AppAdapter appAdapter;
|
||||
|
||||
private SearchView.OnQueryTextListener searchListener;
|
||||
private ActivityBlackListBinding binding;
|
||||
private final Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
}
|
||||
};
|
||||
private final Handler handler = new Handler();
|
||||
private String modulePackageName;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
modulePackageName = getIntent().getStringExtra("modulePackageName");
|
||||
String moduleName = getIntent().getStringExtra("moduleName");
|
||||
binding = ActivityBlackListBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
binding.toolbar.setNavigationOnClickListener(view -> finish());
|
||||
ActionBar bar = getSupportActionBar();
|
||||
if (bar != null) {
|
||||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
bar.setSubtitle(moduleName);
|
||||
}
|
||||
setupWindowInsets(binding.snackbar, binding.recyclerView);
|
||||
appAdapter = new ScopeAdapter(this, modulePackageName);
|
||||
appAdapter.setHasStableIds(true);
|
||||
binding.recyclerView.setAdapter(appAdapter);
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
if (!XposedApp.getPreferences().getBoolean("md2", false)) {
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,
|
||||
DividerItemDecoration.VERTICAL);
|
||||
binding.recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
}
|
||||
appAdapter.setCallback(this);
|
||||
handler.postDelayed(runnable, 300);
|
||||
binding.swipeRefreshLayout.setOnRefreshListener(() -> appAdapter.refresh());
|
||||
|
||||
searchListener = new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
appAdapter.filter(query);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
appAdapter.filter(newText);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_app_list, menu);
|
||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
searchView.setOnQueryTextListener(searchListener);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataReady() {
|
||||
handler.removeCallbacks(runnable);
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
||||
runOnUiThread(() -> appAdapter.getFilter().filter(queryStr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(View v, ApplicationInfo info) {
|
||||
AppHelper.showMenu(this, getSupportFragmentManager(), v, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (searchView.isIconified()) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,10 +69,10 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
private SearchView.OnQueryTextListener mSearchListener;
|
||||
private PackageManager pm;
|
||||
private Comparator<ApplicationInfo> cmp;
|
||||
private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
private final DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
private ModuleUtil moduleUtil;
|
||||
private ModuleAdapter adapter = null;
|
||||
private Runnable reloadModules = new Runnable() {
|
||||
private final Runnable reloadModules = new Runnable() {
|
||||
public void run() {
|
||||
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
|
||||
ArrayList<ModuleUtil.InstalledModule> showList;
|
||||
|
|
@ -443,6 +443,12 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
case R.id.menu_uninstall:
|
||||
startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", module.packageName, null)));
|
||||
return true;
|
||||
case R.id.menu_scope:
|
||||
Intent scopeIntent = new Intent(this, ModuleScopeActivity.class);
|
||||
scopeIntent.putExtra("modulePackageName", module.packageName);
|
||||
scopeIntent.putExtra("moduleName", module.getAppName());
|
||||
startActivity(scopeIntent);
|
||||
return true;
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ import java.util.Locale;
|
|||
|
||||
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> implements Filterable {
|
||||
|
||||
protected final Context context;
|
||||
protected Context context;
|
||||
private final ApplicationInfo.DisplayNameComparator displayNameComparator;
|
||||
private Callback callback;
|
||||
private List<ApplicationInfo> fullList, showList;
|
||||
private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
protected List<ApplicationInfo> fullList, showList;
|
||||
private final DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
private List<String> checkedList;
|
||||
private PackageManager pm;
|
||||
private ApplicationFilter filter;
|
||||
private final PackageManager pm;
|
||||
private final ApplicationFilter filter;
|
||||
private Comparator<ApplicationInfo> cmp;
|
||||
|
||||
AppAdapter(Context context) {
|
||||
|
|
@ -66,17 +66,36 @@ public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> impl
|
|||
}
|
||||
|
||||
private void loadApps() {
|
||||
boolean onlyInAppList = this instanceof ScopeAdapter;
|
||||
fullList = pm.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
if (!XposedApp.getPreferences().getBoolean("show_modules", true)) {
|
||||
List<ApplicationInfo> rmList = new ArrayList<>();
|
||||
List<ApplicationInfo> rmList = new ArrayList<>();
|
||||
if (!XposedApp.getPreferences().getBoolean("show_modules", true) || onlyInAppList) {
|
||||
for (ApplicationInfo info : fullList) {
|
||||
if (info.metaData != null && info.metaData.containsKey("xposedmodule") || AppHelper.FORCE_WHITE_LIST_MODULE.contains(info.packageName)) {
|
||||
rmList.add(info);
|
||||
}
|
||||
}
|
||||
if (rmList.size() > 0) {
|
||||
fullList.removeAll(rmList);
|
||||
}
|
||||
if (onlyInAppList && AppHelper.isBlackListMode()) {
|
||||
if (AppHelper.isWhiteListMode()) {
|
||||
List<String> whiteList = AppHelper.getWhiteList();
|
||||
for (ApplicationInfo info : fullList) {
|
||||
if (!whiteList.contains(info.packageName)) {
|
||||
rmList.add(info);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
List<String> blackList = AppHelper.getBlackList();
|
||||
for (ApplicationInfo info : fullList) {
|
||||
if (blackList.contains(info.packageName)) {
|
||||
rmList.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (rmList.size() > 0) {
|
||||
fullList.removeAll(rmList);
|
||||
}
|
||||
AppHelper.makeSurePath();
|
||||
checkedList = generateCheckedList();
|
||||
|
|
@ -152,7 +171,7 @@ public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> impl
|
|||
cmp = displayNameComparator;
|
||||
break;
|
||||
}
|
||||
Collections.sort(fullList, (a, b) -> {
|
||||
fullList.sort((a, b) -> {
|
||||
boolean aChecked = checkedList.contains(a.packageName);
|
||||
boolean bChecked = checkedList.contains(b.packageName);
|
||||
if (aChecked == bChecked) {
|
||||
|
|
|
|||
|
|
@ -21,13 +21,18 @@ import org.meowcat.edxposed.manager.R;
|
|||
import org.meowcat.edxposed.manager.XposedApp;
|
||||
import org.meowcat.edxposed.manager.util.CompileUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
|
@ -42,12 +47,15 @@ public class AppHelper {
|
|||
private static final String WHITE_LIST_PATH = "conf/whitelist/";
|
||||
private static final String BLACK_LIST_PATH = "conf/blacklist/";
|
||||
private static final String COMPAT_LIST_PATH = "conf/compatlist/";
|
||||
private static final String SCOPE_LIST_PATH = "conf/%s.conf";
|
||||
private static final String WHITE_LIST_MODE = "conf/usewhitelist";
|
||||
private static final String BLACK_LIST_MODE = "conf/blackwhitelist";
|
||||
|
||||
private static final List<String> FORCE_WHITE_LIST = new ArrayList<>(XposedApp.isEnhancementEnabled() ? Arrays.asList(BuildConfig.APPLICATION_ID, "android") : Collections.singletonList(BuildConfig.APPLICATION_ID));
|
||||
public static List<String> FORCE_WHITE_LIST_MODULE = new ArrayList<>(FORCE_WHITE_LIST);
|
||||
|
||||
private static final HashMap<String, List<String>> scopeList = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("OctalInteger")
|
||||
static void makeSurePath() {
|
||||
XposedApp.mkdirAndChmod(WHITE_LIST_PATH, 00777);
|
||||
|
|
@ -331,4 +339,39 @@ public class AppHelper {
|
|||
static boolean removeCompatList(String packageName) {
|
||||
return compatListFileName(packageName, false);
|
||||
}
|
||||
|
||||
static List<String> getScopeList(String modulePackageName) {
|
||||
if (scopeList.containsKey(modulePackageName)) {
|
||||
return scopeList.get(modulePackageName);
|
||||
}
|
||||
File file = new File(BASE_PATH + String.format(SCOPE_LIST_PATH, modulePackageName));
|
||||
List<String> s = new ArrayList<>();
|
||||
try {
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
s.add(line);
|
||||
}
|
||||
scopeList.put(modulePackageName, s);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static boolean saveScopeList(String modulePackageName, List<String> list) {
|
||||
File file = new File(BASE_PATH + String.format(SCOPE_LIST_PATH, modulePackageName));
|
||||
try {
|
||||
PrintWriter pr = new PrintWriter(new FileWriter(file));
|
||||
for (String line : list) {
|
||||
pr.println(line);
|
||||
}
|
||||
pr.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
scopeList.put(modulePackageName, list);
|
||||
setFilePermissionsFromMode(file.getPath(), Context.MODE_WORLD_READABLE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package org.meowcat.edxposed.manager.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
import org.meowcat.edxposed.manager.R;
|
||||
import org.meowcat.edxposed.manager.util.ToastUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ScopeAdapter extends AppAdapter {
|
||||
|
||||
private final String modulePackageName;
|
||||
private List<String> checkedList;
|
||||
|
||||
public ScopeAdapter(Context context, String modulePackageName) {
|
||||
super(context);
|
||||
this.modulePackageName = modulePackageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> generateCheckedList() {
|
||||
AppHelper.makeSurePath();
|
||||
List<String> scopeList = AppHelper.getScopeList(modulePackageName);
|
||||
List<String> list = new ArrayList<>();
|
||||
for (ApplicationInfo info : fullList) {
|
||||
list.add(info.packageName);
|
||||
}
|
||||
scopeList.retainAll(list);
|
||||
checkedList = scopeList;
|
||||
return checkedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCheckedChange(CompoundButton view, boolean isChecked, ApplicationInfo info) {
|
||||
if (isChecked) {
|
||||
checkedList.add(info.packageName);
|
||||
} else {
|
||||
checkedList.remove(info.packageName);
|
||||
}
|
||||
if (!AppHelper.saveScopeList(modulePackageName, checkedList)) {
|
||||
ToastUtil.showShortToast(context, R.string.add_package_failed);
|
||||
if (!isChecked) {
|
||||
checkedList.add(info.packageName);
|
||||
} else {
|
||||
checkedList.remove(info.packageName);
|
||||
}
|
||||
view.setChecked(!isChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
<item
|
||||
android:id="@+id/menu_launch"
|
||||
android:title="@string/module_launch" />
|
||||
<item
|
||||
android:id="@+id/menu_scope"
|
||||
android:title="@string/menu_scope" />
|
||||
<item
|
||||
android:id="@+id/menu_download_updates"
|
||||
android:title="@string/module_download_updates" />
|
||||
|
|
|
|||
|
|
@ -341,4 +341,5 @@
|
|||
<string name="settings_summary_hide_edxposed_manager">Prevent the software from detecting EdXposed Manager\nWARNING: Modules may not be able to start the EdXposed Manager UI properly, some fratures of EdXposed Manager in the system may not work properly</string>
|
||||
<string name="settings_title_disable_hidden_api_bypass">Disable hidden API restrictions bypass</string>
|
||||
<string name="settings_summary_disable_hidden_api_bypass">Disable hidden API restrictions bypass will pass some detection (eg Snapchat), these APIs are disabled by default\n<b>WARNING:</b> Enable this option may cause some features do not work properly, or some other problems</string>
|
||||
<string name="menu_scope">Scope</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue