From 6574115a85ba5a572b62fee55918d8c89c9f2251 Mon Sep 17 00:00:00 2001 From: Fox2Code Date: Sat, 23 Oct 2021 18:14:40 +0200 Subject: [PATCH] Release 0.1.0 - Improved module deletion safety - Improved compat installer script - Added `maxApi` metadata support for modules - Added support links fallbacks for some popular modules - Added Markdown syntax highlight support into module info view (See Prism4j repo for the list of supported languages) - Added hidden dev mode + hidden setting to enable magisk command install --- DEVELOPERS.md | 3 +- README.md | 20 ++++- app/build.gradle | 10 ++- .../main/assets/module_installer_compat.sh | 14 ++++ .../com/fox2code/mmm/ActionButtonType.java | 10 ++- .../main/java/com/fox2code/mmm/Constants.java | 1 + .../java/com/fox2code/mmm/MainActivity.java | 4 +- .../com/fox2code/mmm/MainApplication.java | 84 ++++++++++++++++++- .../fox2code/mmm/ModuleViewListBuilder.java | 4 +- .../com/fox2code/mmm/NotificationType.java | 2 +- .../mmm/installer/InstallerActivity.java | 38 ++++++--- .../mmm/manager/ModuleBootReceive.java | 1 + .../com/fox2code/mmm/manager/ModuleInfo.java | 1 + .../mmm/settings/SettingsActivity.java | 27 ++++++ .../java/com/fox2code/mmm/utils/Http.java | 6 +- .../com/fox2code/mmm/utils/PropUtils.java | 16 ++++ app/src/main/res/values/strings.xml | 6 ++ app/src/main/res/xml/root_preferences.xml | 7 ++ gradle/wrapper/gradle-wrapper.properties | 2 +- 19 files changed, 222 insertions(+), 34 deletions(-) diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 3bf0c3c..6d9f56d 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -24,6 +24,7 @@ This the manager support these new properties ```properties # Fox's Mmm supported properties minApi= +maxApi= minMagisk= support= donate= @@ -31,7 +32,7 @@ config= ``` (Note: All urls must start with `https://`, or else will be ignored) -- `minApi` tell the manager which is the minimum SDK version required for the module +- `minApi` and `maxApi` tell the manager which is the SDK version range the module support (See: [Codenames, Tags, and Build Numbers](https://source.android.com/setup/start/build-numbers)) - `minMagisk` tell the manager which is the minimum Magisk version required for the module (Often for magisk `xx.y` the version code is `xxy00`) diff --git a/README.md b/README.md index d3f6ad9..60da97a 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,16 @@ So I made my own app to do that! :3 **This app is not officially supported by Magisk or it's developers** +## Requirements + +Minimum: +- Android 5.0+ +- Magisk 19.0+ + +Recommended: +- Android 6.0+ +- Magisk 21.2+ + ## For users Related commits: @@ -24,12 +34,14 @@ If a module is in both repo, the manager will just pick the most up to date vers ## For developers -The manager can read new meta keys to allow modules to customize their entry +The manager can read new meta keys to allow modules to customize their own entry -It use `module.prop` the `minApi=` and `minMagisk=` properties to detect compatibility -And use the `support=` and `donate=` key to detect module related links +It also use `minApi`, `maxApi` and `minMagisk` in the `module.prop` to detect compatibility +And support the `support` and `donate` properties to allow them to add their own support links +(Note: the manager use fallback values for some modules, see developer documentation for more info) -It also add new ways to control the installer ui via a new `#!` command system +It also add new ways to control the installer ui via a new `#!` command system +It allow module developers to have a more customizable install experience For more information please check the [developer documentation](DEVELOPERS.md) diff --git a/app/build.gradle b/app/build.gradle index 4e04e1d..dd81863 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.fox2code.mmm" minSdk 21 targetSdk 30 - versionCode 3 - versionName "0.0.3" + versionCode 4 + versionName "0.1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -39,6 +39,10 @@ aboutLibraries { } } +configurations { + implementation.exclude group: 'org.jetbrains' , module: 'annotations' +} + dependencies { // UI implementation 'androidx.appcompat:appcompat:1.3.1' @@ -57,6 +61,8 @@ dependencies { implementation "io.noties.markwon:core:4.6.2" implementation "io.noties.markwon:html:4.6.2" implementation "io.noties.markwon:image:4.6.2" + implementation "io.noties.markwon:syntax-highlight:4.6.2" + annotationProcessor "io.noties:prism4j-bundler:2.0.0" implementation "com.caverock:androidsvg:1.4" // Test diff --git a/app/src/main/assets/module_installer_compat.sh b/app/src/main/assets/module_installer_compat.sh index f0afa64..7a49a26 100644 --- a/app/src/main/assets/module_installer_compat.sh +++ b/app/src/main/assets/module_installer_compat.sh @@ -29,6 +29,19 @@ mount /data 2>/dev/null . /data/adb/magisk/util_functions.sh [ $MAGISK_VER_CODE -lt 19000 ] && require_new_magisk +# Add grep_get_prop implementation if missing +if ! type grep_get_prop &>/dev/null; then +grep_get_prop() { + local result=$(grep_prop $@) + if [ -z "$result" ]; then + # Fallback to getprop + getprop "$1" + else + echo $result + fi +} +fi + if [ $MAGISK_VER_CODE -ge 20400 ]; then # New Magisk have complete installation logic within util_functions.sh install_module @@ -84,6 +97,7 @@ mount_partitions # Detect version and architecture api_level_arch_detect +API=$(grep_get_prop ro.build.version.sdk) # Setup busybox and binaries $BOOTMODE && boot_actions || recovery_actions diff --git a/app/src/main/java/com/fox2code/mmm/ActionButtonType.java b/app/src/main/java/com/fox2code/mmm/ActionButtonType.java index b600773..97c9928 100644 --- a/app/src/main/java/com/fox2code/mmm/ActionButtonType.java +++ b/app/src/main/java/com/fox2code/mmm/ActionButtonType.java @@ -52,8 +52,10 @@ public enum ActionButtonType { @Override public void update(ImageButton button, ModuleHolder moduleHolder) { int icon = moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_UNINSTALLING) ? - R.drawable.ic_baseline_delete_outline_24 : - moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE) ? + R.drawable.ic_baseline_delete_outline_24 : ( + // We can't trust active flag on first boot + MainApplication.isFirstBoot() || + moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)) ? R.drawable.ic_baseline_delete_24 : R.drawable.ic_baseline_delete_forever_24; button.setImageResource(icon); @@ -70,7 +72,9 @@ public enum ActionButtonType { @Override public boolean doActionLong(ImageButton button, ModuleHolder moduleHolder) { - if (moduleHolder.moduleInfo.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)) return false; + // We can't trust active flag on first boot + if (moduleHolder.moduleInfo.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE) + || MainApplication.isFirstBoot()) return false; new AlertDialog.Builder(button.getContext()).setTitle(R.string.master_delete) .setPositiveButton(R.string.master_delete_yes, (v, i) -> { if (!ModuleManager.getINSTANCE().masterClear(moduleHolder.moduleInfo)) { diff --git a/app/src/main/java/com/fox2code/mmm/Constants.java b/app/src/main/java/com/fox2code/mmm/Constants.java index 7cba0bf..674a074 100644 --- a/app/src/main/java/com/fox2code/mmm/Constants.java +++ b/app/src/main/java/com/fox2code/mmm/Constants.java @@ -4,6 +4,7 @@ public class Constants { public static final int MAGISK_VER_CODE_FLAT_MODULES = 19000; public static final int MAGISK_VER_CODE_UTIL_INSTALL = 20400; public static final int MAGISK_VER_CODE_PATH_SUPPORT = 21000; + public static final int MAGISK_VER_CODE_INSTALL_COMMAND = 21200; public static final int MAGISK_VER_CODE_MAGISK_ZYGOTE = 23002; public static final String INTENT_INSTALL_INTERNAL = BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL"; diff --git a/app/src/main/java/com/fox2code/mmm/MainActivity.java b/app/src/main/java/com/fox2code/mmm/MainActivity.java index 29397c1..662d222 100644 --- a/app/src/main/java/com/fox2code/mmm/MainActivity.java +++ b/app/src/main/java/com/fox2code/mmm/MainActivity.java @@ -90,7 +90,7 @@ public class MainActivity extends CompatActivity implements SwipeRefreshLayout.O public void onPathReceived(String path) { Log.i(TAG, "Got magisk path: " + path); if (InstallerInitializer.peekMagiskVersion() < - Constants.MAGISK_VER_CODE_PATH_SUPPORT) + Constants.MAGISK_VER_CODE_INSTALL_COMMAND) moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); @@ -159,7 +159,7 @@ public class MainActivity extends CompatActivity implements SwipeRefreshLayout.O @Override public void onPathReceived(String path) { if (InstallerInitializer.peekMagiskVersion() < - Constants.MAGISK_VER_CODE_PATH_SUPPORT) + Constants.MAGISK_VER_CODE_INSTALL_COMMAND) moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index 3281e28..1d201c1 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -6,7 +6,9 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Color; import android.os.SystemClock; +import android.text.SpannableStringBuilder; import androidx.annotation.NonNull; import androidx.annotation.StyleRes; @@ -27,7 +29,17 @@ import io.noties.markwon.Markwon; import io.noties.markwon.html.HtmlPlugin; import io.noties.markwon.image.ImagesPlugin; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; +import io.noties.markwon.syntax.Prism4jTheme; +import io.noties.markwon.syntax.Prism4jThemeDarkula; +import io.noties.markwon.syntax.Prism4jThemeDefault; +import io.noties.markwon.syntax.SyntaxHighlightPlugin; +import io.noties.prism4j.Prism4j; +import io.noties.prism4j.annotations.PrismBundle; +@PrismBundle( + includeAll = true, + grammarLocatorClassName = ".Prism4jGrammarLocator" +) public class MainApplication extends Application implements CompatActivity.ApplicationCallbacks { private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001 private static Locale timeFormatLocale = @@ -38,6 +50,7 @@ public class MainApplication extends Application implements CompatActivity.Appli private static final int secret; private static SharedPreferences bootSharedPreferences; private static MainApplication INSTANCE; + private static boolean firstBoot; static { Shell.setDefaultBuilder(shellBuilder = Shell.Builder.create() @@ -75,6 +88,32 @@ public class MainApplication extends Application implements CompatActivity.Appli return getSharedPreferences().getBoolean("pref_force_dark_terminal", false); } + public static boolean isDeveloper() { + return BuildConfig.DEBUG || + getSharedPreferences().getBoolean("developer", false); + } + + public static boolean isUsingMagiskCommand() { + return InstallerInitializer.peekMagiskVersion() >= Constants.MAGISK_VER_CODE_INSTALL_COMMAND + && getSharedPreferences().getBoolean("pref_use_magisk_install_command", false) + && isDeveloper(); + } + + public static boolean isFirstBoot() { + return firstBoot; + } + + public static void notifyBootListenerCompleted() { + if (MainApplication.bootSharedPreferences != null) { + MainApplication.bootSharedPreferences.edit() + .putBoolean("first_boot", false).apply(); + } else if (MainApplication.INSTANCE != null) { + MainApplication.getSharedPreferences().edit() + .putBoolean("first_boot", false).apply(); + } + firstBoot = false; + } + public static boolean hasGottenRootAccess() { return getSharedPreferences().getBoolean("has_root_access", false); } @@ -104,18 +143,48 @@ public class MainApplication extends Application implements CompatActivity.Appli public Markwon getMarkwon() { if (this.markwon != null) return this.markwon; - ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext = - new ContextThemeWrapper(this, this.managerThemeResId); + ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext; + if (contextThemeWrapper == null) + contextThemeWrapper = this.markwonThemeContext = + new ContextThemeWrapper(this, this.managerThemeResId); Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create()) + .usePlugin(SyntaxHighlightPlugin.create( + new Prism4j(new Prism4jGrammarLocator()), new Prism4jSwitchTheme())) .usePlugin(ImagesPlugin.create().addSchemeHandler( OkHttpNetworkSchemeHandler.create(Http.getHttpclientWithCache()))).build(); return this.markwon = markwon; } + private class Prism4jSwitchTheme implements Prism4jTheme { + private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT); + private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT); + + private Prism4jTheme getTheme() { + return isLightTheme() ? this.light : this.dark; + } + + @Override + public int background() { + return this.getTheme().background(); + } + + @Override + public int textColor() { + return this.getTheme().textColor(); + } + + @Override + public void apply(@NonNull String language, @NonNull Prism4j.Syntax syntax, + @NonNull SpannableStringBuilder builder, int start, int end) { + this.getTheme().apply(language, syntax, builder, start, end); + } + } + public void setManagerThemeResId(@StyleRes int resId) { this.managerThemeResId = resId; if (this.markwonThemeContext != null) this.markwonThemeContext.setTheme(resId); + this.markwon = null; } @StyleRes @@ -144,13 +213,22 @@ public class MainApplication extends Application implements CompatActivity.Appli public void onCreate() { INSTANCE = this; super.onCreate(); + SharedPreferences sharedPreferences = MainApplication.getSharedPreferences(); // We are only one process so it's ok to do this SharedPreferences bootPrefs = MainApplication.bootSharedPreferences = this.getSharedPreferences("mmm_boot", MODE_PRIVATE); long lastBoot = System.currentTimeMillis() - SystemClock.elapsedRealtime(); long lastBootPrefs = bootPrefs.getLong("last_boot", 0); if (lastBootPrefs == 0 || Math.abs(lastBoot - lastBootPrefs) > 100) { - bootPrefs.edit().clear().putLong("last_boot", lastBoot).apply(); + boolean firstBoot = sharedPreferences.getBoolean("first_boot", true); + bootPrefs.edit().clear().putLong("last_boot", lastBoot) + .putBoolean("first_boot", firstBoot).apply(); + if (firstBoot) { + sharedPreferences.edit().putBoolean("first_boot", false).apply(); + } + MainApplication.firstBoot = firstBoot; + } else { + MainApplication.firstBoot = bootPrefs.getBoolean("first_boot", false); } @StyleRes int themeResId; switch (getSharedPreferences().getString("pref_theme", "system")) { diff --git a/app/src/main/java/com/fox2code/mmm/ModuleViewListBuilder.java b/app/src/main/java/com/fox2code/mmm/ModuleViewListBuilder.java index 217c779..f0c6433 100644 --- a/app/src/main/java/com/fox2code/mmm/ModuleViewListBuilder.java +++ b/app/src/main/java/com/fox2code/mmm/ModuleViewListBuilder.java @@ -72,7 +72,9 @@ public class ModuleViewListBuilder { repoManager.runAfterUpdate(() -> { Log.i(TAG, "A2: " + repoManager.getModules().size()); for (RepoModule repoModule : repoManager.getModules().values()) { - if (!showIncompatible && (repoModule.moduleInfo.minApi > Build.VERSION.SDK_INT || + ModuleInfo moduleInfo = repoModule.moduleInfo; + if (!showIncompatible && (moduleInfo.minApi > Build.VERSION.SDK_INT || + (moduleInfo.maxApi != 0 && moduleInfo.maxApi < Build.VERSION.SDK_INT) || // Only check Magisk compatibility if root is present (InstallerInitializer.peekMagiskPath() != null && repoModule.moduleInfo.minMagisk > diff --git a/app/src/main/java/com/fox2code/mmm/NotificationType.java b/app/src/main/java/com/fox2code/mmm/NotificationType.java index 2d151e9..01e1326 100644 --- a/app/src/main/java/com/fox2code/mmm/NotificationType.java +++ b/app/src/main/java/com/fox2code/mmm/NotificationType.java @@ -42,7 +42,7 @@ public enum NotificationType implements NotificationTypeCst { public boolean shouldRemove() { return InstallerInitializer.peekMagiskPath() == null || InstallerInitializer.peekMagiskVersion() >= - Constants.MAGISK_VER_CODE_PATH_SUPPORT; + Constants.MAGISK_VER_CODE_INSTALL_COMMAND; } }, NO_INTERNET(R.string.fail_internet, R.drawable.ic_baseline_cloud_off_24) { diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java index 7b8738d..361708c 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java @@ -136,20 +136,32 @@ public class InstallerActivity extends CompatActivity { private void doInstall(File file) { Log.i(TAG, "Installing: " + moduleCache.getName()); - File installScript = this.extractCompatScript(); - if (installScript == null) { - this.setInstallStateFinished(false, - "! Failed to extract module install script", ""); - return; - } InstallerController installerController = new InstallerController( this.progressIndicator, this.installerTerminal, file.getAbsoluteFile()); - InstallerMonitor installerMonitor = new InstallerMonitor(installScript); - boolean success = Shell.su("export MMM_EXT_SUPPORT=1", - "cd \"" + this.moduleCache.getAbsolutePath() + "\"", - "sh \"" + installScript.getAbsolutePath() + "\"" + - " /dev/null 1 \"" + file.getAbsolutePath() + "\"") - .to(installerController, installerMonitor).exec().isSuccess(); + InstallerMonitor installerMonitor; + Shell.Job installJob; + if (MainApplication.isUsingMagiskCommand()) { + installerMonitor = new InstallerMonitor(new File(InstallerInitializer + .peekMagiskPath().equals("/sbin") ? "/sbin/magisk" : "/system/bin/magisk")); + installJob = Shell.su("export MMM_EXT_SUPPORT=1", + "cd \"" + this.moduleCache.getAbsolutePath() + "\"", + "magisk --install-module \"" + file.getAbsolutePath() + "\"") + .to(installerController, installerMonitor); + } else { + File installScript = this.extractCompatScript(); + if (installScript == null) { + this.setInstallStateFinished(false, + "! Failed to extract module install script", ""); + return; + } + installerMonitor = new InstallerMonitor(installScript); + installJob = Shell.su("export MMM_EXT_SUPPORT=1", + "cd \"" + this.moduleCache.getAbsolutePath() + "\"", + "sh \"" + installScript.getAbsolutePath() + "\"" + + " /dev/null 1 \"" + file.getAbsolutePath() + "\"") + .to(installerController, installerMonitor); + } + boolean success = installJob.exec().isSuccess(); // Wait one UI cycle before disabling controller or processing results UiThreadHandler.runAndWait(() -> {}); // to avoid race conditions installerController.disable(); @@ -261,7 +273,7 @@ public class InstallerActivity extends CompatActivity { public static class InstallerMonitor extends CallbackList { private static final String DEFAULT_ERR = "! Install failed"; private final String installScriptPath; - public String lastCommand; + public String lastCommand = ""; public InstallerMonitor(File installScript) { super(Runnable::run); diff --git a/app/src/main/java/com/fox2code/mmm/manager/ModuleBootReceive.java b/app/src/main/java/com/fox2code/mmm/manager/ModuleBootReceive.java index 9df5bf7..459053f 100644 --- a/app/src/main/java/com/fox2code/mmm/manager/ModuleBootReceive.java +++ b/app/src/main/java/com/fox2code/mmm/manager/ModuleBootReceive.java @@ -19,6 +19,7 @@ public class ModuleBootReceive extends BroadcastReceiver { InstallerInitializer.tryGetMagiskPathAsync(new InstallerInitializer.Callback() { @Override public void onPathReceived(String path) { + MainApplication.notifyBootListenerCompleted(); ModuleManager.getINSTANCE().scan(); } diff --git a/app/src/main/java/com/fox2code/mmm/manager/ModuleInfo.java b/app/src/main/java/com/fox2code/mmm/manager/ModuleInfo.java index c02e65f..c3a1225 100644 --- a/app/src/main/java/com/fox2code/mmm/manager/ModuleInfo.java +++ b/app/src/main/java/com/fox2code/mmm/manager/ModuleInfo.java @@ -28,6 +28,7 @@ public class ModuleInfo { // Community restrictions public int minMagisk; public int minApi; + public int maxApi; // Module status (0 if not from Module Manager) public int flags; diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index 7c308e0..cf22fa5 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -1,6 +1,8 @@ package com.fox2code.mmm.settings; import android.os.Bundle; +import android.text.method.Touch; +import android.widget.Toast; import androidx.annotation.StyleRes; import androidx.fragment.app.FragmentTransaction; @@ -8,9 +10,12 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import com.fox2code.mmm.BuildConfig; +import com.fox2code.mmm.Constants; import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.R; import com.fox2code.mmm.compat.CompatActivity; +import com.fox2code.mmm.installer.InstallerInitializer; import com.fox2code.mmm.repo.RepoData; import com.fox2code.mmm.repo.RepoManager; import com.fox2code.mmm.utils.IntentHelper; @@ -18,8 +23,11 @@ import com.mikepenz.aboutlibraries.LibsBuilder; import com.topjohnwu.superuser.internal.UiThreadHandler; public class SettingsActivity extends CompatActivity { + private static int devModeStep = 0; + @Override protected void onCreate(Bundle savedInstanceState) { + devModeStep = 0; super.onCreate(savedInstanceState); this.setDisplayHomeAsUpEnabled(true); setContentView(R.layout.settings_activity); @@ -41,7 +49,13 @@ public class SettingsActivity extends CompatActivity { setPreferencesFromResource(R.xml.root_preferences, rootKey); ListPreference themePreference = findPreference("pref_theme"); themePreference.setSummaryProvider(p -> themePreference.getEntry()); + themePreference.setOnPreferenceClickListener(p -> { + // You need to reboot your device at least once to be able to access dev-mode + if (!MainApplication.isFirstBoot()) devModeStep = 1; + return false; + }); themePreference.setOnPreferenceChangeListener((preference, newValue) -> { + devModeStep = 0; @StyleRes int themeResId; switch (String.valueOf(newValue)) { default: @@ -62,6 +76,10 @@ public class SettingsActivity extends CompatActivity { if ("dark".equals(themePreference.getValue())) { findPreference("pref_force_dark_terminal").setEnabled(false); } + if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND + || !MainApplication.isDeveloper()) { + findPreference("pref_use_magisk_install_command").setVisible(false); + } setRepoNameResolution("pref_repo_main", RepoManager.MAGISK_REPO, "Magisk Modules Repo (Official)", RepoManager.MAGISK_REPO_HOMEPAGE); @@ -71,10 +89,19 @@ public class SettingsActivity extends CompatActivity { .withFields(R.string.class.getFields()).withShowLoadingProgress(false) .withLicenseShown(true).withAboutMinimalDesign(false); findPreference("pref_source_code").setOnPreferenceClickListener(p -> { + if (devModeStep == 2 && (BuildConfig.DEBUG || !MainApplication.isDeveloper())) { + devModeStep = 0; + MainApplication.getSharedPreferences().edit() + .putBoolean("developer", true).apply(); + Toast.makeText(getContext(), // Tell the user something changed + R.string.dev_mode_enabled, Toast.LENGTH_SHORT).show(); + return true; + } IntentHelper.openUrl(p.getContext(), "https://github.com/Fox2Code/FoxMagiskModuleManager"); return true; }); findPreference("pref_show_licenses").setOnPreferenceClickListener(p -> { + devModeStep = devModeStep == 1 ? 2 : 0; CompatActivity compatActivity = getCompatActivity(this); compatActivity.setOnBackPressedCallback(this); compatActivity.setTitle(R.string.licenses); diff --git a/app/src/main/java/com/fox2code/mmm/utils/Http.java b/app/src/main/java/com/fox2code/mmm/utils/Http.java index 76bcadb..ac86414 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/Http.java +++ b/app/src/main/java/com/fox2code/mmm/utils/Http.java @@ -50,15 +50,15 @@ public class Http { InetAddress.getByName("2606:4700:4700::0064"), InetAddress.getByName("2606:4700:4700::6400") ).resolvePrivateAddresses(true).build()); - } catch (UnknownHostException e) { - e.printStackTrace(); + } catch (UnknownHostException|RuntimeException e) { + Log.e("Http", "Failed to init DoH", e); } httpClient = httpclientBuilder.build(); MainApplication mainApplication = MainApplication.getINSTANCE(); if (mainApplication != null) { httpclientBuilder.cache(new Cache( new File(mainApplication.getCacheDir(), "http_cache"), - 1024L * 1024L)); // 1Mo of cache + 2L * 1024L * 1024L)); // 2Mib of cache httpclientBuilder.cookieJar(new CDNCookieJar()); httpClientCachable = httpclientBuilder.build(); } else { diff --git a/app/src/main/java/com/fox2code/mmm/utils/PropUtils.java b/app/src/main/java/com/fox2code/mmm/utils/PropUtils.java index 90d422e..d801911 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/PropUtils.java +++ b/app/src/main/java/com/fox2code/mmm/utils/PropUtils.java @@ -12,6 +12,7 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; public class PropUtils { + private static final HashMap moduleSupportsFallbacks = new HashMap<>(); private static final HashMap moduleConfigsFallbacks = new HashMap<>(); private static final HashMap moduleMinApiFallbacks = new HashMap<>(); private static final int RIRU_MIN_API; @@ -19,6 +20,11 @@ public class PropUtils { // Note: These fallback values may not be up-to-date // They are only used if modules don't define the metadata static { + // Support are pages or groups where the user can get support for the module + moduleSupportsFallbacks.put("aospill", "https://t.me/PannekoX"); + moduleSupportsFallbacks.put("quickstepswitcher", "https://t.me/QuickstepSwitcherSupport"); + moduleSupportsFallbacks.put("riru_edxposed", "https://t.me/EdXposed"); + moduleSupportsFallbacks.put("riru_lsposed", "https://github.com/LSPosed/LSPosed/issues/"); // Config are application installed by modules that allow them to be configured moduleConfigsFallbacks.put("quickstepswitcher", "xyz.paphonb.quickstepswitcher"); moduleConfigsFallbacks.put("riru_edxposed", "org.meowcat.edxposed.manager"); @@ -107,6 +113,13 @@ public class PropUtils { moduleInfo.minApi = 0; } break; + case "maxApi": + try { + moduleInfo.maxApi = Integer.parseInt(value); + } catch (Exception e) { + moduleInfo.maxApi = 0; + } + break; } } } @@ -130,6 +143,9 @@ public class PropUtils { || moduleInfo.id.startsWith("riru-")) moduleInfo.minApi = RIRU_MIN_API; } + if (moduleInfo.support == null) { + moduleInfo.support = moduleSupportsFallbacks.get(moduleInfo.id); + } if (moduleInfo.config == null) { moduleInfo.config = moduleConfigsFallbacks.get(moduleInfo.id); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a585bc4..6898210 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -41,4 +41,10 @@ Your current file picker failed to give access to the file. Remote install Your file picker returned a non standard response. + Use magisk module install command + + During test it caused problems to the module install error diagnosis tool, + so I hid this option behind dev-mode, enable this at your own risk! + + Developer mode enabled \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 573ae9a..0990b4e 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -29,6 +29,13 @@ app:icon="@drawable/ic_baseline_hide_source_24" app:title="@string/show_incompatible_pref" app:summary="@string/show_incompatible_desc"/> + +