Add support for module scope

This commit is contained in:
NekoInverter 2020-11-21 20:43:53 +08:00
parent 3a8bd8cb3e
commit 4ce6cb558b
No known key found for this signature in database
GPG Key ID: 280D6CCCF95715F9
8 changed files with 248 additions and 12 deletions

View File

@ -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"

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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" />

View File

@ -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>