Add support for recommended scope
This commit is contained in:
parent
50ea40cd88
commit
7be4e66b98
|
|
@ -22,6 +22,7 @@ import android.widget.Filter;
|
|||
import android.widget.Filterable;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -30,6 +31,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -54,14 +56,17 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
private final ApplicationFilter filter;
|
||||
private final SharedPreferences preferences;
|
||||
private final String modulePackageName;
|
||||
private final String moduleName;
|
||||
private final MasterSwitch masterSwitch;
|
||||
private List<PackageInfo> fullList, showList;
|
||||
private List<String> checkedList;
|
||||
private final List<String> recommendedList;
|
||||
private boolean enabled = true;
|
||||
private ApplicationInfo selectedInfo;
|
||||
|
||||
public ScopeAdapter(AppListActivity activity, String modulePackageName, MasterSwitch masterSwitch) {
|
||||
public ScopeAdapter(AppListActivity activity, String moduleName, String modulePackageName, MasterSwitch masterSwitch) {
|
||||
this.activity = activity;
|
||||
this.moduleName = moduleName;
|
||||
this.modulePackageName = modulePackageName;
|
||||
this.masterSwitch = masterSwitch;
|
||||
preferences = App.getPreferences();
|
||||
|
|
@ -77,6 +82,8 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
ModuleUtil.InstalledModule module = ModuleUtil.getInstance().getModule(modulePackageName);
|
||||
recommendedList = module.getScopeList();
|
||||
enabled = ModuleUtil.getInstance().isModuleEnabled(modulePackageName);
|
||||
refresh();
|
||||
}
|
||||
|
|
@ -91,12 +98,15 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
private void loadApps() {
|
||||
activity.runOnUiThread(() -> masterSwitch.setChecked(enabled));
|
||||
checkedList = AppHelper.getScopeList(modulePackageName);
|
||||
if (checkedList.isEmpty() && hasRecommended()) {
|
||||
checkRecommended();
|
||||
}
|
||||
fullList = pm.getInstalledPackages(PackageManager.GET_META_DATA);
|
||||
List<String> installedList = new ArrayList<>();
|
||||
List<PackageInfo> rmList = new ArrayList<>();
|
||||
for (PackageInfo info : fullList) {
|
||||
installedList.add(info.packageName);
|
||||
if (info.packageName.equals(((ScopeAdapter) this).modulePackageName)) {
|
||||
if (info.packageName.equals(this.modulePackageName)) {
|
||||
rmList.add(info);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -153,9 +163,32 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
});
|
||||
}
|
||||
|
||||
private void checkRecommended() {
|
||||
checkedList.clear();
|
||||
checkedList.addAll(recommendedList);
|
||||
AppHelper.saveScopeList(modulePackageName, checkedList);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private boolean hasRecommended() {
|
||||
return recommendedList != null && !recommendedList.isEmpty();
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.item_show_system) {
|
||||
if (itemId == R.id.use_recommended) {
|
||||
if (!checkedList.isEmpty()) {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.use_recommended)
|
||||
.setMessage(R.string.use_recommended_message)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> checkRecommended())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
} else {
|
||||
checkRecommended();
|
||||
}
|
||||
return true;
|
||||
} else if (itemId == R.id.item_show_system) {
|
||||
item.setChecked(!item.isChecked());
|
||||
preferences.edit().putBoolean("show_system_apps", item.isChecked()).apply();
|
||||
} else if (itemId == R.id.item_show_games) {
|
||||
|
|
@ -227,6 +260,9 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
if (intent == null) {
|
||||
menu.removeItem(R.id.menu_launch);
|
||||
}
|
||||
if (!hasRecommended()) {
|
||||
menu.removeItem(R.id.use_recommended);
|
||||
}
|
||||
menu.findItem(R.id.item_show_system).setChecked(preferences.getBoolean("show_system_apps", false));
|
||||
menu.findItem(R.id.item_show_games).setChecked(preferences.getBoolean("show_games", false));
|
||||
menu.findItem(R.id.item_show_modules).setChecked(preferences.getBoolean("show_modules", false));
|
||||
|
|
@ -276,7 +312,11 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
|
||||
}
|
||||
});
|
||||
holder.appDescription.setText(activity.getString(R.string.app_description, info.packageName, info.versionName));
|
||||
String description = activity.getString(R.string.app_description, info.packageName, info.versionName);
|
||||
if (hasRecommended() && recommendedList.contains(info.packageName)) {
|
||||
description += "\n" + activity.getString(R.string.requested_by_module);
|
||||
}
|
||||
holder.appDescription.setText(description);
|
||||
|
||||
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> {
|
||||
activity.getMenuInflater().inflate(R.menu.menu_app_item, menu);
|
||||
|
|
@ -391,6 +431,36 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
|||
}
|
||||
}
|
||||
|
||||
public boolean onBackPressed() {
|
||||
if (masterSwitch.isChecked() && checkedList.isEmpty()) {
|
||||
if (hasRecommended()) {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.use_recommended)
|
||||
.setMessage(R.string.no_scope_selected_has_recommended)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> checkRecommended())
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||
ModuleUtil.getInstance().setModuleEnabled(modulePackageName, false);
|
||||
Toast.makeText(activity, activity.getString(R.string.module_disabled_no_selection, moduleName), Toast.LENGTH_LONG).show();
|
||||
activity.finish();
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setMessage(R.string.no_scope_selected)
|
||||
.setPositiveButton(android.R.string.cancel, null)
|
||||
.setNegativeButton(android.R.string.ok, (dialog, which) -> {
|
||||
ModuleUtil.getInstance().setModuleEnabled(modulePackageName, false);
|
||||
Toast.makeText(activity, activity.getString(R.string.module_disabled_no_selection, moduleName), Toast.LENGTH_LONG).show();
|
||||
activity.finish();
|
||||
})
|
||||
.show();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAppLabel(ApplicationInfo info, PackageManager pm) {
|
||||
return info.loadLabel(pm).toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,12 @@ import androidx.appcompat.app.ActionBar;
|
|||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import io.github.lsposed.manager.R;
|
||||
import io.github.lsposed.manager.adapters.AppHelper;
|
||||
import io.github.lsposed.manager.adapters.ScopeAdapter;
|
||||
import io.github.lsposed.manager.databinding.ActivityAppListBinding;
|
||||
import io.github.lsposed.manager.util.LinearLayoutManagerFix;
|
||||
import io.github.lsposed.manager.util.ModuleUtil;
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
|
||||
|
||||
public class AppListActivity extends BaseActivity {
|
||||
|
|
@ -38,12 +35,11 @@ public class AppListActivity extends BaseActivity {
|
|||
}
|
||||
};
|
||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||
private String modulePackageName;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
modulePackageName = getIntent().getStringExtra("modulePackageName");
|
||||
String modulePackageName = getIntent().getStringExtra("modulePackageName");
|
||||
String moduleName = getIntent().getStringExtra("moduleName");
|
||||
binding = ActivityAppListBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
|
@ -54,7 +50,7 @@ public class AppListActivity extends BaseActivity {
|
|||
bar.setDisplayHomeAsUpEnabled(true);
|
||||
bar.setTitle(moduleName);
|
||||
bar.setSubtitle(modulePackageName);
|
||||
scopeAdapter = new ScopeAdapter(this, modulePackageName, binding.masterSwitch);
|
||||
scopeAdapter = new ScopeAdapter(this, moduleName, modulePackageName, binding.masterSwitch);
|
||||
scopeAdapter.setHasStableIds(true);
|
||||
binding.recyclerView.setAdapter(scopeAdapter);
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManagerFix(this));
|
||||
|
|
@ -119,16 +115,7 @@ public class AppListActivity extends BaseActivity {
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
if (searchView.isIconified()) {
|
||||
if (binding.masterSwitch.isChecked() && AppHelper.getScopeList(modulePackageName).isEmpty()) {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.no_scope_selected)
|
||||
.setPositiveButton(android.R.string.cancel, null)
|
||||
.setNegativeButton(android.R.string.ok, (dialog, which) -> {
|
||||
ModuleUtil.getInstance().setModuleEnabled(modulePackageName, false);
|
||||
super.onBackPressed();
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
if (scopeAdapter.onBackPressed()) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package io.github.lsposed.manager.ui.activity;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
|
@ -24,6 +25,7 @@ import java.util.Map;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import io.github.lsposed.manager.App;
|
||||
import io.github.lsposed.manager.BuildConfig;
|
||||
import io.github.lsposed.manager.Constants;
|
||||
import io.github.lsposed.manager.R;
|
||||
import io.github.lsposed.manager.adapters.AppHelper;
|
||||
|
|
@ -256,6 +258,7 @@ public final class ModuleUtil {
|
|||
public PackageInfo pkg;
|
||||
private String appName; // loaded lazyily
|
||||
private String description; // loaded lazyily
|
||||
private List<String> scopeList; // loaded lazyily
|
||||
|
||||
private InstalledModule(PackageInfo pkg, boolean isFramework) {
|
||||
this.app = pkg.applicationInfo;
|
||||
|
|
@ -320,6 +323,20 @@ public final class ModuleUtil {
|
|||
return this.description;
|
||||
}
|
||||
|
||||
public List<String> getScopeList() {
|
||||
if (this.scopeList == null) {
|
||||
try {
|
||||
int scopeListResourceId = app.metaData.getInt("xposedscope");
|
||||
if (scopeListResourceId != 0) {
|
||||
scopeList = Arrays.asList(pm.getResourcesForApplication(BuildConfig.APPLICATION_ID).getStringArray(scopeListResourceId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return this.scopeList;
|
||||
}
|
||||
|
||||
public PackageInfo getPackageInfo() {
|
||||
return pkg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
android:icon="@drawable/ic_settings"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/use_recommended"
|
||||
android:title="@string/use_recommended" />
|
||||
|
||||
<item
|
||||
android:id="@+id/item_show_games"
|
||||
android:checkable="true"
|
||||
|
|
|
|||
|
|
@ -154,4 +154,9 @@
|
|||
<string name="failed_to_save_scope_list">作用域列表保存失败</string>
|
||||
<string name="module_settings">模块设置</string>
|
||||
<string name="app_description">%s\n版本:%s</string>
|
||||
<string name="use_recommended">推荐</string>
|
||||
<string name="no_scope_selected_has_recommended">未选择任何应用。选择推荐的应用?</string>
|
||||
<string name="use_recommended_message">选择推荐的应用?</string>
|
||||
<string name="requested_by_module">推荐的应用</string>
|
||||
<string name="module_disabled_no_selection">由于未选择任何应用,模块 %s 已被禁用。</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -162,4 +162,9 @@
|
|||
<string name="failed_to_save_scope_list">Failed save scope list</string>
|
||||
<string name="module_settings">Module settings</string>
|
||||
<string name="app_description">%s\nVersion: %s</string>
|
||||
<string name="use_recommended">Recommended</string>
|
||||
<string name="no_scope_selected_has_recommended">You did not select any app. Select recommended apps?</string>
|
||||
<string name="use_recommended_message">Select recommended apps?</string>
|
||||
<string name="requested_by_module">Recommended</string>
|
||||
<string name="module_disabled_no_selection">Module %s has been disabled since no app selected.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,22 @@
|
|||
androidCompileSdkVersion=30
|
||||
androidMinSdkVersion=26
|
||||
## For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
#
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
#
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
#Sat Jan 30 19:20:27 CST 2021
|
||||
androidTargetSdkVersion=30
|
||||
androidCompileNdkVersion=22.0.7026061
|
||||
android.prefabVersion=1.1.2
|
||||
apiCode=93
|
||||
androidCompileSdkVersion=30
|
||||
androidMinSdkVersion=26
|
||||
org.gradle.jvmargs=-Xmx2048M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.prefabVersion=1.1.2
|
||||
|
|
|
|||
Loading…
Reference in New Issue