more work on realm

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/284/head
androidacy-user 1 year ago
parent 5b3bf70f83
commit a54ecbc6d8

@ -12,6 +12,7 @@ apply plugin: "realm-android"
android {
namespace "com.fox2code.mmm"
compileSdk 33
ndkVersion "25.1.8937393"
signingConfigs {
release {
// Everything comes from local.properties
@ -288,7 +289,12 @@ dependencies {
implementation 'com.github.topjohnwu.libsu:io:5.0.1'
implementation 'com.github.Fox2Code:RosettaX:1.0.9'
implementation 'com.github.Fox2Code:AndroidANSI:1.0.1'
// sentry
implementation "io.sentry:sentry-android:$sentry_version"
implementation "io.sentry:sentry-android-timber:$sentry_version"
implementation "io.sentry:sentry-android-fragment:$sentry_version"
implementation "io.sentry:sentry-android-okhttp:$sentry_version"
// Markdown
implementation "io.noties.markwon:core:4.6.2"
@ -307,7 +313,9 @@ dependencies {
// timber
implementation 'com.jakewharton.timber:timber:5.0.1'
implementation "io.sentry:sentry-android-timber:$sentry_version"
// ksp
implementation "com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.8"
}
if (hasSentryConfig) {

@ -150,12 +150,19 @@ public class AppUpdateManager {
// 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(".", ""));
currentVersion = Integer.parseInt(BuildConfig.VERSION_NAME.replaceAll("\\D", ""));
latestVersion = Integer.parseInt(this.latestRelease.replace("v", "").replaceAll("\\D", ""));
} catch (
NumberFormatException ignored) {
}
return currentVersion < latestVersion || (this.preReleaseNewer && currentVersion < Integer.parseInt(this.latestPreRelease.replace(".", "")));
int latestPreReleaseVersion = 0;
// replace all non-numeric characters with empty string
try {
latestPreReleaseVersion = Integer.parseInt(this.latestPreRelease.replaceAll("\\D", ""));
} catch (
NumberFormatException ignored) {
}
return currentVersion < latestVersion || (this.preReleaseNewer && currentVersion < latestPreReleaseVersion);
}
public boolean peekHasUpdate() {

@ -11,17 +11,28 @@ import android.widget.Toast;
import com.fox2code.foxcompat.app.FoxActivity;
import com.google.android.material.textview.MaterialTextView;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import io.sentry.Sentry;
import io.sentry.UserFeedback;
import io.sentry.protocol.SentryId;
import timber.log.Timber;
public class CrashHandler extends FoxActivity {
@SuppressLint("RestrictedApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
Timber.i("CrashHandler.onCreate(%s)", savedInstanceState);
// log intent with extras
Timber.d("CrashHandler.onCreate: intent=%s", getIntent());
// get exception, stacktrace, and lastEventId from intent and log them
Timber.d("CrashHandler.onCreate: exception=%s", getIntent().getSerializableExtra("exception"));
Timber.d("CrashHandler.onCreate: stacktrace=%s", getIntent().getSerializableExtra("stacktrace"));
Timber.d("CrashHandler.onCreate: lastEventId=%s", getIntent().getStringExtra("lastEventId"));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash_handler);
// set crash_details MaterialTextView to the exception passed in the intent or unknown if null
@ -43,11 +54,12 @@ public class CrashHandler extends FoxActivity {
stacktrace = stacktrace.replace(",", "\n ");
crashDetails.setText(getString(R.string.crash_full_stacktrace, stacktrace));
}
SharedPreferences preferences = getSharedPreferences("sentry", MODE_PRIVATE);
// get lastEventId from intent
String lastEventId = getIntent().getStringExtra("lastEventId");
// disable feedback if sentry is disabled
if (MainApplication.isCrashReportingEnabled()) {
SharedPreferences preferences = getSharedPreferences("sentry", MODE_PRIVATE);
// get lastEventId from intent
SentryId lastEventId = Sentry.captureException((Throwable) getIntent().getSerializableExtra("exception"));
//noinspection ConstantConditions
if (MainApplication.isCrashReportingEnabled() && !BuildConfig.SENTRY_TOKEN.equals("") && lastEventId != null) {
// get name, email, and message fields
EditText name = findViewById(R.id.feedback_name);
EditText email = findViewById(R.id.feedback_email);
@ -60,17 +72,48 @@ public class CrashHandler extends FoxActivity {
return;
}
// if email or name is empty, use "Anonymous"
String nameString = name.getText().toString().equals("") ? "Anonymous" : name.getText().toString();
String emailString = email.getText().toString().equals("") ? "Anonymous" : email.getText().toString();
final String[] nameString = {name.getText().toString().equals("") ? "Anonymous" : name.getText().toString()};
final String[] emailString = {email.getText().toString().equals("") ? "Anonymous" : email.getText().toString()};
// Prevent strict mode violation
// create sentry userFeedback request
new Thread(() -> {
// create sentry userFeedback request
UserFeedback userFeedback = new UserFeedback(lastEventId);
userFeedback.setName(nameString);
userFeedback.setEmail(emailString);
userFeedback.setComments(description.getText().toString());
// send the request
Sentry.captureUserFeedback(userFeedback);
try {
HttpURLConnection connection = (HttpURLConnection) new URL("https" + "://sentry.io/api/0/projects/androidacy-i6/foxmmm/user-feedback/").openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + BuildConfig.SENTRY_TOKEN);
// Setups the JSON body
if (nameString[0].equals(""))
nameString[0] = "Anonymous";
if (emailString[0].equals(""))
emailString[0] = "Anonymous";
JSONObject body = new JSONObject();
body.put("event_id", lastEventId);
body.put("name", nameString[0]);
body.put("email", emailString[0]);
body.put("comments", description.getText().toString());
// Send the request
connection.setDoOutput(true);
connection.getOutputStream().write(body.toString().getBytes());
connection.connect();
// For debug builds, log the response code and response body
if (BuildConfig.DEBUG) {
Timber.d("Response Code: %s", connection.getResponseCode());
}
// Check if the request was successful
if (connection.getResponseCode() == 200) {
runOnUiThread(() -> Toast.makeText(this, R.string.sentry_dialogue_success, Toast.LENGTH_LONG).show());
} else {
runOnUiThread(() -> Toast.makeText(this, R.string.sentry_dialogue_failed_toast, Toast.LENGTH_LONG).show());
}
// close and disconnect the connection
connection.disconnect();
} catch (
JSONException |
IOException ignored) {
// Show a toast if the user feedback could not be submitted
runOnUiThread(() -> Toast.makeText(this, R.string.sentry_dialogue_failed_toast, Toast.LENGTH_LONG).show());
}
}).start();
// Close the activity
finish();
@ -123,7 +166,8 @@ public class CrashHandler extends FoxActivity {
new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
} catch (
InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(() -> view.setBackgroundResource(R.drawable.baseline_copy_all_24));

@ -47,11 +47,16 @@ import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
import io.realm.Realm;
import io.sentry.IHub;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import io.sentry.android.timber.SentryTimberTree;
import timber.log.Timber;
public class MainApplication extends FoxApplication implements androidx.work.Configuration.Provider {
// Warning! Locales that are't exist will crash the app
// Anything that is commented out is supported but the translation is not complete to at least 60%
public static final HashSet<String> supportedLocales = new HashSet<>();
private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001
private static final Shell.Builder shellBuilder;
private static final long secret;
@ -59,9 +64,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
// Use FoxProcess wrapper helper.
private static final boolean wrapped = !FoxProcessExt.isRootLoader();
public static boolean isOfficial = false;
// Warning! Locales that are't exist will crash the app
// Anything that is commented out is supported but the translation is not complete to at least 60%
public static final HashSet<String> supportedLocales = new HashSet<>();
private static Locale timeFormatLocale = Resources.getSystem().getConfiguration().getLocales().get(0);
private static SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString, timeFormatLocale);
private static SharedPreferences bootSharedPreferences;
@ -282,8 +284,16 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
@Override
public void onCreate() {
// init timber
if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree());
else Timber.plant(new ReleaseTree());
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
} else {
if (isCrashReportingEnabled()) {
@SuppressWarnings("UnstableApiUsage") IHub hub = Sentry.getCurrentHub();
Timber.plant(new SentryTimberTree(hub, SentryLevel.ERROR, SentryLevel.ERROR));
} else {
Timber.plant(new ReleaseTree());
}
}
// supportedLocales.add("ar");
// supportedLocales.add("ar_SA");
supportedLocales.add("cs");
@ -479,17 +489,16 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
}
private static class ReleaseTree extends Timber.Tree {
@SuppressWarnings("StatementWithEmptyBody")
@Override
protected void log(int priority, String tag, @NonNull String message, Throwable t) {
if (priority == Log.VERBOSE || priority == Log.DEBUG) {
// silently ignore
} else if (priority == Log.INFO) {
Sentry.captureMessage(message, SentryLevel.INFO);
} else if (priority == Log.WARN) {
Sentry.captureMessage(message, SentryLevel.WARNING);
} else if (priority == Log.ERROR) {
Sentry.captureException(t);
// basically silently drop all logs below error, and write the rest to logcat
if (priority >= Log.ERROR) {
if (t != null) {
Log.println(priority, tag, message);
t.printStackTrace();
} else {
Log.println(priority, tag, message);
}
}
}
}

@ -18,7 +18,6 @@ import com.fox2code.foxcompat.app.FoxActivity;
import com.fox2code.mmm.androidacy.AndroidacyRepoData;
import com.fox2code.mmm.databinding.ActivitySetupBinding;
import com.fox2code.mmm.repo.RepoManager;
import com.fox2code.mmm.utils.realm.ModuleListCache;
import com.fox2code.mmm.utils.realm.ReposList;
import com.fox2code.rosettax.LanguageActivity;
import com.fox2code.rosettax.LanguageSwitcher;
@ -275,17 +274,6 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
// creates the realm database
private void createRealmDatabase() {
Timber.d("Creating Realm databases");
// create the realm database for ModuleListCache
RealmConfiguration config = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).build();
// do a dummy write to create the database
Realm.getInstanceAsync(config, new Realm.Callback() {
@Override
public void onSuccess(@NonNull Realm realm) {
realm.executeTransactionAsync(realm1 -> {
// do nothing
});
}
});
// create the realm database for ReposList
// next, create the realm database for ReposList
RealmConfiguration config2 = new RealmConfiguration.Builder().name("ReposList.realm").directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
@ -332,16 +320,9 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
realm1.close();
if (BuildConfig.DEBUG) {
Timber.d("Realm databases created");
// log each database
Realm realm2 = Realm.getInstance(config);
RealmResults<ModuleListCache> moduleListCaches = realm2.where(ModuleListCache.class).findAll();
Timber.d("ModuleListCache.realm");
for (ModuleListCache moduleListCache : moduleListCaches) {
Timber.d(moduleListCache.toString());
}
realm2.close();
Realm realm3 = Realm.getInstance(config2);
RealmResults<ReposList> reposLists = realm3.where(ReposList.class).findAll();
assert reposLists != null;
Timber.d("ReposList.realm");
for (ReposList reposList : reposLists) {
Timber.d(reposList.toString());

@ -36,8 +36,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import okhttp3.HttpUrl;
import timber.log.Timber;
@ -64,9 +62,6 @@ public final class AndroidacyRepoData extends RepoData {
public AndroidacyRepoData(File cacheRoot, SharedPreferences cachedPreferences, boolean testMode) {
super(testMode ? RepoManager.ANDROIDACY_TEST_MAGISK_REPO_ENDPOINT : RepoManager.ANDROIDACY_MAGISK_REPO_ENDPOINT, cacheRoot, cachedPreferences);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").allowWritesOnUiThread(true).allowWritesOnUiThread(true).directory(cacheRoot).build();
Realm.setDefaultConfiguration(realmConfiguration);
Realm.getInstance(realmConfiguration);
this.defaultName = "Androidacy Modules Repo";
this.defaultWebsite = RepoManager.ANDROIDACY_MAGISK_REPO_HOMEPAGE;
this.defaultSupport = "https://t.me/androidacy_discussions";

@ -383,7 +383,7 @@ public final class RepoManager extends SyncManager {
private RepoData addRepoData(String url, String fallBackName) {
String id = internalIdOfUrl(url);
File cacheRoot = new File(this.mainApplication.getDataDir(), id);
File cacheRoot = new File(this.mainApplication.getDataDir(), "repos/" + id);
SharedPreferences sharedPreferences = this.mainApplication.getSharedPreferences("mmm_" + id, Context.MODE_PRIVATE);
RepoData repoData = id.startsWith("repo_") ? new CustomRepoData(url, cacheRoot, sharedPreferences) : new RepoData(url, cacheRoot, sharedPreferences);
if (fallBackName != null && !fallBackName.isEmpty()) {
@ -409,7 +409,7 @@ public final class RepoManager extends SyncManager {
private AndroidacyRepoData addAndroidacyRepoData() {
// cache dir is actually under app data
File cacheRoot = new File(this.mainApplication.getDataDir(), "androidacy_repo");
File cacheRoot = new File(this.mainApplication.getDataDir(), "repos/androidacy_repo");
SharedPreferences sharedPreferences = this.mainApplication.getSharedPreferences("mmm_androidacy_repo", Context.MODE_PRIVATE);
AndroidacyRepoData repoData = new AndroidacyRepoData(cacheRoot, sharedPreferences, MainApplication.isAndroidacyTestMode());
this.repoData.put(ANDROIDACY_MAGISK_REPO_ENDPOINT, repoData);

@ -1,13 +1,12 @@
package com.fox2code.mmm.repo;
import androidx.annotation.NonNull;
import com.fox2code.mmm.utils.io.Http;
import com.fox2code.mmm.utils.realm.ModuleListCache;
import org.json.JSONException;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
@ -84,8 +83,8 @@ public class RepoUpdater {
// iterate over modules, using this.supportedProperties as a template to attempt to get each property from the module. everything that is not null is added to the module
// use realm to insert to
// props avail:
//
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().build();
File cacheRoot = this.repoData.cacheRoot;
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
// array with module info default values
// supported properties for a module
//id=<string>
@ -109,32 +108,21 @@ public class RepoUpdater {
//installedVersionCode=<int> (only if installed)
//
// all except first six can be null
// this.indexRaw is the raw index file (json) and the modules can be either under the "modules" key or the "data" key
// both are arrays of modules
// try to get modules from "modules" key
// this.indexRaw is the raw index file (json)
JSONObject modules = new JSONObject(new String(this.indexRaw, StandardCharsets.UTF_8));
// check if modules has key "modules" or "data"
try {
if (modules.has("modules")) {
// get modules from "modules" key
modules = modules.getJSONObject("modules");
} else if (modules.has("data")) {
// get modules from "data" key
modules = modules.getJSONObject("data");
}
} catch (JSONException e) {
// there's a possibility that the modules key is an array, so we need to convert it to a json object
// get modules array
JSONObject[] modulesArray = new JSONObject[]{modules};
// create new json object
modules = new JSONObject();
// iterate over modules array
for (int i = 0; i < modulesArray.length; i++) {
// put module in json object
modules.put(String.valueOf(i), modulesArray[i]);
}
JSONArray modulesArray;
// androidacy repo uses "data" key, others should use "modules" key. Both are JSONArrays
if (this.repoData.getName().equals("Androidacy Modules Repo")) {
// get modules from "data" key. This is a JSONArray so we need to convert it to a JSONObject
modulesArray = modules.getJSONArray("data");
} else {
// get modules from "modules" key. This is a JSONArray so we need to convert it to a JSONObject
modulesArray = modules.getJSONArray("modules");
}
for (JSONObject module : new JSONObject[]{modules}) {
// iterate over modules. pls dont hate me for this, its ugly but it works
for (int n = 0; n < modulesArray.length(); n++) {
// get module
JSONObject module = modulesArray.getJSONObject(n);
try {
// get module id
String id = module.getString("id");
@ -149,23 +137,74 @@ public class RepoUpdater {
// get module description
String description = module.getString("description");
// get module min api
int minApi = module.getInt("minApi");
// get module max api
int maxApi = module.getInt("maxApi");
String minApi;
if (module.has("minApi") && !module.getString("minApi").equals("")) {
minApi = module.getString("minApi");
} else {
minApi = "0";
}
// coerce min api to int
int minApiInt = Integer.parseInt(minApi);
// get module max api and set to 0 if it's "" or null
String maxApi;
if (module.has("maxApi") && !module.getString("maxApi").equals("")) {
maxApi = module.getString("maxApi");
} else {
maxApi = "0";
}
// coerce max api to int
int maxApiInt = Integer.parseInt(maxApi);
// get module min magisk
int minMagisk = module.getInt("minMagisk");
String minMagisk;
if (module.has("minMagisk") && !module.getString("minMagisk").equals("")) {
minMagisk = module.getString("minMagisk");
} else {
minMagisk = "0";
}
// coerce min magisk to int
int minMagiskInt = Integer.parseInt(minMagisk);
// get module need ramdisk
boolean needRamdisk = module.getBoolean("needRamdisk");
boolean needRamdisk;
if (module.has("needRamdisk")) {
needRamdisk = module.getBoolean("needRamdisk");
} else {
needRamdisk = false;
}
// get module support
String support = module.getString("support");
String support;
if (module.has("support")) {
support = module.getString("support");
} else {
support = "";
}
// get module donate
String donate = module.getString("donate");
String donate;
if (module.has("donate")) {
donate = module.getString("donate");
} else {
donate = "";
}
// get module config
String config = module.getString("config");
String config;
if (module.has("config")) {
config = module.getString("config");
} else {
config = "";
}
// get module change boot
boolean changeBoot = module.getBoolean("changeBoot");
boolean changeBoot;
if (module.has("changeBoot")) {
changeBoot = module.getBoolean("changeBoot");
} else {
changeBoot = false;
}
// get module mmt reborn
boolean mmtReborn = module.getBoolean("mmtReborn");
boolean mmtReborn;
if (module.has("mmtReborn")) {
mmtReborn = module.getBoolean("mmtReborn");
} else {
mmtReborn = false;
}
// get module repo id
String repoId = this.repoData.id;
// get module installed
@ -177,63 +216,53 @@ public class RepoUpdater {
// then insert to realm
// then commit
// then close
Realm.getInstanceAsync(realmConfiguration, new Realm.Callback() {
@Override
public void onSuccess(@NonNull Realm realm) {
realm.executeTransactionAsync(r -> {
// create a new module
ModuleListCache moduleListCache = r.createObject(ModuleListCache.class);
// set module id
moduleListCache.setId(id);
// set module name
moduleListCache.setName(name);
// set module version
moduleListCache.setVersion(version);
// set module version code
moduleListCache.setVersionCode(versionCode);
// set module author
moduleListCache.setAuthor(author);
// set module description
moduleListCache.setDescription(description);
// set module min api
moduleListCache.setMinApi(minApi);
// set module max api
moduleListCache.setMaxApi(maxApi);
// set module min magisk
moduleListCache.setMinMagisk(minMagisk);
// set module need ramdisk
moduleListCache.setNeedRamdisk(needRamdisk);
// set module support
moduleListCache.setSupport(support);
// set module donate
moduleListCache.setDonate(donate);
// set module config
moduleListCache.setConfig(config);
// set module change boot
moduleListCache.setChangeBoot(changeBoot);
// set module mmt reborn
moduleListCache.setMmtReborn(mmtReborn);
// set module repo id
moduleListCache.setRepoId(repoId);
// set module installed
moduleListCache.setInstalled(installed);
// set module installed version code
moduleListCache.setInstalledVersionCode(installedVersionCode);
}, () -> {
// Transaction was a success.
Timber.d("onSuccess: Transaction was a success.");
// close realm
realm.close();
}, error -> {
// Transaction failed and was automatically canceled.
Timber.e(error);
// close realm
realm.close();
});
}
Realm realm = Realm.getInstance(realmConfiguration);
if (realm.isInTransaction()) {
realm.cancelTransaction();
}
realm.executeTransaction(r -> {
// create the object
// if it already exists, it will be updated
// create a new module
ModuleListCache moduleListCache = r.createObject(ModuleListCache.class, id);
// set module name
moduleListCache.setName(name);
// set module version
moduleListCache.setVersion(version);
// set module version code
moduleListCache.setVersionCode(versionCode);
// set module author
moduleListCache.setAuthor(author);
// set module description
moduleListCache.setDescription(description);
// set module min api
moduleListCache.setMinApi(minApiInt);
// set module max api
moduleListCache.setMaxApi(maxApiInt);
// set module min magisk
moduleListCache.setMinMagisk(minMagiskInt);
// set module need ramdisk
moduleListCache.setNeedRamdisk(needRamdisk);
// set module support
moduleListCache.setSupport(support);
// set module donate
moduleListCache.setDonate(donate);
// set module config
moduleListCache.setConfig(config);
// set module change boot
moduleListCache.setChangeBoot(changeBoot);
// set module mmt reborn
moduleListCache.setMmtReborn(mmtReborn);
// set module repo id
moduleListCache.setRepoId(repoId);
// set module installed
moduleListCache.setInstalled(installed);
// set module installed version code
moduleListCache.setInstalledVersionCode(installedVersionCode);
});
realm.close();
} catch (
JSONException e) {
Exception e) {
e.printStackTrace();
Timber.w("Failed to get module info from module " + module + " in repo " + this.repoData.id + " with error " + e.getMessage());
}

@ -40,6 +40,7 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import io.sentry.android.okhttp.SentryOkHttpInterceptor;
import okhttp3.Cache;
import okhttp3.Cookie;
import okhttp3.CookieJar;
@ -174,6 +175,10 @@ public class Http {
Timber.e(e, "Failed to init cronet");
// Gracefully fallback to okhttp
}
// add sentry interceptor
if (MainApplication.isCrashReportingEnabled()) {
httpclientBuilder.addInterceptor(new SentryOkHttpInterceptor());
}
// Fallback DNS cache responses in case request fail but already succeeded once in the past
fallbackDNS = new FallBackDNS(mainApplication, dns, "github.com", "api.github.com", "raw.githubusercontent.com", "camo.githubusercontent.com", "user-images.githubusercontent.com", "cdn.jsdelivr.net", "img.shields.io", "magisk-modules-repo.github.io", "www.androidacy.com", "api.androidacy.com", "production-api.androidacy.com");
httpclientBuilder.cookieJar(new CDNCookieJar(cookieManager));

@ -15,6 +15,7 @@ import java.util.Objects;
import io.sentry.Sentry;
import io.sentry.android.core.SentryAndroid;
import io.sentry.android.fragment.FragmentLifecycleIntegration;
import io.sentry.android.timber.SentryTimberIntegration;
public class SentryMain {
public static final boolean IS_SENTRY_INSTALLED = true;
@ -43,6 +44,8 @@ public class SentryMain {
intent.putExtra("exception", throwable);
// add stacktrace as string
intent.putExtra("stacktrace", throwable.getStackTrace());
// put lastEventId in intent (get from preferences)
intent.putExtra("lastEventId", String.valueOf(Sentry.getLastEventId()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mainApplication.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
@ -55,6 +58,10 @@ public class SentryMain {
} else {
sentryEnabled = true; // Set sentry state to enabled
options.addIntegration(new FragmentLifecycleIntegration(mainApplication, true, true));
// Enable automatic activity lifecycle breadcrumbs
options.setEnableActivityLifecycleBreadcrumbs(true);
// Enable automatic fragment lifecycle breadcrumbs
options.addIntegration(new SentryTimberIntegration());
options.setCollectAdditionalContext(true);
options.setAttachThreads(true);
options.setAttachStacktrace(true);
@ -84,8 +91,10 @@ public class SentryMain {
// 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 (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));
}

@ -287,7 +287,7 @@
<string name="setup_language_button">Choose language</string>
<string name="title_activity_setup">Setup Wizard</string>
<string name="action_settings">Settings</string>
<string name="repo_update_failed_message">The following repos have failed to update:\\n\\n%s</string>
<string name="repo_update_failed_message">The following repos have failed to update:\n\n%s</string>
<string name="reset_api_key">Reset API keys</string>
<string name="upgrade_androidacy_promo">Upgrade to premium</string>
<string name="upgrade_androidacy_promo_desc">Upgrading to premium will remove ads, captchas, and downloads for the Androidacy Repository, and support Androidacy and the module authors.</string>

@ -4,7 +4,12 @@ buildscript {
google()
mavenCentral()
gradlePluginPortal()
maven { url 'https://jitpack.io' }
maven {
url 'https://jitpack.io'
}
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
project.ext.latestAboutLibsRelease = "10.5.2"
project.ext.sentryConfigFile = new File(rootDir, "sentry.properties").getAbsoluteFile()
@ -22,7 +27,7 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "io.realm:realm-gradle-plugin:10.11.1"
classpath "io.realm:realm-gradle-plugin:10.13.1-transformer-api"
}
}

@ -6,6 +6,9 @@ dependencyResolutionManagement {
maven {
url 'https://jitpack.io'
}
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
}
rootProject.name = "MagiskModuleManager"

Loading…
Cancel
Save