Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 6574115

Browse files
committed
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
1 parent 6a608ff commit 6574115

19 files changed

+222
-34
lines changed

DEVELOPERS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ This the manager support these new properties
2424
```properties
2525
# Fox's Mmm supported properties
2626
minApi=<int>
27+
maxApi=<int>
2728
minMagisk=<int>
2829
support=<url>
2930
donate=<url>
3031
config=<package>
3132
```
3233
(Note: All urls must start with `https://`, or else will be ignored)
3334

34-
- `minApi` tell the manager which is the minimum SDK version required for the module
35+
- `minApi` and `maxApi` tell the manager which is the SDK version range the module support
3536
(See: [Codenames, Tags, and Build Numbers](https://source.android.com/setup/start/build-numbers))
3637
- `minMagisk` tell the manager which is the minimum Magisk version required for the module
3738
(Often for magisk `xx.y` the version code is `xxy00`)

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ So I made my own app to do that! :3
55

66
**This app is not officially supported by Magisk or it's developers**
77

8+
## Requirements
9+
10+
Minimum:
11+
- Android 5.0+
12+
- Magisk 19.0+
13+
14+
Recommended:
15+
- Android 6.0+
16+
- Magisk 21.2+
17+
818
## For users
919

1020
Related commits:
@@ -24,12 +34,14 @@ If a module is in both repo, the manager will just pick the most up to date vers
2434

2535
## For developers
2636

27-
The manager can read new meta keys to allow modules to customize their entry
37+
The manager can read new meta keys to allow modules to customize their own entry
2838

29-
It use `module.prop` the `minApi=<int>` and `minMagisk=<int>` properties to detect compatibility
30-
And use the `support=<url>` and `donate=<url>` key to detect module related links
39+
It also use `minApi`, `maxApi` and `minMagisk` in the `module.prop` to detect compatibility
40+
And support the `support` and `donate` properties to allow them to add their own support links
41+
(Note: the manager use fallback values for some modules, see developer documentation for more info)
3142

32-
It also add new ways to control the installer ui via a new `#!` command system
43+
It also add new ways to control the installer ui via a new `#!` command system
44+
It allow module developers to have a more customizable install experience
3345

3446
For more information please check the [developer documentation](DEVELOPERS.md)
3547

app/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "com.fox2code.mmm"
1111
minSdk 21
1212
targetSdk 30
13-
versionCode 3
14-
versionName "0.0.3"
13+
versionCode 4
14+
versionName "0.1.0"
1515

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}
@@ -39,6 +39,10 @@ aboutLibraries {
3939
}
4040
}
4141

42+
configurations {
43+
implementation.exclude group: 'org.jetbrains' , module: 'annotations'
44+
}
45+
4246
dependencies {
4347
// UI
4448
implementation 'androidx.appcompat:appcompat:1.3.1'
@@ -57,6 +61,8 @@ dependencies {
5761
implementation "io.noties.markwon:core:4.6.2"
5862
implementation "io.noties.markwon:html:4.6.2"
5963
implementation "io.noties.markwon:image:4.6.2"
64+
implementation "io.noties.markwon:syntax-highlight:4.6.2"
65+
annotationProcessor "io.noties:prism4j-bundler:2.0.0"
6066
implementation "com.caverock:androidsvg:1.4"
6167

6268
// Test

app/src/main/assets/module_installer_compat.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ mount /data 2>/dev/null
2929
. /data/adb/magisk/util_functions.sh
3030
[ $MAGISK_VER_CODE -lt 19000 ] && require_new_magisk
3131

32+
# Add grep_get_prop implementation if missing
33+
if ! type grep_get_prop &>/dev/null; then
34+
grep_get_prop() {
35+
local result=$(grep_prop $@)
36+
if [ -z "$result" ]; then
37+
# Fallback to getprop
38+
getprop "$1"
39+
else
40+
echo $result
41+
fi
42+
}
43+
fi
44+
3245
if [ $MAGISK_VER_CODE -ge 20400 ]; then
3346
# New Magisk have complete installation logic within util_functions.sh
3447
install_module
@@ -84,6 +97,7 @@ mount_partitions
8497

8598
# Detect version and architecture
8699
api_level_arch_detect
100+
API=$(grep_get_prop ro.build.version.sdk)
87101

88102
# Setup busybox and binaries
89103
$BOOTMODE && boot_actions || recovery_actions

app/src/main/java/com/fox2code/mmm/ActionButtonType.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ public void doAction(ImageButton button, ModuleHolder moduleHolder) {
5252
@Override
5353
public void update(ImageButton button, ModuleHolder moduleHolder) {
5454
int icon = moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_UNINSTALLING) ?
55-
R.drawable.ic_baseline_delete_outline_24 :
56-
moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE) ?
55+
R.drawable.ic_baseline_delete_outline_24 : (
56+
// We can't trust active flag on first boot
57+
MainApplication.isFirstBoot() ||
58+
moduleHolder.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)) ?
5759
R.drawable.ic_baseline_delete_24 :
5860
R.drawable.ic_baseline_delete_forever_24;
5961
button.setImageResource(icon);
@@ -70,7 +72,9 @@ public void doAction(ImageButton button, ModuleHolder moduleHolder) {
7072

7173
@Override
7274
public boolean doActionLong(ImageButton button, ModuleHolder moduleHolder) {
73-
if (moduleHolder.moduleInfo.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)) return false;
75+
// We can't trust active flag on first boot
76+
if (moduleHolder.moduleInfo.hasFlag(ModuleInfo.FLAG_MODULE_ACTIVE)
77+
|| MainApplication.isFirstBoot()) return false;
7478
new AlertDialog.Builder(button.getContext()).setTitle(R.string.master_delete)
7579
.setPositiveButton(R.string.master_delete_yes, (v, i) -> {
7680
if (!ModuleManager.getINSTANCE().masterClear(moduleHolder.moduleInfo)) {

app/src/main/java/com/fox2code/mmm/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public class Constants {
44
public static final int MAGISK_VER_CODE_FLAT_MODULES = 19000;
55
public static final int MAGISK_VER_CODE_UTIL_INSTALL = 20400;
66
public static final int MAGISK_VER_CODE_PATH_SUPPORT = 21000;
7+
public static final int MAGISK_VER_CODE_INSTALL_COMMAND = 21200;
78
public static final int MAGISK_VER_CODE_MAGISK_ZYGOTE = 23002;
89
public static final String INTENT_INSTALL_INTERNAL =
910
BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL";

app/src/main/java/com/fox2code/mmm/MainActivity.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat
9090
public void onPathReceived(String path) {
9191
Log.i(TAG, "Got magisk path: " + path);
9292
if (InstallerInitializer.peekMagiskVersion() <
93-
Constants.MAGISK_VER_CODE_PATH_SUPPORT)
93+
Constants.MAGISK_VER_CODE_INSTALL_COMMAND)
9494
moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED);
9595
if (!MainApplication.isShowcaseMode())
9696
moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE);
@@ -159,7 +159,7 @@ public void refreshUI() {
159159
@Override
160160
public void onPathReceived(String path) {
161161
if (InstallerInitializer.peekMagiskVersion() <
162-
Constants.MAGISK_VER_CODE_PATH_SUPPORT)
162+
Constants.MAGISK_VER_CODE_INSTALL_COMMAND)
163163
moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED);
164164
if (!MainApplication.isShowcaseMode())
165165
moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE);

app/src/main/java/com/fox2code/mmm/MainApplication.java

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import android.content.SharedPreferences;
77
import android.content.res.Configuration;
88
import android.content.res.Resources;
9+
import android.graphics.Color;
910
import android.os.SystemClock;
11+
import android.text.SpannableStringBuilder;
1012

1113
import androidx.annotation.NonNull;
1214
import androidx.annotation.StyleRes;
@@ -27,7 +29,17 @@
2729
import io.noties.markwon.html.HtmlPlugin;
2830
import io.noties.markwon.image.ImagesPlugin;
2931
import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
32+
import io.noties.markwon.syntax.Prism4jTheme;
33+
import io.noties.markwon.syntax.Prism4jThemeDarkula;
34+
import io.noties.markwon.syntax.Prism4jThemeDefault;
35+
import io.noties.markwon.syntax.SyntaxHighlightPlugin;
36+
import io.noties.prism4j.Prism4j;
37+
import io.noties.prism4j.annotations.PrismBundle;
3038

39+
@PrismBundle(
40+
includeAll = true,
41+
grammarLocatorClassName = ".Prism4jGrammarLocator"
42+
)
3143
public class MainApplication extends Application implements CompatActivity.ApplicationCallbacks {
3244
private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001
3345
private static Locale timeFormatLocale =
@@ -38,6 +50,7 @@ public class MainApplication extends Application implements CompatActivity.Appli
3850
private static final int secret;
3951
private static SharedPreferences bootSharedPreferences;
4052
private static MainApplication INSTANCE;
53+
private static boolean firstBoot;
4154

4255
static {
4356
Shell.setDefaultBuilder(shellBuilder = Shell.Builder.create()
@@ -75,6 +88,32 @@ public static boolean isForceDarkTerminal() {
7588
return getSharedPreferences().getBoolean("pref_force_dark_terminal", false);
7689
}
7790

91+
public static boolean isDeveloper() {
92+
return BuildConfig.DEBUG ||
93+
getSharedPreferences().getBoolean("developer", false);
94+
}
95+
96+
public static boolean isUsingMagiskCommand() {
97+
return InstallerInitializer.peekMagiskVersion() >= Constants.MAGISK_VER_CODE_INSTALL_COMMAND
98+
&& getSharedPreferences().getBoolean("pref_use_magisk_install_command", false)
99+
&& isDeveloper();
100+
}
101+
102+
public static boolean isFirstBoot() {
103+
return firstBoot;
104+
}
105+
106+
public static void notifyBootListenerCompleted() {
107+
if (MainApplication.bootSharedPreferences != null) {
108+
MainApplication.bootSharedPreferences.edit()
109+
.putBoolean("first_boot", false).apply();
110+
} else if (MainApplication.INSTANCE != null) {
111+
MainApplication.getSharedPreferences().edit()
112+
.putBoolean("first_boot", false).apply();
113+
}
114+
firstBoot = false;
115+
}
116+
78117
public static boolean hasGottenRootAccess() {
79118
return getSharedPreferences().getBoolean("has_root_access", false);
80119
}
@@ -104,18 +143,48 @@ public static String formatTime(long timeStamp) {
104143
public Markwon getMarkwon() {
105144
if (this.markwon != null)
106145
return this.markwon;
107-
ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext =
108-
new ContextThemeWrapper(this, this.managerThemeResId);
146+
ContextThemeWrapper contextThemeWrapper = this.markwonThemeContext;
147+
if (contextThemeWrapper == null)
148+
contextThemeWrapper = this.markwonThemeContext =
149+
new ContextThemeWrapper(this, this.managerThemeResId);
109150
Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create())
151+
.usePlugin(SyntaxHighlightPlugin.create(
152+
new Prism4j(new Prism4jGrammarLocator()), new Prism4jSwitchTheme()))
110153
.usePlugin(ImagesPlugin.create().addSchemeHandler(
111154
OkHttpNetworkSchemeHandler.create(Http.getHttpclientWithCache()))).build();
112155
return this.markwon = markwon;
113156
}
114157

158+
private class Prism4jSwitchTheme implements Prism4jTheme {
159+
private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT);
160+
private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT);
161+
162+
private Prism4jTheme getTheme() {
163+
return isLightTheme() ? this.light : this.dark;
164+
}
165+
166+
@Override
167+
public int background() {
168+
return this.getTheme().background();
169+
}
170+
171+
@Override
172+
public int textColor() {
173+
return this.getTheme().textColor();
174+
}
175+
176+
@Override
177+
public void apply(@NonNull String language, @NonNull Prism4j.Syntax syntax,
178+
@NonNull SpannableStringBuilder builder, int start, int end) {
179+
this.getTheme().apply(language, syntax, builder, start, end);
180+
}
181+
}
182+
115183
public void setManagerThemeResId(@StyleRes int resId) {
116184
this.managerThemeResId = resId;
117185
if (this.markwonThemeContext != null)
118186
this.markwonThemeContext.setTheme(resId);
187+
this.markwon = null;
119188
}
120189

121190
@StyleRes
@@ -144,13 +213,22 @@ public boolean isLightTheme() {
144213
public void onCreate() {
145214
INSTANCE = this;
146215
super.onCreate();
216+
SharedPreferences sharedPreferences = MainApplication.getSharedPreferences();
147217
// We are only one process so it's ok to do this
148218
SharedPreferences bootPrefs = MainApplication.bootSharedPreferences =
149219
this.getSharedPreferences("mmm_boot", MODE_PRIVATE);
150220
long lastBoot = System.currentTimeMillis() - SystemClock.elapsedRealtime();
151221
long lastBootPrefs = bootPrefs.getLong("last_boot", 0);
152222
if (lastBootPrefs == 0 || Math.abs(lastBoot - lastBootPrefs) > 100) {
153-
bootPrefs.edit().clear().putLong("last_boot", lastBoot).apply();
223+
boolean firstBoot = sharedPreferences.getBoolean("first_boot", true);
224+
bootPrefs.edit().clear().putLong("last_boot", lastBoot)
225+
.putBoolean("first_boot", firstBoot).apply();
226+
if (firstBoot) {
227+
sharedPreferences.edit().putBoolean("first_boot", false).apply();
228+
}
229+
MainApplication.firstBoot = firstBoot;
230+
} else {
231+
MainApplication.firstBoot = bootPrefs.getBoolean("first_boot", false);
154232
}
155233
@StyleRes int themeResId;
156234
switch (getSharedPreferences().getString("pref_theme", "system")) {

app/src/main/java/com/fox2code/mmm/ModuleViewListBuilder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ public void appendRemoteModules() {
7272
repoManager.runAfterUpdate(() -> {
7373
Log.i(TAG, "A2: " + repoManager.getModules().size());
7474
for (RepoModule repoModule : repoManager.getModules().values()) {
75-
if (!showIncompatible && (repoModule.moduleInfo.minApi > Build.VERSION.SDK_INT ||
75+
ModuleInfo moduleInfo = repoModule.moduleInfo;
76+
if (!showIncompatible && (moduleInfo.minApi > Build.VERSION.SDK_INT ||
77+
(moduleInfo.maxApi != 0 && moduleInfo.maxApi < Build.VERSION.SDK_INT) ||
7678
// Only check Magisk compatibility if root is present
7779
(InstallerInitializer.peekMagiskPath() != null &&
7880
repoModule.moduleInfo.minMagisk >

app/src/main/java/com/fox2code/mmm/NotificationType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public boolean shouldRemove() {
4242
public boolean shouldRemove() {
4343
return InstallerInitializer.peekMagiskPath() == null ||
4444
InstallerInitializer.peekMagiskVersion() >=
45-
Constants.MAGISK_VER_CODE_PATH_SUPPORT;
45+
Constants.MAGISK_VER_CODE_INSTALL_COMMAND;
4646
}
4747
},
4848
NO_INTERNET(R.string.fail_internet, R.drawable.ic_baseline_cloud_off_24) {

0 commit comments

Comments
 (0)