diff --git a/app/build.gradle b/app/build.gradle index 268b1f3..4d527d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ android { // Get the androidacy client ID from the androidacy.properties Properties properties = new Properties() - // If androidacy.properties doesn't exist, use the default client ID which is limited + // If androidacy.properties doesn't exist, use the fdroid client ID which is limited // to 50 requests per minute if (project.rootProject.file('androidacy.properties').exists()) { properties.load(project.rootProject.file('androidacy.properties').newDataInputStream()) @@ -212,7 +212,7 @@ dependencies { implementation "dev.rikka.rikkax.insets:insets:1.3.0" implementation 'com.github.Dimezis:BlurView:version-2.0.2' implementation 'com.github.KieronQuinn:MonetCompat:0.4.1' - implementation 'com.github.Fox2Code:FoxCompat:0.1.5' + implementation 'com.github.Fox2Code:FoxCompat:0.1.6' // Update the version code in the root build.gradle implementation "com.mikepenz:aboutlibraries:${latestAboutLibsRelease}" @@ -220,8 +220,9 @@ dependencies { implementation 'androidx.work:work-runtime:2.7.1' implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:5.0.0-alpha.10' implementation 'com.squareup.okhttp3:okhttp-brotli:5.0.0-alpha.10' - // Chromium cronet from microG - implementation fileTree(dir: 'libs', include: '*.jar') + // Chromium cronet from androidacy + implementation 'com.androidacy:cronet-common:108.0.5359.95' + implementation 'com.androidacy:cronet-native:108.0.5359.95' // Force prefer our own version of Cronet implementation 'com.github.topjohnwu.libsu:io:5.0.1' implementation 'com.github.Fox2Code:RosettaX:1.0.9' diff --git a/app/libs/arm64-v8a.jar b/app/libs/arm64-v8a.jar deleted file mode 100644 index 315c2b8..0000000 Binary files a/app/libs/arm64-v8a.jar and /dev/null differ diff --git a/app/libs/armeabi-v7a.jar b/app/libs/armeabi-v7a.jar deleted file mode 100644 index c3c8f84..0000000 Binary files a/app/libs/armeabi-v7a.jar and /dev/null differ diff --git a/app/libs/cronet_impl_common_java.jar b/app/libs/cronet_impl_common_java.jar deleted file mode 100644 index cc492a6..0000000 Binary files a/app/libs/cronet_impl_common_java.jar and /dev/null differ diff --git a/app/libs/cronet_impl_native_java.jar b/app/libs/cronet_impl_native_java.jar deleted file mode 100644 index ecb9d8a..0000000 Binary files a/app/libs/cronet_impl_native_java.jar and /dev/null differ diff --git a/app/libs/x86.jar b/app/libs/x86.jar deleted file mode 100644 index 8a1556c..0000000 Binary files a/app/libs/x86.jar and /dev/null differ diff --git a/app/libs/x86_64.jar b/app/libs/x86_64.jar deleted file mode 100644 index 6d45fad..0000000 Binary files a/app/libs/x86_64.jar and /dev/null differ diff --git a/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java index 8ad158a..d29f460 100644 --- a/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java +++ b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java @@ -21,26 +21,19 @@ import java.util.HashMap; // See https://docs.github.com/en/rest/reference/repos#releases public class AppUpdateManager { public static final int FLAG_COMPAT_LOW_QUALITY = 0x0001; - public static final int FLAG_COMPAT_NO_EXT = 0x0002; - public static final int FLAG_COMPAT_MAGISK_CMD = 0x0004; - public static final int FLAG_COMPAT_NEED_32BIT = 0x0008; - public static final int FLAG_COMPAT_MALWARE = 0x0010; - public static final int FLAG_COMPAT_NO_ANSI = 0x0020; - public static final int FLAG_COMPAT_FORCE_ANSI = 0x0040; - public static final int FLAG_COMPAT_FORCE_HIDE = 0x0080; - public static final int FLAG_COMPAT_MMT_REBORN = 0x0100; + public static final int FLAG_COMPAT_NO_EXT = 0x0002; + public static final int FLAG_COMPAT_MAGISK_CMD = 0x0004; + public static final int FLAG_COMPAT_NEED_32BIT = 0x0008; + public static final int FLAG_COMPAT_MALWARE = 0x0010; + public static final int FLAG_COMPAT_NO_ANSI = 0x0020; + public static final int FLAG_COMPAT_FORCE_ANSI = 0x0040; + public static final int FLAG_COMPAT_FORCE_HIDE = 0x0080; + public static final int FLAG_COMPAT_MMT_REBORN = 0x0100; public static final int FLAG_COMPAT_ZIP_WRAPPER = 0x0200; private static final String TAG = "AppUpdateManager"; private static final AppUpdateManager INSTANCE = new AppUpdateManager(); - private static final String RELEASES_API_URL = - "https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases"; - private static final String COMPAT_API_URL = - "https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/issues/4"; - - public static AppUpdateManager getAppUpdateManager() { - return INSTANCE; - } - + private static final String RELEASES_API_URL = "https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases"; + private static final String COMPAT_API_URL = "https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/issues/4"; private final HashMap compatDataId = new HashMap<>(); private final Object updateLock = new Object(); private final File compatFile; @@ -49,13 +42,10 @@ public class AppUpdateManager { private long lastChecked; private boolean preReleaseNewer; private boolean lastCheckSuccess; - private AppUpdateManager() { this.compatFile = new File(MainApplication.getINSTANCE().getFilesDir(), "compat.txt"); - this.latestRelease = MainApplication.getBootSharedPreferences() - .getString("updater_latest_release", BuildConfig.VERSION_NAME); - this.latestPreRelease = MainApplication.getBootSharedPreferences() - .getString("updater_latest_pre_release", BuildConfig.VERSION_NAME); + this.latestRelease = MainApplication.getBootSharedPreferences().getString("updater_latest_release", BuildConfig.VERSION_NAME); + this.latestPreRelease = MainApplication.getBootSharedPreferences().getString("updater_latest_pre_release", BuildConfig.VERSION_NAME); this.lastChecked = 0; this.preReleaseNewer = true; if (this.compatFile.isFile()) { @@ -67,24 +57,34 @@ public class AppUpdateManager { } } + public static AppUpdateManager getAppUpdateManager() { + return INSTANCE; + } + + public static int getFlagsForModule(String moduleId) { + return INSTANCE.getCompatibilityFlags(moduleId); + } + + public static boolean shouldForceHide(String repoId) { + if (BuildConfig.DEBUG || repoId.startsWith("repo_") || repoId.equals("magisk_alt_repo")) + return false; + return !repoId.startsWith("repo_") && (INSTANCE.getCompatibilityFlags(repoId) & FLAG_COMPAT_FORCE_HIDE) != 0; + } + // Return true if should show a notification public boolean checkUpdate(boolean force) { - if (!BuildConfig.ENABLE_AUTO_UPDATER) - return false; - if (!force && this.peekShouldUpdate()) - return true; + if (!BuildConfig.ENABLE_AUTO_UPDATER) return false; + if (!force && this.peekShouldUpdate()) return true; long lastChecked = this.lastChecked; if (lastChecked != 0 && // Avoid spam calls by putting a 60 seconds timer lastChecked < System.currentTimeMillis() - 60000L) return force && this.peekShouldUpdate(); synchronized (this.updateLock) { - if (lastChecked != this.lastChecked) - return this.peekShouldUpdate(); + if (lastChecked != this.lastChecked) return this.peekShouldUpdate(); boolean preReleaseNewer = true; try { - JSONArray releases = new JSONArray(new String(Http.doHttpGet( - RELEASES_API_URL, false), StandardCharsets.UTF_8)); + JSONArray releases = new JSONArray(new String(Http.doHttpGet(RELEASES_API_URL, false), StandardCharsets.UTF_8)); String latestRelease = null, latestPreRelease = null; for (int i = 0; i < releases.length(); i++) { JSONObject release = releases.getJSONObject(i); @@ -92,22 +92,18 @@ public class AppUpdateManager { if (release.getBoolean("draft")) continue; boolean preRelease = release.getBoolean("prerelease"); String version = release.getString("tag_name"); - if (version.startsWith("v")) - version = version.substring(1); + if (version.startsWith("v")) version = version.substring(1); if (preRelease) { - if (latestPreRelease == null) - latestPreRelease = version; + if (latestPreRelease == null) latestPreRelease = version; } else if (latestRelease == null) { latestRelease = version; - if (latestPreRelease == null) - preReleaseNewer = false; + if (latestPreRelease == null) preReleaseNewer = false; } if (latestRelease != null && latestPreRelease != null) { break; // We read everything we needed to read. } } - if (latestRelease != null) - this.latestRelease = latestRelease; + if (latestRelease != null) this.latestRelease = latestRelease; if (latestPreRelease != null) { this.latestPreRelease = latestPreRelease; this.preReleaseNewer = preReleaseNewer; @@ -131,45 +127,42 @@ public class AppUpdateManager { public void checkUpdateCompat() { if (this.compatFile.exists()) { long lastUpdate = this.compatFile.lastModified(); - if (lastUpdate <= System.currentTimeMillis() && - lastUpdate + 600_000L > System.currentTimeMillis()) { + if (lastUpdate <= System.currentTimeMillis() && lastUpdate + 600_000L > System.currentTimeMillis()) { return; // Skip update } } try { - JSONObject object = new JSONObject(new String(Http.doHttpGet( - COMPAT_API_URL, false), StandardCharsets.UTF_8)); + JSONObject object = new JSONObject(new String(Http.doHttpGet(COMPAT_API_URL, false), StandardCharsets.UTF_8)); if (object.isNull("body")) { compatDataId.clear(); Files.write(compatFile, new byte[0]); return; } - byte[] rawData = object.getString("body") - .getBytes(StandardCharsets.UTF_8); + byte[] rawData = object.getString("body").getBytes(StandardCharsets.UTF_8); this.parseCompatibilityFlags(new ByteArrayInputStream(rawData)); Files.write(compatFile, rawData); - if (!BuildConfig.ENABLE_AUTO_UPDATER) - this.lastCheckSuccess = true; + if (!BuildConfig.ENABLE_AUTO_UPDATER) this.lastCheckSuccess = true; } catch (Exception e) { - if (!BuildConfig.ENABLE_AUTO_UPDATER) - this.lastCheckSuccess = false; + if (!BuildConfig.ENABLE_AUTO_UPDATER) this.lastCheckSuccess = false; Log.e("AppUpdateManager", "Failed to update compat list", e); } } public boolean peekShouldUpdate() { - if (!BuildConfig.ENABLE_AUTO_UPDATER) - return false; - return !(BuildConfig.VERSION_NAME.equals(this.latestRelease) || - (this.preReleaseNewer && - BuildConfig.VERSION_NAME.equals(this.latestPreRelease))); + if (!BuildConfig.ENABLE_AUTO_UPDATER) return false; + // Convert both BuildConfig.VERSION_NAME and latestRelease to int + int currentVersion = 0, latestVersion = 0; + try { + currentVersion = Integer.parseInt(BuildConfig.VERSION_NAME.replace(".", "")); + latestVersion = Integer.parseInt(this.latestRelease.replace(".", "")); + } catch (NumberFormatException ignored) { + } + return currentVersion < latestVersion || (this.preReleaseNewer && currentVersion < Integer.parseInt(this.latestPreRelease.replace(".", ""))); } public boolean peekHasUpdate() { - if (!BuildConfig.ENABLE_AUTO_UPDATER) - return false; - return !BuildConfig.VERSION_NAME.equals(this.preReleaseNewer ? - this.latestPreRelease : this.latestRelease); + if (!BuildConfig.ENABLE_AUTO_UPDATER) return false; + return !BuildConfig.VERSION_NAME.equals(this.preReleaseNewer ? this.latestPreRelease : this.latestRelease); } public boolean isLastCheckSuccess() { @@ -178,8 +171,7 @@ public class AppUpdateManager { private void parseCompatibilityFlags(InputStream inputStream) throws IOException { compatDataId.clear(); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); String line; while ((line = bufferedReader.readLine()) != null) { line = line.trim(); @@ -231,16 +223,4 @@ public class AppUpdateManager { Integer compatFlags = compatDataId.get(moduleId); return compatFlags == null ? 0 : compatFlags; } - - public static int getFlagsForModule(String moduleId) { - return INSTANCE.getCompatibilityFlags(moduleId); - } - - public static boolean shouldForceHide(String repoId) { - if (BuildConfig.DEBUG || repoId.startsWith("repo_") || - repoId.equals("magisk_alt_repo")) return false; - return !repoId.startsWith("repo_") && - (INSTANCE.getCompatibilityFlags(repoId) & - FLAG_COMPAT_FORCE_HIDE) != 0; - } } diff --git a/app/src/main/java/com/fox2code/mmm/MainActivity.java b/app/src/main/java/com/fox2code/mmm/MainActivity.java index 34d11e3..de05278 100644 --- a/app/src/main/java/com/fox2code/mmm/MainActivity.java +++ b/app/src/main/java/com/fox2code/mmm/MainActivity.java @@ -158,11 +158,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); - noodleDebug.setEnabled(noodleDebugState); - noodleDebug.bind(); - noodleDebug.push("Ensure Permissions"); ensurePermissions(); - noodleDebug.pop(); ModuleManager.getINSTANCE().scan(); ModuleManager.getINSTANCE().runAfterScan(moduleViewListBuilder::appendInstalledModules); this.commonNext(); @@ -171,21 +167,17 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe @Override public void onFailure(int error) { Log.i(TAG, "Failed to get magisk path!"); - noodleDebug.setEnabled(noodleDebugState); - noodleDebug.bind(); moduleViewListBuilder.addNotification(InstallerInitializer.getErrorNotification()); this.commonNext(); } public void commonNext() { - NoodleDebug noodleDebug = NoodleDebug.getNoodleDebug(); swipeRefreshBlocker = System.currentTimeMillis() + 5_000L; updateScreenInsets(); // Fix an edge case if (MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.SHOWCASE_MODE); if (!Http.hasWebView()) // Check Http for WebView availability moduleViewListBuilder.addNotification(NotificationType.NO_WEB_VIEW); - noodleDebug.push("Apply"); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); runOnUiThread(() -> { progressIndicator.setIndeterminate(false); @@ -194,14 +186,14 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe updateScreenInsets(getResources().getConfiguration()); }); Log.i(TAG, "Scanning for modules!"); - noodleDebug.replace("Initialize Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Initialize Update"); final int max = ModuleManager.getINSTANCE().getUpdatableModuleCount(); if (RepoManager.getINSTANCE().getCustomRepoManager().needUpdate()) { Log.w(TAG, "Need update on create?"); } - noodleDebug.replace("Check Update Compat"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check Update Compat"); AppUpdateManager.getAppUpdateManager().checkUpdateCompat(); - noodleDebug.replace("Check Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check Update"); RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> progressIndicator.setProgressCompat((int) (value * PRECISION), true) : () -> progressIndicator.setProgressCompat((int) (value * PRECISION * 0.75F), true))); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); if (!NotificationType.NO_INTERNET.shouldRemove()) { @@ -211,16 +203,16 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe } else { // Compatibility data still needs to be updated AppUpdateManager appUpdateManager = AppUpdateManager.getAppUpdateManager(); - noodleDebug.replace("Check App Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check App Update"); if (BuildConfig.ENABLE_AUTO_UPDATER && appUpdateManager.checkUpdate(true)) moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE); - noodleDebug.replace("Check Json Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check Json Update"); if (max != 0) { int current = 0; - noodleDebug.push(""); + // noodleDebug.push(""); for (LocalModuleInfo localModuleInfo : ModuleManager.getINSTANCE().getModules().values()) { if (localModuleInfo.updateJson != null) { - noodleDebug.replace(localModuleInfo.id); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", localModuleInfo.id); try { localModuleInfo.checkModuleUpdate(); } catch (Exception e) { @@ -231,7 +223,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe runOnUiThread(() -> progressIndicator.setProgressCompat((int) ((1F * currentTmp / max) * PRECISION * 0.25F + (PRECISION * 0.75F)), true)); } } - noodleDebug.pop(); } } runOnUiThread(() -> { @@ -241,12 +232,11 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe setActionBarBackground(null); updateScreenInsets(getResources().getConfiguration()); }); - noodleDebug.replace("Apply"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Apply"); RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); - noodleDebug.pop(); Log.i(TAG, "Finished app opening state!"); - noodleDebug.unbind(); + // noodleDebug.unbind(); } }, true); ExternalHelper.INSTANCE.refreshHelper(this); @@ -328,8 +318,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); - noodleDebug.setEnabled(noodleDebugState); - noodleDebug.bind(); ModuleManager.getINSTANCE().scan(); ModuleManager.getINSTANCE().runAfterScan(moduleViewListBuilder::appendInstalledModules); this.commonNext(); @@ -345,7 +333,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe public void commonNext() { Log.i(TAG, "Common Before"); - NoodleDebug noodleDebug = NoodleDebug.getNoodleDebug(); if (MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.SHOWCASE_MODE); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); @@ -354,26 +341,23 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe else if (AppUpdateManager.getAppUpdateManager().checkUpdate(false)) moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE); RepoManager.getINSTANCE().updateEnabledStates(); - noodleDebug.push(""); if (RepoManager.getINSTANCE().getCustomRepoManager().needUpdate()) { runOnUiThread(() -> { progressIndicator.setIndeterminate(false); progressIndicator.setMax(PRECISION); }); - noodleDebug.replace("Check Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check Update"); RepoManager.getINSTANCE().update(value -> runOnUiThread(() -> progressIndicator.setProgressCompat((int) (value * PRECISION), true))); runOnUiThread(() -> { progressIndicator.setProgressCompat(PRECISION, true); progressIndicator.setVisibility(View.GONE); }); } - noodleDebug.replace("Apply"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Apply"); RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); Log.i(TAG, "Common Before applyTo"); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); - noodleDebug.pop(); Log.i(TAG, "Common After"); - noodleDebug.unbind(); } }); this.initMode = false; @@ -390,33 +374,33 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe this.swipeRefreshLayout.setRefreshing(false); return; // Do not double scan } + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Refresh"); this.progressIndicator.setVisibility(View.VISIBLE); this.progressIndicator.setProgressCompat(0, false); this.swipeRefreshBlocker = System.currentTimeMillis() + 5_000L; // this.swipeRefreshLayout.setRefreshing(true); ?? new Thread(() -> { - noodleDebug.setEnabled(noodleDebugState); - NoodleDebug noodleDebug = this.noodleDebug.bind(); Http.cleanDnsCache(); // Allow DNS reload from network - noodleDebug.push("Check Update"); + // noodleDebug.push("Check Update"); final int max = ModuleManager.getINSTANCE().getUpdatableModuleCount(); RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> progressIndicator.setProgressCompat((int) (value * PRECISION), true) : () -> progressIndicator.setProgressCompat((int) (value * PRECISION * 0.75F), true))); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); if (!NotificationType.NO_INTERNET.shouldRemove()) { moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); + } else if (!NotificationType.REPO_UPDATE_FAILED.shouldRemove()) { + moduleViewListBuilder.addNotification(NotificationType.REPO_UPDATE_FAILED); } else { // Compatibility data still needs to be updated AppUpdateManager appUpdateManager = AppUpdateManager.getAppUpdateManager(); - // noodleDebug.replace("Check App Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check App Update"); if (BuildConfig.ENABLE_AUTO_UPDATER && appUpdateManager.checkUpdate(true)) moduleViewListBuilder.addNotification(NotificationType.UPDATE_AVAILABLE); - // noodleDebug.replace("Check Json Update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Check Json Update"); if (max != 0) { int current = 0; - noodleDebug.push(""); for (LocalModuleInfo localModuleInfo : ModuleManager.getINSTANCE().getModules().values()) { if (localModuleInfo.updateJson != null) { - noodleDebug.replace(localModuleInfo.id); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", localModuleInfo.id); try { localModuleInfo.checkModuleUpdate(); } catch (Exception e) { @@ -427,23 +411,20 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe runOnUiThread(() -> progressIndicator.setProgressCompat((int) ((1F * currentTmp / max) * PRECISION * 0.25F + (PRECISION * 0.75F)), true)); } } - noodleDebug.pop(); } } - // noodleDebug.replace("Apply"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Apply"); runOnUiThread(() -> { this.progressIndicator.setVisibility(View.GONE); this.swipeRefreshLayout.setRefreshing(false); }); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); - if (!NotificationType.NO_INTERNET.shouldRemove()) { - this.moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); - } RepoManager.getINSTANCE().updateEnabledStates(); RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); this.moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); - // noodleDebug.pop(); - // noodleDebug.unbind(); + /* + noodleDebug.unbind(); + */ }, "Repo update thread").start(); } diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index dac051b..be1fc27 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -60,6 +60,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con private static SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString, timeFormatLocale); private static SharedPreferences bootSharedPreferences; private static String relPackageName = BuildConfig.APPLICATION_ID; + @SuppressLint("StaticFieldLeak") private static MainApplication INSTANCE; private static boolean firstBoot; diff --git a/app/src/main/java/com/fox2code/mmm/NotificationType.java b/app/src/main/java/com/fox2code/mmm/NotificationType.java index abd4c17..b71d25e 100644 --- a/app/src/main/java/com/fox2code/mmm/NotificationType.java +++ b/app/src/main/java/com/fox2code/mmm/NotificationType.java @@ -191,6 +191,7 @@ public enum NotificationType implements NotificationTypeCst { } public boolean shouldRemove() { + // By default, remove the notification` return false; } diff --git a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java index e9d8f09..f14de34 100644 --- a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java +++ b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java @@ -184,7 +184,8 @@ public final class AndroidacyRepoData extends RepoData { } String deviceId = generateDeviceId(); long time = System.currentTimeMillis(); - if (this.androidacyBlockade > time) return false; + if (this.androidacyBlockade > time) return true; // fake it till you make it. Basically, + // don'e fail just becaue we're rate limited. API and web rate limits are different. this.androidacyBlockade = time + 30_000L; try { if (this.token == null) { @@ -249,6 +250,9 @@ public final class AndroidacyRepoData extends RepoData { @Override protected List populate(JSONObject jsonObject) throws JSONException, NoSuchAlgorithmException { + if (BuildConfig.DEBUG) { + Log.d(TAG, "AndroidacyRepoData populate start"); + } if (!jsonObject.getString("status").equals("success")) throw new JSONException("Response is not a success!"); String name = jsonObject.optString("name", "Androidacy Modules Repo"); @@ -326,7 +330,9 @@ public final class AndroidacyRepoData extends RepoData { String config = jsonObject.optString("config", ""); moduleInfo.config = config.isEmpty() ? null : config; PropUtils.applyFallbacks(moduleInfo); // Apply fallbacks - Log.d(TAG, "Module " + moduleInfo.name + " " + moduleInfo.id + " " + moduleInfo.version + " " + moduleInfo.versionCode); + // Log.d(TAG, + // "Module " + moduleInfo.name + " " + moduleInfo.id + " " + moduleInfo + // .version + " " + moduleInfo.versionCode); } Iterator moduleInfoIterator = this.moduleHashMap.values().iterator(); while (moduleInfoIterator.hasNext()) { diff --git a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyWebAPI.java b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyWebAPI.java index d457947..b2cfb06 100644 --- a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyWebAPI.java +++ b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyWebAPI.java @@ -29,7 +29,6 @@ import com.fox2code.mmm.utils.ExternalHelper; import com.fox2code.mmm.utils.Files; import com.fox2code.mmm.utils.Hashes; import com.fox2code.mmm.utils.IntentHelper; -import com.fox2code.mmm.utils.PropUtils; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import java.io.File; @@ -44,11 +43,11 @@ public class AndroidacyWebAPI { private static final int MAX_COMPAT_MODE = 1; private final AndroidacyActivity activity; private final boolean allowInstall; - private boolean allowHideNote = true; boolean consumedAction; boolean downloadMode; int effectiveCompatMode; int notifiedCompatMode; + private boolean allowHideNote = true; public AndroidacyWebAPI(AndroidacyActivity activity, boolean allowInstall) { this.activity = activity; @@ -113,7 +112,7 @@ public class AndroidacyWebAPI { final boolean fMMTReborn = mmtReborn; builder.setPositiveButton(hasUpdate ? R.string.update_module : R.string.install_module, (x, y) -> IntentHelper.openInstaller(this.activity, - fModuleUrl, fTitle, fConfig, fChecksum, fMMTReborn)); + fModuleUrl, fTitle, fConfig, fChecksum, fMMTReborn)); } builder.setOnCancelListener(dialogInterface -> { if (!this.activity.backOnResume) @@ -299,7 +298,7 @@ public class AndroidacyWebAPI { return; } // Get moduleTitle from url -String moduleTitle = AndroidacyUtil.getModuleTitle(moduleUrl); + String moduleTitle = AndroidacyUtil.getModuleTitle(moduleUrl); this.openNativeModuleDialogRaw(moduleUrl, moduleId, moduleTitle, checksum, this.canInstall()); } diff --git a/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java b/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java index 50d08fb..d99ffb7 100644 --- a/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java +++ b/app/src/main/java/com/fox2code/mmm/background/BackgroundUpdateChecker.java @@ -4,6 +4,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.StrictMode; import androidx.annotation.NonNull; import androidx.core.app.NotificationChannelCompat; @@ -53,6 +54,9 @@ public class BackgroundUpdateChecker extends Worker { } static void doCheck(Context context) { + // This is actually not recommended but it's the only way to do it + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); ModuleManager.getINSTANCE().scanAsync(); RepoManager.getINSTANCE().update(null); diff --git a/app/src/main/java/com/fox2code/mmm/manager/ModuleManager.java b/app/src/main/java/com/fox2code/mmm/manager/ModuleManager.java index 6573682..dedb516 100644 --- a/app/src/main/java/com/fox2code/mmm/manager/ModuleManager.java +++ b/app/src/main/java/com/fox2code/mmm/manager/ModuleManager.java @@ -5,6 +5,7 @@ import android.util.Log; import androidx.annotation.NonNull; +import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.installer.InstallerInitializer; import com.fox2code.mmm.utils.Http; @@ -70,13 +71,13 @@ public final class ModuleManager extends SyncManager { if (!FORCE_NEED_FALLBACK && needFallback) { Log.e(TAG, "Failed to detect modules folder, using fallback instead."); } - noodleDebug.replace("Scan"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Scan"); if (modules != null) { noodleDebug.push(""); for (String module : modules) { if (!new SuFile("/data/adb/modules/" + module).isDirectory()) continue; // Ignore non directory files inside modules folder - noodleDebug.replace(module); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", module); LocalModuleInfo moduleInfo = moduleInfos.get(module); if (moduleInfo == null) { moduleInfo = new LocalModuleInfo(module); @@ -118,16 +119,15 @@ public final class ModuleManager extends SyncManager { moduleInfo.flags |= FLAG_MM_INVALID; } } - noodleDebug.pop(); } - noodleDebug.replace("Scan update"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Scan update"); String[] modules_update = new SuFile("/data/adb/modules_update").list(); if (modules_update != null) { noodleDebug.push(""); for (String module : modules_update) { if (!new SuFile("/data/adb/modules_update/" + module).isDirectory()) continue; // Ignore non directory files inside modules folder - noodleDebug.replace(module); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", module); LocalModuleInfo moduleInfo = moduleInfos.get(module); if (moduleInfo == null) { moduleInfo = new LocalModuleInfo(module); @@ -143,16 +143,15 @@ public final class ModuleManager extends SyncManager { moduleInfo.flags |= FLAG_MM_INVALID; } } - noodleDebug.pop(); } - noodleDebug.replace("Finalize scan"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Finalize scan"); this.updatableModuleCount = 0; Iterator moduleInfoIterator = this.moduleInfos.values().iterator(); noodleDebug.push(""); while (moduleInfoIterator.hasNext()) { LocalModuleInfo moduleInfo = moduleInfoIterator.next(); - noodleDebug.replace(moduleInfo.id); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", moduleInfo.id); if ((moduleInfo.flags & FLAG_MM_UNPROCESSED) != 0) { moduleInfoIterator.remove(); continue; // Don't process fallbacks if unreferenced @@ -174,12 +173,10 @@ public final class ModuleManager extends SyncManager { } moduleInfo.verify(); } - noodleDebug.pop(); if (firstScan) { editor.putBoolean("mm_first_scan", false); editor.apply(); } - noodleDebug.pop(); } public HashMap getModules() { diff --git a/app/src/main/java/com/fox2code/mmm/repo/RepoManager.java b/app/src/main/java/com/fox2code/mmm/repo/RepoManager.java index 663b0ce..ab4b39f 100644 --- a/app/src/main/java/com/fox2code/mmm/repo/RepoManager.java +++ b/app/src/main/java/com/fox2code/mmm/repo/RepoManager.java @@ -1,12 +1,18 @@ package com.fox2code.mmm.repo; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; +import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.MainApplication; +import com.fox2code.mmm.R; import com.fox2code.mmm.XHooks; import com.fox2code.mmm.XRepo; import com.fox2code.mmm.androidacy.AndroidacyRepoData; @@ -14,9 +20,9 @@ import com.fox2code.mmm.manager.ModuleInfo; import com.fox2code.mmm.utils.Files; import com.fox2code.mmm.utils.Hashes; import com.fox2code.mmm.utils.Http; -import com.fox2code.mmm.utils.NoodleDebug; import com.fox2code.mmm.utils.PropUtils; import com.fox2code.mmm.utils.SyncManager; +import com.google.android.material.snackbar.Snackbar; import java.io.File; import java.io.IOException; @@ -28,6 +34,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; public final class RepoManager extends SyncManager { public static final String MAGISK_REPO = @@ -64,10 +71,10 @@ public final class RepoManager extends SyncManager { private final HashMap modules; private final AndroidacyRepoData androidacyRepoData; private final CustomRepoManager customRepoManager; + public String repoLastErrorName = null; private boolean hasInternet; - private boolean repoLastError = false; private boolean initialized; - public String repoLastErrorName = null; + private boolean repoLastSuccess; private RepoManager(MainApplication mainApplication) { INSTANCE = this; // Set early fox XHooks @@ -227,10 +234,8 @@ public final class RepoManager extends SyncManager { return repoData; } + @SuppressLint("StringFormatInvalid") protected void scanInternal(@NonNull UpdateListener updateListener) { - NoodleDebug noodleDebug = NoodleDebug.getNoodleDebug(); - // First, check if we have internet connection - noodleDebug.push("Downloading indexes"); this.modules.clear(); updateListener.update(0D); // Using LinkedHashSet to deduplicate Androidacy entry. @@ -238,26 +243,27 @@ public final class RepoManager extends SyncManager { this.repoData.values()).toArray(new RepoData[0]); RepoUpdater[] repoUpdaters = new RepoUpdater[repoDatas.length]; int moduleToUpdate = 0; - noodleDebug.push(""); for (int i = 0; i < repoDatas.length; i++) { - noodleDebug.replace(repoDatas[i].getName()); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoDatas[i].getName()); moduleToUpdate += (repoUpdaters[i] = new RepoUpdater(repoDatas[i])).fetchIndex(); updateListener.update(STEP1 / repoDatas.length * (i + 1)); } - noodleDebug.pop(); - noodleDebug.replace("Updating meta-data"); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Updating meta-data"); int updatedModules = 0; boolean allowLowQualityModules = MainApplication.isDisableLowQualityModuleFilter(); - noodleDebug.push(""); for (int i = 0; i < repoUpdaters.length; i++) { + // Check if the repo is enabled + if (!repoUpdaters[i].repoData.isEnabled()) { + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Skipping disabled repo: " + repoUpdaters[i].repoData.getName()); + continue; + } List repoModules = repoUpdaters[i].toUpdate(); RepoData repoData = repoDatas[i]; - noodleDebug.replace(repoData.getName()); - Log.d(TAG, "Registering " + repoData.getName()); - noodleDebug.push(""); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoData.getName()); + if (BuildConfig.DEBUG) Log.d(TAG, "Registering " + repoData.getName()); for (RepoModule repoModule : repoModules) { - noodleDebug.replace(repoModule.id); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoModule.id); try { if (repoModule.propUrl != null && !repoModule.propUrl.isEmpty()) { @@ -283,7 +289,6 @@ public final class RepoManager extends SyncManager { updatedModules++; updateListener.update(STEP1 + (STEP2 / moduleToUpdate * updatedModules)); } - noodleDebug.pop(); for (RepoModule repoModule : repoUpdaters[i].toApply()) { if ((repoModule.moduleInfo.flags & ModuleInfo.FLAG_METADATA_INVALID) == 0) { RepoModule registeredRepoModule = this.modules.get(repoModule.id); @@ -296,9 +301,7 @@ public final class RepoManager extends SyncManager { } } } - noodleDebug.pop(); - noodleDebug.replace("Finishing update"); - noodleDebug.push(""); + if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Finishing update"); this.hasInternet = false; // Check if we have internet connection // Attempt to contact connectivitycheck.gstatic.com/generate_204 @@ -318,22 +321,36 @@ public final class RepoManager extends SyncManager { } catch (IOException e) { Log.e(TAG, "Failed to check internet connection", e); } - noodleDebug.pop(); if (hasInternet) { for (int i = 0; i < repoDatas.length; i++) { - noodleDebug.replace(repoUpdaters[i].repoData.getName()); - this.repoLastError = !repoUpdaters[i].finish(); - if (this.repoLastError) { + // If repo is not enabled, skip + if (!repoDatas[i].isEnabled()) { + if (BuildConfig.DEBUG) Log.d("NoodleDebug", + "Skipping " + repoDatas[i].getName() + " because it's disabled"); + continue; + } + if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoUpdaters[i].repoData.getName()); + this.repoLastSuccess = repoUpdaters[i].finish(); + if (!this.repoLastSuccess) { Log.e(TAG, "Failed to update " + repoUpdaters[i].repoData.getName()); + // Show snackbar on main looper and add some bottom padding + int finalI = i; + Activity context = MainApplication.getINSTANCE().getLastCompatActivity(); + new Handler(Looper.getMainLooper()).post(() -> { + if (context != null) { + Snackbar.make(context.findViewById(android.R.id.content), + context.getString(R.string.repo_update_failed_extended, + repoUpdaters[finalI].repoData.getName()), + Snackbar.LENGTH_LONG).show(); + } + }); this.repoLastErrorName = repoUpdaters[i].repoData.getName(); } updateListener.update(STEP1 + STEP2 + (STEP3 / repoDatas.length * (i + 1))); } } - noodleDebug.pop(); Log.i(TAG, "Got " + this.modules.size() + " modules!"); updateListener.update(1D); - noodleDebug.pop(); // pop "Finishing update" } public void updateEnabledStates() { @@ -408,6 +425,6 @@ public final class RepoManager extends SyncManager { } public boolean isLastUpdateSuccess() { - return this.repoLastError; + return this.repoLastSuccess; } } diff --git a/app/src/main/java/com/fox2code/mmm/repo/RepoUpdater.java b/app/src/main/java/com/fox2code/mmm/repo/RepoUpdater.java index c7145ac..befc5c3 100644 --- a/app/src/main/java/com/fox2code/mmm/repo/RepoUpdater.java +++ b/app/src/main/java/com/fox2code/mmm/repo/RepoUpdater.java @@ -1,20 +1,11 @@ package com.fox2code.mmm.repo; import android.util.Log; -import android.view.View; -import android.view.Window; -import android.widget.Toast; -import androidx.annotation.Nullable; - -import com.fox2code.mmm.MainActivity; -import com.fox2code.mmm.MainApplication; +import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.utils.Files; import com.fox2code.mmm.utils.Http; -import com.fox2code.mmm.utils.HttpException; -import com.google.android.material.snackbar.Snackbar; -import org.jetbrains.annotations.Contract; import org.json.JSONObject; import java.io.IOException; @@ -52,12 +43,12 @@ public class RepoUpdater { } this.indexRaw = Http.doHttpGet(this.repoData.getUrl(), false); // Ensure it's a valid json and response code is 200 - if (Arrays.hashCode(this.indexRaw) == 0) { + /*if (Arrays.hashCode(this.indexRaw) == 0) { this.indexRaw = null; this.toUpdate = Collections.emptyList(); this.toApply = this.repoData.moduleHashMap.values(); return 0; - } + }*/ this.toUpdate = this.repoData.populate(new JSONObject( new String(this.indexRaw, StandardCharsets.UTF_8))); // Since we reuse instances this should work @@ -83,7 +74,7 @@ public class RepoUpdater { } public boolean finish() { - final boolean success = this.indexRaw != null; + boolean success = this.indexRaw != null; // If repo is not enabled we don't need to do anything, just return true if (!this.repoData.isEnabled()) { return true; @@ -91,6 +82,9 @@ public class RepoUpdater { if (this.indexRaw != null) { try { Files.write(this.repoData.metaDataCache, this.indexRaw); + if (BuildConfig.DEBUG) { + Log.d(TAG, "Wrote index of " + this.repoData.id); + } } catch (IOException e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/fox2code/mmm/utils/Hashes.java b/app/src/main/java/com/fox2code/mmm/utils/Hashes.java index c346af6..26e39fa 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/Hashes.java +++ b/app/src/main/java/com/fox2code/mmm/utils/Hashes.java @@ -24,6 +24,7 @@ public class Hashes { } public static String hashMd5(byte[] input) { + Log.w(TAG, "hashMd5: This method is insecure, use hashSha256 instead"); try { MessageDigest md = MessageDigest.getInstance("MD5"); 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 5be3187..43c8c78 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/Http.java +++ b/app/src/main/java/com/fox2code/mmm/utils/Http.java @@ -238,6 +238,7 @@ public class Http { (allowCache ? getHttpClientWithCache() : getHttpClient()).newCall(new Request.Builder().url(url).get().build()).execute(); // 200/204 == success, 304 == cache valid if (response.code() != 200 && response.code() != 204 && (response.code() != 304 || !allowCache)) { + Log.e(TAG, "Failed to fetch " + url + ", code: " + response.code()); checkNeedCaptchaAndroidacy(url, response.code()); // If it's a 401, and an androidacy link, it's probably an invalid token if (response.code() == 401 && AndroidacyUtil.isAndroidacyLink(url)) { @@ -260,6 +261,7 @@ public class Http { @SuppressWarnings("resource") private static Object doHttpPostRaw(String url, String data, boolean allowCache) throws IOException { + if (BuildConfig.DEBUG) Log.d(TAG, "POST " + url + " " + data); checkNeedBlockAndroidacyRequest(url); Response response = (allowCache ? getHttpClientWithCache() : getHttpClient()).newCall(new Request.Builder().url(url).post(JsonRequestBody.from(data)).header("Content-Type", "application/json").build()).execute(); if (response.isRedirect()) { @@ -280,10 +282,11 @@ public class Http { } public static byte[] doHttpGet(String url, ProgressListener progressListener) throws IOException { - Log.d("Http", "Progress URL: " + url); + if (BuildConfig.DEBUG) Log.d("Http", "Progress URL: " + url); checkNeedBlockAndroidacyRequest(url); Response response = getHttpClient().newCall(new Request.Builder().url(url).get().build()).execute(); if (response.code() != 200 && response.code() != 204) { + Log.e(TAG, "Failed to fetch " + url + ", code: " + response.code()); checkNeedCaptchaAndroidacy(url, response.code()); throw new HttpException(response.code()); } diff --git a/app/src/main/res/layout/module_entry.xml b/app/src/main/res/layout/module_entry.xml index 8b050da..8c2c7b8 100644 --- a/app/src/main/res/layout/module_entry.xml +++ b/app/src/main/res/layout/module_entry.xml @@ -16,7 +16,7 @@ android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" - style="?attr/materialCardViewFilledStyle"> + style="?attr/materialCardViewElevatedStyle"> @color/black @color/black - @color/black - @color/black + @color/dark_backgroundColor + @color/cardview_dark_background @color/black @color/black - - @color/system_accent2_900 - @color/system_accent2_900 + + @color/system_accent2_300 + @color/system_accent2_700 + @color/system_accent2_400 + @color/system_accent2_600 + + @color/system_accent2_700 + @color/system_accent2_700 +