Lots of foxes and refactoring

- Move some docs to docs folder
- Refactor sentry a little
- In order to "fix" custom repos, don't let them be disabled
- Misc updates and optimizations

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/242/head
androidacy-user 1 year ago
parent 26f6d4e657
commit 37b93367bf

@ -5,19 +5,19 @@
Important news Important news
</summary> </summary>
I have health problems that made me work slow on everything. I have health problems that made me work slow on everything. I don't like sharing my health problmes
I don't like sharing my health problmes but it has been to much recently for me to keep it for myself. but it has been to much recently for me to keep it for myself.
This has been too much for me recently, so my moderators (same that on telegram) This has been too much for me recently, so my moderators (same that on telegram)
will be handling the project for me for a while. will be handling the project for me for a while.
I had theses problems even before I started FoxMMM, the only reason no one noticed is because I had theses problems even before I started FoxMMM, the only reason no one noticed is because I can
I can work or go to any school because of how much pain and exhaustion I feel everyday. work or go to any school because of how much pain and exhaustion I feel everyday.
The only two thing that helped me reduce the pain is making code and playing with firends. The only two thing that helped me reduce the pain is making code and playing with firends.
Even tho I'm very slow at doing anything, the only thing that made me look like I was working Even tho I'm very slow at doing anything, the only thing that made me look like I was working on
on this project at a normal speed like someone that work is because 75% of my time was on this project. this project at a normal speed like someone that work is because 75% of my time was on this project.
There was also some times I couldn't work on this projects for multiple days because of my health, There was also some times I couldn't work on this projects for multiple days because of my health,
sometimes I was forcing myself to change one line of code from this project because doing nothing sometimes I was forcing myself to change one line of code from this project because doing nothing
@ -25,33 +25,33 @@ was more painful that trying something while in pain.
Spending time with my friend and working on this project was a sort of pain killer for me. Spending time with my friend and working on this project was a sort of pain killer for me.
Even tho I received money from my parent and the governement for my health problems, Even tho I received money from my parent and the governement for my health problems, I didn't know
I didn't know what to do with it cause anything I could have bought had no use for me what to do with it cause anything I could have bought had no use for me because my extreme pain made
because my extreme pain made me unable to use anything. (Even video games) me unable to use anything. (Even video games)
My health issues also prevented me to do any project of greater complexcity that this,
and without community support I would have been physically unable to continue this project.
My health issues also prevented me to do any project of greater complexcity that this, and without
community support I would have been physically unable to continue this project.
There was clues of my health problems, right on this project, and theses are the following: There was clues of my health problems, right on this project, and theses are the following:
- My commit time of day being random proving I have no jobs. - My commit time of day being random proving I have no jobs.
- Me not commiting for entire week, or having only commited one line in a week. - Me not commiting for entire week, or having only commited one line in a week.
- Me taking too much time to publish release after I did the relase commit. - Me taking too much time to publish release after I did the relase commit.
- Me missing obvious bugs and being able to do simple task properly - Me missing obvious bugs and being able to do simple task properly
(Well maybe this last one is harder to proove via commit history) (Well maybe this last one is harder to proove via commit history)
But sine many peoples are faking health issues for clout, if any data-scientist want But sine many peoples are faking health issues for clout, if any data-scientist want to do an
to do an analysis to proove what it would make my day, and I would be happy to give money analysis to proove what it would make my day, and I would be happy to give money if someone does
if someone does that because I don't know what do to with my money at this point. that because I don't know what do to with my money at this point.
This is really sickening peoples need to give proof for their mental/health This is really sickening peoples need to give proof for their mental/health issues because some
issues because some peoples fake having thoses issues for clout. peoples fake having thoses issues for clout.
If you want to use my health problems for coult, I don't care as long as you are respectful, If you want to use my health problems for coult, I don't care as long as you are respectful, at
at least you won't be hurting peoples with mental/health issues by faking having thoses issues. least you won't be hurting peoples with mental/health issues by faking having thoses issues.
I'll probably delete this section once my health would be gotten better, or at I'll probably delete this section once my health would be gotten better, or at least good enough for
least good enough for me to not be stuck on my bed at least once a day because of pain. me to not be stuck on my bed at least once a day because of pain.
</details> </details>
@ -68,9 +68,10 @@ Main activity:
[<img src="screenshot-dark.jpg" width="250"/>](screenshot-dark.jpg) [<img src="screenshot-dark.jpg" width="250"/>](screenshot-dark.jpg)
[<img src="screenshot-light.jpg" width="250"/>](screenshot-light.jpg) [<img src="screenshot-light.jpg" width="250"/>](screenshot-light.jpg)
## What is this? ## What is this?
The official Magisk has dropped support to download online modules, so I made Fox's Magisk Module Manager to help you download and install Magisk modules. The official Magisk has dropped support to download online modules, so I made Fox's Magisk Module
Manager to help you download and install Magisk modules.
**This app is not officially supported by Magisk or its developers** **This app is not officially supported by Magisk or its developers**
@ -80,11 +81,13 @@ The official Magisk has dropped support to download online modules, so I made Fo
## Requirements ## Requirements
Minimum: Minimum:
- Android 5.0+ - Android 5.0+
- Magisk 19.0+ - Magisk 19.0+
- An internet connection - An internet connection
Recommended: Recommended:
- Android 6.0+ - Android 6.0+
- Magisk 21.2+ - Magisk 21.2+
- An internet connection - An internet connection
@ -93,17 +96,18 @@ Note: This app may require the use of a VPN in countries with a state wide firew
## For users ## For users
To install the app go to [releases](https://github.com/Fox2Code/FoxMagiskModuleManager/releases), To install the app go to [releases](https://github.com/Fox2Code/FoxMagiskModuleManager/releases),
and download and install the latest `.apk` on your device. and download and install the latest `.apk` on your device.
## Repositories Available ## Repositories Available
The app currently use these two repos as module sources, each with their own benefits and
The app currently use these two repos as module sources, each with their own benefits and drawback: drawbacks:
(Note: Each module repo can be disabled in the settings of the app) (Note: Each module repo can be disabled in the settings of the app)
(Note²: I do not own or actively monitor any of the repos or modules, **download at your own risk**) (Note²: I do not own or actively monitor any of the repos or modules, **download at your own risk**)
#### [https://github.com/Magisk-Modules-Alt-Repo](https://github.com/Magisk-Modules-Alt-Repo) #### [https://github.com/Magisk-Modules-Alt-Repo](https://github.com/Magisk-Modules-Alt-Repo)
- Accepting new modules [here](https://github.com/Magisk-Modules-Alt-Repo/submission) - Accepting new modules [here](https://github.com/Magisk-Modules-Alt-Repo/submission)
- Less restrictive than the original repo - Less restrictive than the original repo
- Officially supported by Fox's mmm - Officially supported by Fox's mmm
@ -113,22 +117,25 @@ Support:
[![GitHub issues](https://img.shields.io/github/issues/Magisk-Modules-Alt-Repo/submission)](https://github.com/Magisk-Modules-Alt-Repo/submission/issues) [![GitHub issues](https://img.shields.io/github/issues/Magisk-Modules-Alt-Repo/submission)](https://github.com/Magisk-Modules-Alt-Repo/submission/issues)
#### [https://www.androidacy.com/modules-repo/](https://www.androidacy.com/modules-repo/) #### [https://www.androidacy.com/modules-repo/](https://www.androidacy.com/modules-repo/)
- Accepting new modules [here](https://www.androidacy.com/module-repository-applications/) - Accepting new modules [here](https://www.androidacy.com/module-repository-applications/)
- Modules downloadable easily outside the app - Modules downloadable easily outside the app
- Officially supported by Fox's mmm - Officially supported by Fox's mmm
- Contains ads to help cover server costs - May show ads to help cover infrastrcture costs.
- [Read more](https://www.androidacycom/doing-it-alone-the-what-the-how-and-the-why/)
| [Privacy policy](https://www.androidacy.com/privacy/)
- Added features like module reviews, automatic VirusTotal scans, and more - Added features like module reviews, automatic VirusTotal scans, and more
Support: Support:
[![Telegram Group](https://img.shields.io/endpoint?color=neon&style=flat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fandroidacy_discussions)](https://telegram.dog/androidacy_discussions) [![Telegram Group](https://img.shields.io/endpoint?color=neon&style=flat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fandroidacy_discussions)](https://telegram.dog/androidacy_discussions)
If a module is in multiple repos, the manager will just pick the most up to date version If a module is in multiple repos, the manager will just pick the most up to date version of the
of the module, if a module is in multiple repos it will just use first registered repo. module, if a module is in multiple repos it will just use first registered repo.
Note: If you or a friend uploaded a module and it doesn't appear in your module Note: If you or a friend uploaded a module and it doesn't appear in your module list you can disable
list you can disable the low quality filter in the app settings. the low quality filter in the app settings.
Go to the [developer documentation](DEVELOPERS.md) for more info. Go to the [developer documentation](docs/DEVELOPERS.md) for more info.
## For developers ## For developers
@ -142,14 +149,15 @@ And if you want to be event fancier you can setup `config` to your own config ap
It also add new ways to control the installer ui via a new `#!` command system It also add new ways to control the installer ui via a new `#!` command system
It allow module developers to have a more customizable install experience It allow module developers to have a more customizable install experience
For more information please check the [developer documentation](DEVELOPERS.md) For more information please check the [developer documentation](docs/DEVELOPERS.md)
## For translators ## For translators
We use Weblate for translations: https://translate.nift4.org/engage/foxmmm/ We use Weblate for translations: https://translate.nift4.org/engage/foxmmm/
(Make sure to check your spam folder when registering) (Make sure to check your spam folder when registering)
If you do not want to register on the self-hosted Weblate instance, you can do a pull request on GitHub: If you do not want to register on the self-hosted Weblate instance, you can do a pull request on
GitHub:
See [`app/src/main/res/values/strings.xml`](https://github.com/Fox2Code/FoxMagiskModuleManager/blob/master/app/src/main/res/values/strings.xml) See [`app/src/main/res/values/strings.xml`](https://github.com/Fox2Code/FoxMagiskModuleManager/blob/master/app/src/main/res/values/strings.xml)
and [`app/src/main/res/values/arrays.xml`](https://github.com/Fox2Code/FoxMagiskModuleManager/blob/master/app/src/main/res/values/arrays.xml) and [`app/src/main/res/values/arrays.xml`](https://github.com/Fox2Code/FoxMagiskModuleManager/blob/master/app/src/main/res/values/arrays.xml)
@ -159,46 +167,39 @@ If your language is right to left don't forget to set `lang_support_rtl` to `tru
Translators are not expected to have any previous coding experience. Translators are not expected to have any previous coding experience.
## License ## License
See [LICENSE](LICENCE). Library licenses can be found in the licenses section of the app.
Fox's Magisk Manager, the icon, and names are copyright
Cronet is licensed under the Apache License, Version 2.0. Static libraries are licensed under 2021-present [Fox2Code](https://github.com/Fox2Code). The Androidacy name, logo, integration, and
the BSD license. See [LICENSE](https://chromium.googlesource.com/chromium/src/+/master/LICENSE) later portions of the code are copyright
for more information. Libraries were built using the microg build script which can be found [here](https://github.com/microg/cronet-build). 2022-present [Androidacy](https://www.androidacy.com/?utm_source=fox-repo&utm_medium=web). See
[LICENSE](LICENCE) for details. Library licenses can be found in the licenses section of the app.
## I want to add my own repo
Modules are not covered by this license, please check the license of each module before using it.
To add you own repo to Fox's mmm it need to follow theses conditions:
- The module repo or at least one of it's owners must be known. Some third party backend services may be proprietary, please check their terms of service before
- Modules in the repo must be monitored, and malicious modules must be removed. using them.
- Module repo must have a valid, working, automatically or frequently updated `modules.json`
([Example](https://github.com/Magisk-Modules-Alt-Repo/json/blob/main/modules.json)) ## Disclaimer
In addition of these initial condition the repo must follow these rules: In no event shall the developer be liable for any special, direct, indirect, consequential, or
- Repos must process and take-down off their repo module where it's removal was requested incidental damages or any damages whatsoever, whether in an action of contract, negligence or other
by their original author, even if their licences legally allow their distributions. tort, arising out of or in connection with the use of the app or the contents of the app. The
- Repos may collect and store "mixed anonymous data" without user permission developer reserves the right to make additions, deletions, or modification to the contents on the
(Anonymous means no personal data, usernames, email, or IP addresses) app at any time without prior notice.
(Mixed means users data must be split and not that separate data is not linkable together)
- Temporary storage of IPs address without user consent is allowed for rate limiting, GeoIP, This app is not affiliated with Magisk or its developers, nor with any of the module repos or
security reason, and must not be used for any other purpose without user explicit consent. developers of the modules.
(GeoIP is the process of getting the country of an IP address)
- Repos may not collect and/or distribute any personal data without informing users that they do so and offering a way to opt out ## Add your own repos
- Modules owners must be aware that their modules are being hosted on the repository
(This rule doesn't apply for modules from `Magisk-Modules-Repo` last updated before 2022) See [the documentation](docs/add-repo.md)
- Modules owners must be aware of any change made of the distributed version of their modules.
## Issues with a repo
Please note Androidacy has their Module Repository Policies outlined [on their website](https://www.androidacy.com/module-requirements/?utm_source=foxmmm-readme&utm_medium=web). Please refer to that document for the latest changes regarding their Repository.
If you have a problem with a repo, please contact the repo owner **first**. If you are unable to
If all of these conditions are met you can open an issue for review. reach them or they are not willing to help, you can contact us as a last resort.
(And don't forget to include a link to the `modules.json`)
Default repo owners:
If an existing repo is not respecting theses rules please open an issue.
If a repo is repeatedly violating these rule will be removed from the app. - Androidacy: [Telegram](https://telegram.dog/androidacy_discussions)
Last update of theses rules are: 4 May 2022 - Magisk-Modules-Alt-Repo: [Telegram](https://github.com/Magisk-Modules-Alt-Repo/submission/issues)
Please note that these rules does not apply retroactively.
If your post an issue about rules violation they must violate both the version of
the rules at the moment of the incident and the latest version of the rules.
(This paragraph doesn't apply for license violation, legal requests, or illegal behaviour.)
In addition, we advise you to contact the repo host beforehand to attempt to resolve any issues. This helps avoid unnecessary conflict, and most of the time will get your issue solved quickly!

@ -8,7 +8,7 @@ plugins {
android { android {
namespace "com.fox2code.mmm" namespace "com.fox2code.mmm"
compileSdk 33 compileSdk 33
buildToolsVersion '30.0.3' buildToolsVersion '33.0.0'
signingConfigs { signingConfigs {
release { release {
// Everything comes from local.properties // Everything comes from local.properties
@ -111,8 +111,8 @@ android {
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_11
} }
lint { lint {
disable 'MissingTranslation' disable 'MissingTranslation'
@ -121,7 +121,7 @@ android {
} }
aboutLibraries { aboutLibraries {
additionalLicenses = ["LGPL_3_0_only"] additionalLicenses = ["LGPL_3_0_only", "Apache_2_0"]
} }
// "true" is not allowed inside this block, use "hasSentryConfig" instead. // "true" is not allowed inside this block, use "hasSentryConfig" instead.
@ -190,10 +190,6 @@ configurations {
implementation.exclude group: 'org.jetbrains', module: 'annotations' implementation.exclude group: 'org.jetbrains', module: 'annotations'
if (!hasSentryConfig) { if (!hasSentryConfig) {
implementation.exclude group: 'io.sentry', module: 'sentry-android' implementation.exclude group: 'io.sentry', module: 'sentry-android'
implementation.exclude group: 'io.sentry', module: 'sentry-android-fragment'
implementation.exclude group: 'io.sentry', module: 'sentry-android-okhttp'
implementation.exclude group: 'io.sentry', module: 'sentry-android-core'
implementation.exclude group: 'io.sentry', module: 'sentry-android-ndk'
} }
} }
@ -230,11 +226,7 @@ dependencies {
if (hasSentryConfig) { if (hasSentryConfig) {
// Error reporting // Error reporting
defaultImplementation 'io.sentry:sentry-android:6.9.2' implementation 'io.sentry:sentry-android:6.9.2'
defaultImplementation 'io.sentry:sentry-android-fragment:6.9.2'
defaultImplementation 'io.sentry:sentry-android-okhttp:6.9.2'
defaultImplementation 'io.sentry:sentry-android-core:6.9.2'
defaultImplementation 'io.sentry:sentry-android-ndk:6.9.2'
} }
// Markdown // Markdown
@ -243,7 +235,6 @@ dependencies {
implementation "io.noties.markwon:image:4.6.2" implementation "io.noties.markwon:image:4.6.2"
implementation "io.noties.markwon:syntax-highlight:4.6.2" implementation "io.noties.markwon:syntax-highlight:4.6.2"
implementation 'com.google.net.cronet:cronet-okhttp:0.1.0' implementation 'com.google.net.cronet:cronet-okhttp:0.1.0'
// Ignore all org.chromium.net dependencies
annotationProcessor "io.noties:prism4j-bundler:2.0.0" annotationProcessor "io.noties:prism4j-bundler:2.0.0"
implementation "com.caverock:androidsvg:1.4" implementation "com.caverock:androidsvg:1.4"

@ -309,7 +309,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
this.updateBlurState(); this.updateBlurState();
this.moduleViewListBuilder.setQuery(null); this.moduleViewListBuilder.setQuery(null);
Log.i(TAG, "Item After"); Log.i(TAG, "Item After");
noodleDebugState = MainApplication.isDeveloper();
this.moduleViewListBuilder.refreshNotificationsUI(this.moduleViewAdapter); this.moduleViewListBuilder.refreshNotificationsUI(this.moduleViewAdapter);
InstallerInitializer.tryGetMagiskPathAsync(new InstallerInitializer.Callback() { InstallerInitializer.tryGetMagiskPathAsync(new InstallerInitializer.Callback() {
@Override @Override

@ -2,7 +2,6 @@ package com.fox2code.mmm;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
@ -50,7 +49,6 @@ import io.noties.prism4j.annotations.PrismBundle;
@PrismBundle(includeAll = true, grammarLocatorClassName = ".Prism4jGrammarLocator") @PrismBundle(includeAll = true, grammarLocatorClassName = ".Prism4jGrammarLocator")
public class MainApplication extends FoxApplication implements androidx.work.Configuration.Provider { public class MainApplication extends FoxApplication implements androidx.work.Configuration.Provider {
private static final String TAG = "MainApplication";
private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001 private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001
private static final Shell.Builder shellBuilder; private static final Shell.Builder shellBuilder;
private static final long secret; private static final long secret;
@ -69,8 +67,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
secret = new Random().nextLong(); secret = new Random().nextLong();
} }
// Provides the Context for the base application
public Context FoxApplication = this;
@StyleRes @StyleRes
private int managerThemeResId = R.style.Theme_MagiskModuleManager; private int managerThemeResId = R.style.Theme_MagiskModuleManager;
private FoxThemeWrapper markwonThemeContext; private FoxThemeWrapper markwonThemeContext;
@ -143,7 +139,8 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
} }
public static boolean isDeveloper() { public static boolean isDeveloper() {
return BuildConfig.DEBUG || getSharedPreferences().getBoolean("developer", false); if (BuildConfig.DEBUG) return true;
return getSharedPreferences().getBoolean("developer", false);
} }
public static boolean isDisableLowQualityModuleFilter() { public static boolean isDisableLowQualityModuleFilter() {
@ -166,10 +163,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
return firstBoot; return firstBoot;
} }
public static boolean hasGottenRootAccess() {
return getSharedPreferences().getBoolean("has_root_access", false);
}
public static void setHasGottenRootAccess(boolean bool) { public static void setHasGottenRootAccess(boolean bool) {
getSharedPreferences().edit().putBoolean("has_root_access", bool).apply(); getSharedPreferences().edit().putBoolean("has_root_access", bool).apply();
} }
@ -205,10 +198,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
return this.markwon = markwon; return this.markwon = markwon;
} }
public FoxThemeWrapper getMarkwonThemeContext() {
return this.markwonThemeContext;
}
@NonNull @NonNull
@Override @Override
public androidx.work.Configuration getWorkManagerConfiguration() { public androidx.work.Configuration getWorkManagerConfiguration() {
@ -285,11 +274,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
if (INSTANCE == null) INSTANCE = this; if (INSTANCE == null) INSTANCE = this;
relPackageName = this.getPackageName(); relPackageName = this.getPackageName();
super.onCreate(); super.onCreate();
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
DynamicColors.applyToActivitiesIfAvailable(this,
new DynamicColorsOptions.Builder().setPrecondition(
(activity, theme) -> isMonetEnabled()).build());
}*/
SharedPreferences sharedPreferences = MainApplication.getSharedPreferences(); SharedPreferences sharedPreferences = MainApplication.getSharedPreferences();
// We are only one process so it's ok to do this // We are only one process so it's ok to do this
SharedPreferences bootPrefs = MainApplication.bootSharedPreferences = this.getSharedPreferences("mmm_boot", MODE_PRIVATE); SharedPreferences bootPrefs = MainApplication.bootSharedPreferences = this.getSharedPreferences("mmm_boot", MODE_PRIVATE);
@ -332,6 +316,10 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
} }
} }
private Intent getIntent() {
return this.getPackageManager().getLaunchIntentForPackage(this.getPackageName());
}
@Override @Override
public void onCreateFoxActivity(FoxActivity compatActivity) { public void onCreateFoxActivity(FoxActivity compatActivity) {
super.onCreateFoxActivity(compatActivity); super.onCreateFoxActivity(compatActivity);

@ -179,8 +179,8 @@ public final class AndroidacyActivity extends FoxActivity {
// Don't open non Androidacy urls inside WebView // Don't open non Androidacy urls inside WebView
if (request.isForMainFrame() && !AndroidacyUtil.isAndroidacyLink(request.getUrl())) { if (request.isForMainFrame() && !AndroidacyUtil.isAndroidacyLink(request.getUrl())) {
if (downloadMode || backOnResume) return true; if (downloadMode || backOnResume) return true;
Log.i(TAG, "Exiting WebView " + // hideToken in case isAndroidacyLink fail. Log.i(TAG,
AndroidacyUtil.hideToken(request.getUrl().toString())); "Exiting WebView " + AndroidacyUtil.hideToken(request.getUrl().toString()));
IntentHelper.openUri(view.getContext(), request.getUrl().toString()); IntentHelper.openUri(view.getContext(), request.getUrl().toString());
return true; return true;
} }

@ -2,6 +2,7 @@ package com.fox2code.mmm.repo;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -51,7 +52,7 @@ public class RepoData extends XRepo {
this.defaultName = url; // Set url as default name this.defaultName = url; // Set url as default name
this.forceHide = AppUpdateManager.shouldForceHide(this.id); this.forceHide = AppUpdateManager.shouldForceHide(this.id);
this.enabled = (!this.forceHide) && MainApplication.getSharedPreferences() this.enabled = (!this.forceHide) && MainApplication.getSharedPreferences()
.getBoolean("pref_" + this.id + "_enabled", this.isEnabledByDefault()); .getBoolean("pref_" + this.getPreferenceId() + "_enabled", true);
this.defaultWebsite = "https://" + Uri.parse(url).getHost() + "/"; this.defaultWebsite = "https://" + Uri.parse(url).getHost() + "/";
if (!this.cacheRoot.isDirectory()) { if (!this.cacheRoot.isDirectory()) {
boolean mkdirs = this.cacheRoot.mkdirs(); boolean mkdirs = this.cacheRoot.mkdirs();
@ -206,14 +207,22 @@ public class RepoData extends XRepo {
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled && !this.forceHide; this.enabled = enabled && !this.forceHide;
if (BuildConfig.DEBUG) {
Log.d("RepoData",
"Repo " + this.id + " enabled: " + this.enabled + " (forced: " + this.forceHide + ") with preferenceID: " + this.getPreferenceId());
}
MainApplication.getSharedPreferences().edit() MainApplication.getSharedPreferences().edit()
.putBoolean("pref_" + this.getPreferenceId() + "_enabled", enabled).apply(); .putBoolean("pref_" + this.getPreferenceId() + "_enabled", enabled).apply();
} }
public void updateEnabledState() { public void updateEnabledState() {
this.forceHide = AppUpdateManager.shouldForceHide(this.id); this.forceHide = AppUpdateManager.shouldForceHide(this.id);
if (BuildConfig.DEBUG) {
Log.d("RepoData",
"Repo " + this.id + " update enabled: " + this.enabled + " (forced: " + this.forceHide + ") with preferenceID: " + this.getPreferenceId());
}
this.enabled = (!this.forceHide) && MainApplication.getSharedPreferences() this.enabled = (!this.forceHide) && MainApplication.getSharedPreferences()
.getBoolean("pref_" + this.getPreferenceId() + "_enabled", this.isEnabledByDefault()); .getBoolean("pref_" + this.getPreferenceId() + "_enabled", true);
} }
public String getUrl() throws NoSuchAlgorithmException { public String getUrl() throws NoSuchAlgorithmException {

@ -138,7 +138,7 @@ public final class RepoManager extends SyncManager {
case ANDROIDACY_TEST_MAGISK_REPO_ENDPOINT: case ANDROIDACY_TEST_MAGISK_REPO_ENDPOINT:
return "androidacy_repo"; return "androidacy_repo";
default: default:
return "repo_" + Hashes.hashSha1( return "repo_" + Hashes.hashSha256(
url.getBytes(StandardCharsets.UTF_8)); url.getBytes(StandardCharsets.UTF_8));
} }
} }
@ -223,26 +223,26 @@ public final class RepoManager extends SyncManager {
RepoUpdater[] repoUpdaters = new RepoUpdater[repoDatas.length]; RepoUpdater[] repoUpdaters = new RepoUpdater[repoDatas.length];
int moduleToUpdate = 0; int moduleToUpdate = 0;
for (int i = 0; i < repoDatas.length; i++) { for (int i = 0; i < repoDatas.length; i++) {
if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoDatas[i].getName()); if (BuildConfig.DEBUG) Log.d("RepoManager", "Fetching: " + repoDatas[i].getName());
moduleToUpdate += (repoUpdaters[i] = moduleToUpdate += (repoUpdaters[i] =
new RepoUpdater(repoDatas[i])).fetchIndex(); new RepoUpdater(repoDatas[i])).fetchIndex();
updateListener.update(STEP1 / repoDatas.length * (i + 1)); updateListener.update(STEP1 / repoDatas.length * (i + 1));
} }
if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Updating meta-data"); if (BuildConfig.DEBUG) Log.d("RepoManag3er", "Updating meta-data");
int updatedModules = 0; int updatedModules = 0;
boolean allowLowQualityModules = MainApplication.isDisableLowQualityModuleFilter(); boolean allowLowQualityModules = MainApplication.isDisableLowQualityModuleFilter();
for (int i = 0; i < repoUpdaters.length; i++) { for (int i = 0; i < repoUpdaters.length; i++) {
// Check if the repo is enabled // Check if the repo is enabled
if (!repoUpdaters[i].repoData.isEnabled()) { if (!repoUpdaters[i].repoData.isEnabled()) {
if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Skipping disabled repo: " + repoUpdaters[i].repoData.getName()); if (BuildConfig.DEBUG) Log.d("RepoManager",
"Skipping disabled repo: " + repoUpdaters[i].repoData.getName());
continue; continue;
} }
List<RepoModule> repoModules = repoUpdaters[i].toUpdate(); List<RepoModule> repoModules = repoUpdaters[i].toUpdate();
RepoData repoData = repoDatas[i]; RepoData repoData = repoDatas[i];
if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoData.getName()); if (BuildConfig.DEBUG) Log.d("RepoManager", "Registering " + repoData.getName());
if (BuildConfig.DEBUG) Log.d(TAG, "Registering " + repoData.getName());
for (RepoModule repoModule : repoModules) { for (RepoModule repoModule : repoModules) {
if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoModule.id); if (BuildConfig.DEBUG) Log.d("RepoManager", "Fetching module: " + repoModule.id);
try { try {
if (repoModule.propUrl != null && if (repoModule.propUrl != null &&
!repoModule.propUrl.isEmpty()) { !repoModule.propUrl.isEmpty()) {
@ -280,7 +280,7 @@ public final class RepoManager extends SyncManager {
} }
} }
} }
if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Finishing update"); if (BuildConfig.DEBUG) Log.d("RepoManager", "Finishing update");
this.hasInternet = false; this.hasInternet = false;
// Check if we have internet connection // Check if we have internet connection
// Attempt to contact connectivitycheck.gstatic.com/generate_204 // Attempt to contact connectivitycheck.gstatic.com/generate_204
@ -304,11 +304,12 @@ public final class RepoManager extends SyncManager {
for (int i = 0; i < repoDatas.length; i++) { for (int i = 0; i < repoDatas.length; i++) {
// If repo is not enabled, skip // If repo is not enabled, skip
if (!repoDatas[i].isEnabled()) { if (!repoDatas[i].isEnabled()) {
if (BuildConfig.DEBUG) Log.d("NoodleDebug", if (BuildConfig.DEBUG) Log.d("RepoManager",
"Skipping " + repoDatas[i].getName() + " because it's disabled"); "Skipping " + repoDatas[i].getName() + " because it's disabled");
continue; continue;
} }
if (BuildConfig.DEBUG) Log.d("NoodleDebug", repoUpdaters[i].repoData.getName()); if (BuildConfig.DEBUG) Log.d("RepoManager",
"Finishing: " + repoUpdaters[i].repoData.getName());
this.repoLastSuccess = repoUpdaters[i].finish(); this.repoLastSuccess = repoUpdaters[i].finish();
if (!this.repoLastSuccess) { if (!this.repoLastSuccess) {
Log.e(TAG, "Failed to update " + repoUpdaters[i].repoData.getName()); Log.e(TAG, "Failed to update " + repoUpdaters[i].repoData.getName());

@ -324,6 +324,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
if (!SentryMain.IS_SENTRY_INSTALLED || !BuildConfig.DEBUG || if (!SentryMain.IS_SENTRY_INSTALLED || !BuildConfig.DEBUG ||
InstallerInitializer.peekMagiskPath() == null) { InstallerInitializer.peekMagiskPath() == null) {
// Hide the pref_crash option if not in debug mode - stop users from purposely crashing the app // Hide the pref_crash option if not in debug mode - stop users from purposely crashing the app
Log.d(TAG, String.format("Sentry installed: %s, debug: %s, magisk path: %s",
SentryMain.IS_SENTRY_INSTALLED, BuildConfig.DEBUG, InstallerInitializer.peekMagiskPath()));
Objects.requireNonNull((Preference) findPreference("pref_crash")).setVisible(false); Objects.requireNonNull((Preference) findPreference("pref_crash")).setVisible(false);
} else { } else {
findPreference("pref_crash").setOnPreferenceClickListener(preference -> { findPreference("pref_crash").setOnPreferenceClickListener(preference -> {
@ -864,12 +866,20 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
preference.setTitle(repoData.getName()); preference.setTitle(repoData.getName());
preference = findPreference(preferenceName + "_enabled"); preference = findPreference(preferenceName + "_enabled");
if (preference != null) { if (preference != null) {
((TwoStatePreference) preference).setChecked(repoData.isEnabled()); // Handle custom repo separately
preference.setTitle(repoData.isEnabled() ? R.string.repo_enabled : R.string.repo_disabled); if (repoData instanceof CustomRepoData) {
preference.setOnPreferenceChangeListener((p, newValue) -> { preference.setTitle(R.string.custom_repo_always_on);
p.setTitle(((Boolean) newValue) ? R.string.repo_enabled : R.string.repo_disabled); // Disable the preference
return true; preference.setEnabled(false);
}); return;
} else {
((TwoStatePreference) preference).setChecked(repoData.isEnabled());
preference.setTitle(repoData.isEnabled() ? R.string.repo_enabled : R.string.repo_disabled);
preference.setOnPreferenceChangeListener((p, newValue) -> {
p.setTitle(((Boolean) newValue) ? R.string.repo_enabled : R.string.repo_disabled);
return true;
});
}
} }
preference = findPreference(preferenceName + "_website"); preference = findPreference(preferenceName + "_website");
String homepage = repoData.getWebsite(); String homepage = repoData.getWebsite();

@ -203,4 +203,5 @@
<string name="blur_disabled_summary">Blur is not compatible with transparent themes.</string> <string name="blur_disabled_summary">Blur is not compatible with transparent themes.</string>
<string name="transparent_theme_dialogue_title">You are setting a transparent theme</string> <string name="transparent_theme_dialogue_title">You are setting a transparent theme</string>
<string name="transparent_theme_dialogue_message">Transparent themes may have some inconsistencies and may not work on all ROMs. In additon, monet and blur will be disabled. You can change back at any time.</string> <string name="transparent_theme_dialogue_message">Transparent themes may have some inconsistencies and may not work on all ROMs. In additon, monet and blur will be disabled. You can change back at any time.</string>
<string name="custom_repo_always_on">Custom repos are always on until you remove them.</string>
</resources> </resources>

@ -90,12 +90,16 @@
<PreferenceCategory <PreferenceCategory
app:key="pref_custom_repo_0" app:key="pref_custom_repo_0"
app:title="@string/loading"> app:title="@string/loading">
<!-- Custom repos can't be enabled/disabled. Instead, they must be deleted. Show a disabled
switch to indicate that. -->
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="true"
app:enabled="false"
app:icon="@drawable/ic_baseline_extension_24" app:icon="@drawable/ic_baseline_extension_24"
app:key="pref_custom_repo_0_enabled" app:key="pref_custom_repo_0_enabled"
app:singleLineTitle="false" app:singleLineTitle="false"
app:switchTextOff="@string/repo_disabled" app:switchTextOff="@string/repo_disabled"
app:switchTextOn="@string/repo_enabled" /> app:switchTextOn="@string/custom_repo_always_on" />
<com.fox2code.mmm.settings.LongClickablePreference <com.fox2code.mmm.settings.LongClickablePreference
app:icon="@drawable/ic_baseline_language_24" app:icon="@drawable/ic_baseline_language_24"
app:key="pref_custom_repo_0_website" app:key="pref_custom_repo_0_website"
@ -126,11 +130,13 @@
app:key="pref_custom_repo_1" app:key="pref_custom_repo_1"
app:title="@string/loading"> app:title="@string/loading">
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="true"
app:enabled="false"
app:icon="@drawable/ic_baseline_extension_24" app:icon="@drawable/ic_baseline_extension_24"
app:key="pref_custom_repo_1_enabled" app:key="pref_custom_repo_1_enabled"
app:singleLineTitle="false" app:singleLineTitle="false"
app:switchTextOff="@string/repo_disabled" app:switchTextOff="@string/repo_disabled"
app:switchTextOn="@string/repo_enabled" /> app:switchTextOn="@string/custom_repo_always_on" />/>
<com.fox2code.mmm.settings.LongClickablePreference <com.fox2code.mmm.settings.LongClickablePreference
app:icon="@drawable/ic_baseline_language_24" app:icon="@drawable/ic_baseline_language_24"
app:key="pref_custom_repo_1_website" app:key="pref_custom_repo_1_website"
@ -161,11 +167,13 @@
app:key="pref_custom_repo_2" app:key="pref_custom_repo_2"
app:title="@string/loading"> app:title="@string/loading">
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="true"
app:enabled="false"
app:icon="@drawable/ic_baseline_extension_24" app:icon="@drawable/ic_baseline_extension_24"
app:key="pref_custom_repo_2_enabled" app:key="pref_custom_repo_2_enabled"
app:singleLineTitle="false" app:singleLineTitle="false"
app:switchTextOff="@string/repo_disabled" app:switchTextOff="@string/repo_disabled"
app:switchTextOn="@string/repo_enabled" /> app:switchTextOn="@string/custom_repo_always_on" />
<com.fox2code.mmm.settings.LongClickablePreference <com.fox2code.mmm.settings.LongClickablePreference
app:icon="@drawable/ic_baseline_language_24" app:icon="@drawable/ic_baseline_language_24"
app:key="pref_custom_repo_2_website" app:key="pref_custom_repo_2_website"
@ -196,11 +204,13 @@
app:key="pref_custom_repo_3" app:key="pref_custom_repo_3"
app:title="@string/loading"> app:title="@string/loading">
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="true"
app:enabled="false"
app:icon="@drawable/ic_baseline_extension_24" app:icon="@drawable/ic_baseline_extension_24"
app:key="pref_custom_repo_3_enabled" app:key="pref_custom_repo_3_enabled"
app:singleLineTitle="false" app:singleLineTitle="false"
app:switchTextOff="@string/repo_disabled" app:switchTextOff="@string/repo_disabled"
app:switchTextOn="@string/repo_enabled" /> app:switchTextOn="@string/custom_repo_always_on" />
<com.fox2code.mmm.settings.LongClickablePreference <com.fox2code.mmm.settings.LongClickablePreference
app:icon="@drawable/ic_baseline_language_24" app:icon="@drawable/ic_baseline_language_24"
app:key="pref_custom_repo_3_website" app:key="pref_custom_repo_3_website"
@ -231,11 +241,13 @@
app:key="pref_custom_repo_4" app:key="pref_custom_repo_4"
app:title="@string/loading"> app:title="@string/loading">
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="true"
app:enabled="false"
app:icon="@drawable/ic_baseline_extension_24" app:icon="@drawable/ic_baseline_extension_24"
app:key="pref_custom_repo_4_enabled" app:key="pref_custom_repo_4_enabled"
app:singleLineTitle="false" app:singleLineTitle="false"
app:switchTextOff="@string/repo_disabled" app:switchTextOff="@string/repo_disabled"
app:switchTextOn="@string/repo_enabled" /> app:switchTextOn="@string/custom_repo_always_on" />
<com.fox2code.mmm.settings.LongClickablePreference <com.fox2code.mmm.settings.LongClickablePreference
app:icon="@drawable/ic_baseline_language_24" app:icon="@drawable/ic_baseline_language_24"
app:key="pref_custom_repo_4_website" app:key="pref_custom_repo_4_website"

@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="QueryAllPackagesPermission"> tools:ignore="QueryAllPackagesPermission">
<uses-sdk tools:overrideLibrary="io.sentry.android" />
<application android:icon="@mipmap/ic_launcher" android:enableOnBackInvokedCallback="true" <application android:icon="@mipmap/ic_launcher" android:enableOnBackInvokedCallback="true"
tools:targetApi="tiramisu"> tools:targetApi="tiramisu">

@ -1,5 +1,8 @@
package com.fox2code.mmm.sentry; package com.fox2code.mmm.sentry;
import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT;
import android.annotation.SuppressLint;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
@ -7,23 +10,17 @@ import com.fox2code.mmm.BuildConfig;
import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.androidacy.AndroidacyUtil; import com.fox2code.mmm.androidacy.AndroidacyUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import io.sentry.Breadcrumb;
import io.sentry.Hint;
import io.sentry.JsonObjectWriter; import io.sentry.JsonObjectWriter;
import io.sentry.NoOpLogger; import io.sentry.NoOpLogger;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.SentryOptions; import io.sentry.UserFeedback;
import io.sentry.TypeCheckHint;
import io.sentry.android.core.SentryAndroid; import io.sentry.android.core.SentryAndroid;
import io.sentry.android.fragment.FragmentLifecycleIntegration; import io.sentry.android.fragment.FragmentLifecycleIntegration;
import io.sentry.android.okhttp.SentryOkHttpInterceptor;
import io.sentry.hints.DiskFlushNotification; import io.sentry.hints.DiskFlushNotification;
import io.sentry.protocol.SentryId;
public class SentryMain { public class SentryMain {
public static final boolean IS_SENTRY_INSTALLED = true; public static final boolean IS_SENTRY_INSTALLED = true;
@ -33,6 +30,7 @@ public class SentryMain {
* Initialize Sentry * Initialize Sentry
* Sentry is used for crash reporting and performance monitoring. The SDK is explcitly configured not to send PII, and server side scrubbing of sensitive data is enabled (which also removes IP addresses) * Sentry is used for crash reporting and performance monitoring. The SDK is explcitly configured not to send PII, and server side scrubbing of sensitive data is enabled (which also removes IP addresses)
*/ */
@SuppressLint("RestrictedApi")
public static void initialize(final MainApplication mainApplication) { public static void initialize(final MainApplication mainApplication) {
SentryAndroid.init(mainApplication, options -> { SentryAndroid.init(mainApplication, options -> {
// If crash reporting is disabled, stop here. // If crash reporting is disabled, stop here.
@ -40,6 +38,12 @@ public class SentryMain {
options.setDsn(""); options.setDsn("");
} else { } else {
options.addIntegration(new FragmentLifecycleIntegration(mainApplication, true, true)); options.addIntegration(new FragmentLifecycleIntegration(mainApplication, true, true));
options.setCollectAdditionalContext(true);
options.setAttachThreads(true);
options.setAttachStacktrace(true);
options.setEnableNdk(true);
// Intercept okhttp requests to add sentry headers
options.addInAppInclude("com.fox2code.mmm");
// Sentry sends ABSOLUTELY NO Personally Identifiable Information (PII) by default. // Sentry sends ABSOLUTELY NO Personally Identifiable Information (PII) by default.
// Already set to false by default, just set it again to make peoples feel safer. // Already set to false by default, just set it again to make peoples feel safer.
options.setSendDefaultPii(false); options.setSendDefaultPii(false);
@ -86,27 +90,36 @@ public class SentryMain {
Log.i(TAG, stringBuilder.toString()); Log.i(TAG, stringBuilder.toString());
} }
if (MainApplication.isCrashReportingEnabled()) { if (MainApplication.isCrashReportingEnabled()) {
// Get user feedback
SentryId sentryId = event.getEventId();
if (sentryId != null) {
UserFeedback userFeedback = new UserFeedback(sentryId);
userFeedback.setName("Anonymous");
userFeedback.setEmail("test@test.com");
userFeedback.setComments("No comments");
Sentry.captureUserFeedback(userFeedback);
}
return event; return event;
} else { } else {
// We need to do this to avoid crash delay on crash when the event is dropped // We need to do this to avoid crash delay on crash when the event is dropped
DiskFlushNotification diskFlushNotification = hint.getAs( DiskFlushNotification diskFlushNotification = hint.getAs(
TypeCheckHint.SENTRY_TYPE_CHECK_HINT, DiskFlushNotification.class); SENTRY_TYPE_CHECK_HINT, DiskFlushNotification.class);
if (diskFlushNotification != null) diskFlushNotification.markFlushed(); if (diskFlushNotification != null) diskFlushNotification.markFlushed();
return null; return null;
} }
}); });
// Filter breadrcrumb content from crash report.
options.setBeforeBreadcrumb((breadcrumb, hint) -> {
String url = (String) breadcrumb.getData("url");
if (url == null || url.isEmpty()) return breadcrumb;
if ("cloudflare-dns.com".equals(Uri.parse(url).getHost()))
return null;
if (AndroidacyUtil.isAndroidacyLink(url)) {
breadcrumb.setData("url", AndroidacyUtil.hideToken(url));
}
return breadcrumb;
});
} }
// Filter breadrcrumb content from crash report.
options.setBeforeBreadcrumb((breadcrumb, hint) -> {
String url = (String) breadcrumb.getData("url");
if (url == null || url.isEmpty()) return breadcrumb;
if ("cloudflare-dns.com".equals(Uri.parse(url).getHost()))
return null;
if (AndroidacyUtil.isAndroidacyLink(url)) {
breadcrumb.setData("url", AndroidacyUtil.hideToken(url));
}
return breadcrumb;
});
}); });
} }

@ -100,7 +100,7 @@ Note²: For `minMagisk`, `XX.Y` is parsed as `XXY00`, so you can just put the Ma
(For example `- Hello world` will be transformed to `[*] Hello world`, do not apply to modules installed from storage) (For example `- Hello world` will be transformed to `[*] Hello world`, do not apply to modules installed from storage)
Note: Fox's Mmm use fallback Note: Fox's Mmm use fallback
[here](app/src/main/java/com/fox2code/mmm/utils/PropUtils.java#L36) [here](../app/src/main/java/com/fox2code/mmm/utils/PropUtils.java#L36)
for some modules for some modules
Theses values are only used if not defined in the `module.prop` files Theses values are only used if not defined in the `module.prop` files
So the original module maker can still override them So the original module maker can still override them
@ -173,7 +173,7 @@ mmm_exec hideLoading
mmm_exec setSupportLink https://github.com/Fox2Code/FoxMagiskModuleManager mmm_exec setSupportLink https://github.com/Fox2Code/FoxMagiskModuleManager
``` ```
[You may look at the examples modules and their codes.](examples) [You may look at the examples modules and their codes.](../examples)
## Developer mode ## Developer mode

@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:Reserv
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true # android.enableJetifier=true
# Fox builds props mods # Fox builds props mods
org.gradle.parallel=true org.gradle.parallel=true

@ -1,6 +1,6 @@
#Sun Jun 05 10:40:53 EDT 2022 #Sun Jun 05 10:40:53 EDT 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
Loading…
Cancel
Save