Lots of changes and code cleanup

- Remove binaries because I was lied to
- Stuff
- Other stuff
- Jeez why did I wait two days to commit, I can't remember anything I did

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/242/head
androidacy-user 1 year ago
parent a1cc1a29c9
commit 71e11600ef

@ -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'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -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<String, Integer> 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;
}
}

@ -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();
}

@ -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;

@ -191,6 +191,7 @@ public enum NotificationType implements NotificationTypeCst {
}
public boolean shouldRemove() {
// By default, remove the notification`
return false;
}

@ -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<RepoModule> 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<RepoModule> moduleInfoIterator = this.moduleHashMap.values().iterator();
while (moduleInfoIterator.hasNext()) {

@ -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());
}

@ -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);

@ -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<LocalModuleInfo> 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<String, LocalModuleInfo> getModules() {

@ -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<String, RepoModule> 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<RepoModule> 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;
}
}

@ -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();
}

@ -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");

@ -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());
}

@ -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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"

@ -26,13 +26,22 @@
<style name="Theme.MagiskModuleManager.Monet.Black" parent="Theme.MagiskModuleManager.Monet.Dark">
<item name="colorBackgroundFloating">@color/black</item>
<item name="android:windowBackground">@color/black</item>
<item name="boxBackgroundColor">@color/black</item>
<item name="cardBackgroundColor">@color/black</item>
<item name="boxBackgroundColor">@color/dark_backgroundColor</item>
<item name="cardBackgroundColor">@color/cardview_dark_background</item>
<item name="backgroundColor">@color/black</item>
<item name="colorSurface">@color/black</item>
<!-- Darker variants of the colors -->
<item name="colorPrimaryVariant">@color/system_accent2_900</item>
<item name="colorSecondaryVariant">@color/system_accent2_900</item>
<!-- Darker variants of the monet colors -->
<item name="colorPrimary">@color/system_accent2_300</item>
<item name="colorPrimaryVariant">@color/system_accent2_700</item>
<item name="colorSecondary">@color/system_accent2_400</item>
<item name="colorSecondaryVariant">@color/system_accent2_600</item>
<!-- Override chip style -->
<item name="chipBackgroundColor">@color/system_accent2_700</item>
<item name="chipSurfaceColor">@color/system_accent2_700</item>
<!-- <item name="colorOnPrimary">@color/system_accent2_100</item>
<item name="colorOnSecondary">@color/system_accent2_100</item>
<item name="colorOnBackground">@color/system_accent2_100</item>
<item name="colorOnSurface">@color/system_accent2_100</item> -->
</style>
<style name="Widget.Material3.Chip.Choice.Dark" parent="Widget.Material3.Chip.Assist">

@ -7,6 +7,7 @@
<color name="teal_700">#FF018786</color>
<color name="orange_700">#EF6C00</color>
<color name="orange_200">#FFA726</color>
<color name="orange_500">#FF9800</color>
<color name="black_transparent">#70000000</color>
<color name="white_transparent">#70FFFFFF</color>
<color name="transparent">#00000000</color>

@ -198,4 +198,5 @@
download the GitHub release if you\'d like to benefit from features like module reviews, automatic security checks, and more.</string>
<string name="download_full_app">Download full version</string>
<string name="repo_update_failed">Some repos have failed to update</string>
<string name="repo_update_failed_extended">Update of %1$s failed. Please try again later.</string>
</resources>

@ -92,8 +92,10 @@
<item name="backgroundColor">@color/black</item>
<item name="colorSurface">@color/black</item>
<!-- Darker variants of the colors -->
<item name="colorPrimaryVariant">@color/system_accent2_900</item>
<item name="colorSecondaryVariant">@color/system_accent2_900</item>
<item name="colorPrimary">@color/orange_500</item>
<item name="colorPrimaryVariant">@color/orange_700</item>
<item name="colorSecondary">@color/orange_500</item>
<item name="colorSecondaryVariant">@color/orange_700</item>
</style>
<style name="Widget.Material.Chip.Choice.Dark" parent="Widget.MaterialComponents.Chip.Action">

@ -6,7 +6,7 @@ buildscript {
gradlePluginPortal()
maven { url 'https://jitpack.io' }
}
project.ext.latestAboutLibsRelease = "10.5.0"
project.ext.latestAboutLibsRelease = "10.5.2"
project.ext.sentryConfigFile = new File(rootDir, "sentry.properties").getAbsoluteFile()
project.ext.hasSentryConfig = sentryConfigFile.exists()
project.ext.sentryCli = [

Loading…
Cancel
Save