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

Commit 82d4282

Browse files
authored
Merge branch 'Fox2Code:master' into master
2 parents 4cd3fcb + 680abcb commit 82d4282

File tree

14 files changed

+321
-36
lines changed

14 files changed

+321
-36
lines changed

app/build.gradle

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

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}
@@ -64,7 +64,7 @@ dependencies {
6464
// Utils
6565
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3'
6666
implementation 'com.squareup.okhttp3:okhttp-brotli:4.9.3'
67-
implementation 'com.github.topjohnwu.libsu:io:3.2.1'
67+
implementation 'com.github.topjohnwu.libsu:io:4.0.0'
6868

6969
// Markdown
7070
implementation "io.noties.markwon:core:4.6.2"
@@ -74,6 +74,9 @@ dependencies {
7474
annotationProcessor "io.noties:prism4j-bundler:2.0.0"
7575
implementation "com.caverock:androidsvg:1.4"
7676

77+
// Utils for compat
78+
compileOnly "org.robolectric:android-all:11-robolectric-6757853"
79+
7780
// Test
7881
testImplementation 'junit:junit:4.+'
7982
androidTestImplementation 'androidx.test.ext:junit:1.1.3'

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

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,63 @@
22

33
import android.util.Log;
44

5+
import com.fox2code.mmm.utils.Files;
56
import com.fox2code.mmm.utils.Http;
67

78
import org.json.JSONArray;
89
import org.json.JSONObject;
910

11+
import java.io.BufferedReader;
12+
import java.io.ByteArrayInputStream;
13+
import java.io.File;
14+
import java.io.FileInputStream;
15+
import java.io.IOException;
16+
import java.io.InputStream;
17+
import java.io.InputStreamReader;
1018
import java.nio.charset.StandardCharsets;
19+
import java.util.HashMap;
1120

1221
// See https://docs.github.com/en/rest/reference/repos#releases
1322
public class AppUpdateManager {
23+
public static int FLAG_COMPAT_LOW_QUALITY = 0x01;
24+
public static int FLAG_COMPAT_NO_EXT = 0x02;
25+
public static int FLAG_COMPAT_MAGISK_CMD = 0x04;
26+
public static int FLAG_COMPAT_NEED_32BIT = 0x08;
1427
private static final String TAG = "AppUpdateManager";
1528
private static final AppUpdateManager INSTANCE = new AppUpdateManager();
1629
private static final String RELEASES_API_URL =
1730
"https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases";
31+
private static final String COMPAT_API_URL =
32+
"https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases";
1833

1934
public static AppUpdateManager getAppUpdateManager() {
2035
return INSTANCE;
2136
}
2237

38+
private final HashMap<String, Integer> compatDataId = new HashMap<>();
2339
private final Object updateLock = new Object();
40+
private final File compatFile;
2441
private String latestRelease;
2542
private String latestPreRelease;
2643
private long lastChecked;
2744
private boolean preReleaseNewer;
2845
private boolean lastCheckSuccess;
2946

3047
private AppUpdateManager() {
48+
this.compatFile = new File(MainApplication.getINSTANCE().getFilesDir(), "compat.txt");
3149
this.latestRelease = MainApplication.getBootSharedPreferences()
3250
.getString("updater_latest_release", BuildConfig.VERSION_NAME);
3351
this.latestPreRelease = MainApplication.getBootSharedPreferences()
3452
.getString("updater_latest_pre_release", BuildConfig.VERSION_NAME);
3553
this.lastChecked = 0;
3654
this.preReleaseNewer = true;
55+
if (this.compatFile.isFile()) {
56+
try {
57+
this.parseCompatibilityFlags(new FileInputStream(this.compatFile));
58+
} catch (IOException e) {
59+
e.printStackTrace();
60+
}
61+
}
3762
}
3863

3964
// Return true if should show a notification
@@ -95,6 +120,31 @@ public boolean checkUpdate(boolean force) {
95120
return this.peekShouldUpdate();
96121
}
97122

123+
public void checkUpdateCompat() {
124+
if (this.compatFile.exists()) {
125+
long lastUpdate = this.compatFile.lastModified();
126+
if (lastUpdate <= System.currentTimeMillis() &&
127+
lastUpdate + 600_000L > System.currentTimeMillis()) {
128+
return; // Skip update
129+
}
130+
}
131+
try {
132+
JSONObject object = new JSONObject(new String(Http.doHttpGet(
133+
COMPAT_API_URL, false), StandardCharsets.UTF_8));
134+
if (object.isNull("body")) {
135+
compatDataId.clear();
136+
Files.write(compatFile, new byte[0]);
137+
return;
138+
}
139+
byte[] rawData = object.getString("body")
140+
.getBytes(StandardCharsets.UTF_8);
141+
this.parseCompatibilityFlags(new ByteArrayInputStream(rawData));
142+
Files.write(compatFile, rawData);
143+
} catch (Exception e) {
144+
Log.e("AppUpdateManager", "Failed to update compat list", e);
145+
}
146+
}
147+
98148
public boolean peekShouldUpdate() {
99149
return !(BuildConfig.VERSION_NAME.equals(this.latestRelease) ||
100150
(this.preReleaseNewer &&
@@ -109,4 +159,46 @@ public boolean peekHasUpdate() {
109159
public boolean isLastCheckSuccess() {
110160
return lastCheckSuccess;
111161
}
162+
163+
private void parseCompatibilityFlags(InputStream inputStream) throws IOException {
164+
compatDataId.clear();
165+
BufferedReader bufferedReader = new BufferedReader(
166+
new InputStreamReader(inputStream, StandardCharsets.UTF_8));
167+
String line;
168+
while ((line = bufferedReader.readLine()) != null) {
169+
line = line.trim();
170+
if (line.isEmpty() || line.startsWith("#")) continue;
171+
int i = line.indexOf('/');
172+
if (i == -1) continue;
173+
int value = 0;
174+
for (String arg : line.substring(i + 1).split(",")) {
175+
switch (arg) {
176+
default:
177+
break;
178+
case "lowQuality":
179+
value |= FLAG_COMPAT_LOW_QUALITY;
180+
break;
181+
case "noExt":
182+
value |= FLAG_COMPAT_NO_EXT;
183+
break;
184+
case "magiskCmd":
185+
value |= FLAG_COMPAT_MAGISK_CMD;
186+
break;
187+
case "need32bit":
188+
value |= FLAG_COMPAT_NEED_32BIT;
189+
break;
190+
}
191+
}
192+
compatDataId.put(line.substring(0, i), value);
193+
}
194+
}
195+
196+
public int getCompatibilityFlags(String moduleId) {
197+
Integer compatFlags = compatDataId.get(moduleId);
198+
return compatFlags == null ? 0 : compatFlags;
199+
}
200+
201+
public static int getFlagsForModule(String moduleId) {
202+
return INSTANCE.getCompatibilityFlags(moduleId);
203+
}
112204
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat
117117
MainActivity.this.searchView.clearFocus();
118118
}
119119
});
120+
this.searchCard.setRadius(this.searchCard.getHeight() / 2F);
120121
this.searchView.setMinimumHeight(CompatDisplay.dpToPixel(16));
121122
this.searchView.setImeOptions(EditorInfo.IME_ACTION_SEARCH |
122123
EditorInfo.IME_FLAG_NO_FULLSCREEN);
@@ -179,6 +180,8 @@ public void commonNext() {
179180
} else {
180181
if (AppUpdateManager.getAppUpdateManager().checkUpdate(true))
181182
moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE);
183+
if (AppUpdateManager.getAppUpdateManager().isLastCheckSuccess())
184+
AppUpdateManager.getAppUpdateManager().checkUpdateCompat();
182185
if (max != 0) {
183186
int current = 0;
184187
for (LocalModuleInfo localModuleInfo :
@@ -241,9 +244,10 @@ private void updateScreenInsets(Configuration configuration) {
241244
swipeRefreshLayoutOrigStartOffset + combinedBarsHeight,
242245
swipeRefreshLayoutOrigEndOffset + combinedBarsHeight);
243246
this.moduleViewListBuilder.setHeaderPx(
244-
actionBarHeight + CompatDisplay.dpToPixel(4));
247+
actionBarHeight + CompatDisplay.dpToPixel(8));
245248
this.moduleViewListBuilder.setFooterPx(
246249
bottomInset + this.searchCard.getHeight());
250+
this.searchCard.setRadius(this.searchCard.getHeight() / 2F);
247251
this.moduleViewListBuilder.updateInsets();
248252
this.actionBarBlur.invalidate();
249253
this.overScrollInsetTop = combinedBarsHeight;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public ViewHolder(@NonNull View itemView) {
104104
}
105105
}
106106
});
107+
this.buttonAction.setClickable(false);
107108
this.switchMaterial.setEnabled(false);
108109
this.switchMaterial.setOnCheckedChangeListener((v, checked) -> {
109110
if (this.initState) return; // Skip if non user

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public void appendRemoteModules() {
7676
RepoManager repoManager = RepoManager.getINSTANCE();
7777
repoManager.runAfterUpdate(() -> {
7878
Log.i(TAG, "A2: " + repoManager.getModules().size());
79+
boolean no32bitSupport = Build.SUPPORTED_32_BIT_ABIS.length == 0;
7980
for (RepoModule repoModule : repoManager.getModules().values()) {
8081
if (!repoModule.repoData.isEnabled()) continue;
8182
ModuleInfo moduleInfo = repoModule.moduleInfo;
@@ -84,9 +85,11 @@ public void appendRemoteModules() {
8485
// Only check Magisk compatibility if root is present
8586
(InstallerInitializer.peekMagiskPath() != null &&
8687
repoModule.moduleInfo.minMagisk >
87-
InstallerInitializer.peekMagiskVersion()
88-
)))
89-
continue; // Skip adding incompatible modules
88+
InstallerInitializer.peekMagiskVersion())) ||
89+
// If 64bit only system, skip 32bit only modules
90+
(no32bitSupport && (AppUpdateManager.getFlagsForModule(repoModule.id)
91+
& AppUpdateManager.FLAG_COMPAT_NEED_32BIT) != 0)
92+
) continue; // Skip adding incompatible modules
9093
ModuleHolder moduleHolder = this.mappedModuleHolders.get(repoModule.id);
9194
if (moduleHolder == null) {
9295
this.mappedModuleHolders.put(repoModule.id,

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ public boolean shouldRemove() {
3131
return !MainApplication.isShowcaseMode();
3232
}
3333
},
34-
NO_ROOT(R.string.fail_root_magisk, R.drawable.ic_baseline_numbers_24) {
34+
NO_ROOT(R.string.fail_root_magisk, R.drawable.ic_baseline_numbers_24, v -> {
35+
IntentHelper.openUrl(v.getContext(), "https://github.com/topjohnwu/Magisk");
36+
}) {
3537
@Override
3638
public boolean shouldRemove() {
3739
return InstallerInitializer.peekMagiskPath() != null;
3840
}
3941
},
40-
MAGISK_OUTDATED(R.string.magisk_outdated, R.drawable.ic_baseline_update_24) {
42+
MAGISK_OUTDATED(R.string.magisk_outdated, R.drawable.ic_baseline_update_24, v -> {
43+
IntentHelper.openUrl(v.getContext(), "https://github.com/topjohnwu/Magisk");
44+
}) {
4145
@Override
4246
public boolean shouldRemove() {
4347
return InstallerInitializer.peekMagiskPath() == null ||
@@ -128,7 +132,11 @@ public boolean shouldRemove() {
128132
public final boolean special;
129133

130134
NotificationType(@StringRes int textId, int iconId) {
131-
this(textId, iconId, R.attr.colorError, R.attr.colorOnPrimary); //R.attr.colorOnError);
135+
this(textId, iconId, R.attr.colorError, R.attr.colorOnPrimary);
136+
}
137+
138+
NotificationType(@StringRes int textId, int iconId, View.OnClickListener onClickListener) {
139+
this(textId, iconId, R.attr.colorError, R.attr.colorOnPrimary, onClickListener);
132140
}
133141

134142
NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr) {

app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyActivity.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
8181
setActionBarBackground(null);
8282
this.setDisplayHomeAsUpEnabled(true);
8383
if (title == null || title.isEmpty()) {
84-
this.setTitle(title);
85-
} else {
8684
this.setTitle("Androidacy");
85+
} else {
86+
this.setTitle(title);
8787
}
8888
if (allowInstall || title == null || title.isEmpty()) {
8989
this.hideActionBar();
@@ -120,9 +120,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
120120
public boolean shouldOverrideUrlLoading(
121121
@NonNull WebView view, @NonNull WebResourceRequest request) {
122122
// Don't open non Androidacy urls inside WebView
123-
if (request.isForMainFrame() && !(request.getUrl().getScheme().equals("intent") ||
124-
AndroidacyUtil.isAndroidacyLink(request.getUrl()))) {
125-
IntentHelper.openUrl(view.getContext(), request.getUrl().toString());
123+
if (request.isForMainFrame() &&
124+
!AndroidacyUtil.isAndroidacyLink(request.getUrl())) {
125+
IntentHelper.openUri(view.getContext(), request.getUrl().toString());
126126
return true;
127127
}
128128
return false;

app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.graphics.drawable.Drawable;
1111
import android.os.Build;
1212
import android.os.Bundle;
13+
import android.os.SystemProperties;
1314
import android.util.Log;
1415
import android.util.TypedValue;
1516
import android.view.KeyCharacterMap;
@@ -88,8 +89,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
8889
if (!this.onCreateCalled) {
8990
this.getLayoutInflater().setFactory2(new LayoutInflaterFactory(this.getDelegate())
9091
.addOnViewCreatedListener(WindowInsetsHelper.Companion.getLISTENER()));
91-
this.hasHardwareNavBar = ViewConfiguration.get(this).hasPermanentMenuKey() ||
92-
KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
92+
this.hasHardwareNavBar = this.hasHardwareNavBar0();
9393
this.onCreateCalledOnce = true;
9494
}
9595
Application application = this.getApplication();
@@ -104,6 +104,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
104104

105105
@Override
106106
protected void onResume() {
107+
this.hasHardwareNavBar = this.hasHardwareNavBar0();
107108
super.onResume();
108109
this.refreshUI();
109110
}
@@ -287,9 +288,13 @@ public int getNavigationBarHeight() {
287288

288289
public boolean hasHardwareNavBar() {
289290
// If onCreate has not been called yet, cached value is not valid
290-
return this.onCreateCalledOnce ? this.hasHardwareNavBar :
291-
ViewConfiguration.get(this).hasPermanentMenuKey() ||
292-
KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
291+
return this.onCreateCalledOnce ? this.hasHardwareNavBar : this.hasHardwareNavBar0();
292+
}
293+
294+
private boolean hasHardwareNavBar0() {
295+
return (ViewConfiguration.get(this).hasPermanentMenuKey() ||
296+
KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)) &&
297+
!"0".equals(SystemProperties.get("qemu.hw.mainkeys"));
293298
}
294299

295300
public void setActionBarExtraMenuButton(@DrawableRes int drawableResId,

0 commit comments

Comments
 (0)