diff --git a/app/build.gradle b/app/build.gradle index eb90f63..47938af 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,6 +79,9 @@ aboutLibraries { } sentry { + // Disable sentry on F-Droid flavor + ignoredFlavors = [ "fdroid" ] + // Disables or enables the handling of Proguard mapping for Sentry. // If enabled the plugin will generate a UUID and will take care of // uploading the mapping to Sentry. If disabled, all the logic @@ -137,7 +140,6 @@ sentry { configurations { implementation.exclude group: 'org.jetbrains', module: 'annotations' - implementation.exclude group: 'io.sentry', module: 'sentry-android-okhttp' } dependencies { @@ -156,7 +158,7 @@ dependencies { implementation "dev.rikka.rikkax.insets:insets:1.3.0" implementation 'com.github.Dimezis:BlurView:version-1.6.6' implementation 'com.github.KieronQuinn:MonetCompat:0.4.1' - implementation 'com.github.Fox2Code:FoxCompat:0.1.4b' + implementation 'com.github.Fox2Code:FoxCompat:0.1.5' // Utils implementation 'androidx.work:work-runtime:2.7.1' @@ -167,11 +169,11 @@ dependencies { implementation 'com.github.Fox2Code:AndroidANSI:1.0.1' // Error reporting - implementation 'io.sentry:sentry-android:6.4.1' - implementation 'io.sentry:sentry-android-fragment:6.4.1' - implementation 'io.sentry:sentry-android-okhttp:6.4.1' - implementation 'io.sentry:sentry-android-core:6.4.1' - implementation 'io.sentry:sentry-android-ndk:6.4.1' + defaultImplementation 'io.sentry:sentry-android:6.4.1' + defaultImplementation 'io.sentry:sentry-android-fragment:6.4.1' + defaultImplementation 'io.sentry:sentry-android-okhttp:6.4.1' + defaultImplementation 'io.sentry:sentry-android-core:6.4.1' + defaultImplementation 'io.sentry:sentry-android-ndk:6.4.1' // Markdown implementation "io.noties.markwon:core:4.6.2" diff --git a/app/src/default/AndroidManifest.xml b/app/src/default/AndroidManifest.xml new file mode 100644 index 0000000..e764f3f --- /dev/null +++ b/app/src/default/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/default/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java b/app/src/default/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java new file mode 100644 index 0000000..5684172 --- /dev/null +++ b/app/src/default/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java @@ -0,0 +1,32 @@ +package com.fox2code.mmm.sentry; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import io.sentry.Breadcrumb; +import io.sentry.SentryLevel; + +public class SentryBreadcrumb { + final Breadcrumb breadcrumb; + + public SentryBreadcrumb() { + breadcrumb = new Breadcrumb(); + breadcrumb.setLevel(SentryLevel.INFO); + } + + public void setType(@Nullable String type) { + breadcrumb.setType(type); + } + + public void setData(@NotNull String key, @NotNull Object value) { + Objects.requireNonNull(key); + Objects.requireNonNull(value); + breadcrumb.setData(key, value); + } + + public void setCategory(@Nullable String category) { + breadcrumb.setCategory(category); + } +} diff --git a/app/src/default/java/com/fox2code/mmm/sentry/SentryMain.java b/app/src/default/java/com/fox2code/mmm/sentry/SentryMain.java new file mode 100644 index 0000000..a48becf --- /dev/null +++ b/app/src/default/java/com/fox2code/mmm/sentry/SentryMain.java @@ -0,0 +1,97 @@ +package com.fox2code.mmm.sentry; + +import android.util.Log; + +import com.fox2code.mmm.BuildConfig; +import com.fox2code.mmm.MainApplication; + +import java.io.IOException; +import java.io.Writer; + +import io.sentry.JsonObjectWriter; +import io.sentry.NoOpLogger; +import io.sentry.Sentry; +import io.sentry.TypeCheckHint; +import io.sentry.android.core.SentryAndroid; +import io.sentry.android.fragment.FragmentLifecycleIntegration; +import io.sentry.hints.DiskFlushNotification; + +public class SentryMain { + public static final boolean IS_SENTRY_INSTALLED = true; + private static final String TAG = "SentryMain"; + + public static void initialize(final MainApplication mainApplication) { + SentryAndroid.init(mainApplication, options -> { + // If crash reporting is disabled, stop here. + if (!MainApplication.isCrashReportingEnabled()) { + options.setDsn(""); + } else { + options.addIntegration(new FragmentLifecycleIntegration(mainApplication, true, true)); + // 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. + options.setSendDefaultPii(false); + // It just tell if sentry should ping the sentry dsn to tell the app is running. + // This is not needed at all for crash reporting purposes, so disable it. + options.setEnableAutoSessionTracking(false); + // A screenshot of the app itself is only sent if the app crashes, and it only shows the last activity + // In addition, sentry is configured with a trusted third party other than sentry.io, and only trusted people have access to the sentry instance + // Add a callback that will be used before the event is sent to Sentry. + // With this callback, you can modify the event or, when returning null, also discard the event. + options.setBeforeSend((event, hint) -> { + if (BuildConfig.DEBUG) { // Debug sentry events for debug. + StringBuilder stringBuilder = new StringBuilder("Sentry report debug: "); + try { + event.serialize(new JsonObjectWriter(new Writer() { + @Override + public void write(char[] cbuf) { + stringBuilder.append(cbuf); + } + + @Override + public void write(String str) { + stringBuilder.append(str); + } + + @Override + public void write(char[] chars, int i, int i1) { + stringBuilder.append(chars, i, i1); + } + + @Override + public void write(String str, int off, int len) { + stringBuilder.append(str, off, len); + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + }, 4), NoOpLogger.getInstance()); + } catch (IOException ignored) { + } + Log.i(TAG, stringBuilder.toString()); + } + if (MainApplication.isCrashReportingEnabled()) { + return event; + } else { + // We need to do this to avoid crash delay on crash when the event is dropped + DiskFlushNotification diskFlushNotification = hint.getAs( + TypeCheckHint.SENTRY_TYPE_CHECK_HINT, DiskFlushNotification.class); + if (diskFlushNotification != null) diskFlushNotification.markFlushed(); + return null; + } + }); + } + + }); + } + + public static void addSentryBreadcrumb(SentryBreadcrumb sentryBreadcrumb) { + if (MainApplication.isCrashReportingEnabled()) { + Sentry.addBreadcrumb(sentryBreadcrumb.breadcrumb); + } + } +} diff --git a/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java b/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java new file mode 100644 index 0000000..a1cb9f4 --- /dev/null +++ b/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryBreadcrumb.java @@ -0,0 +1,19 @@ +package com.fox2code.mmm.sentry; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class SentryBreadcrumb { + public SentryBreadcrumb() {} + + public void setType(@Nullable String type) {} + + public void setData(@NotNull String key, @NotNull Object value) { + Objects.requireNonNull(key); + Objects.requireNonNull(value); + } + + public void setCategory(@Nullable String category) {} +} diff --git a/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryMain.java b/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryMain.java new file mode 100644 index 0000000..7d3e354 --- /dev/null +++ b/app/src/fdroid/java/com/fox2code/mmm/sentry/SentryMain.java @@ -0,0 +1,11 @@ +package com.fox2code.mmm.sentry; + +import com.fox2code.mmm.MainApplication; + +public class SentryMain { + public static final boolean IS_SENTRY_INSTALLED = false; + + public static void initialize(MainApplication mainApplication) {} + + public static void addSentryBreadcrumb(SentryBreadcrumb sentryBreadcrumb) {} +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2c17148..9eae912 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,9 +10,7 @@ - + @@ -113,21 +111,5 @@ android:name="androidx.work.WorkManagerInitializer" tools:node="remove" /> - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index 31164d8..b01e477 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -23,6 +23,7 @@ import com.fox2code.foxcompat.FoxApplication; import com.fox2code.foxcompat.FoxThemeWrapper; import com.fox2code.foxcompat.internal.FoxProcessExt; import com.fox2code.mmm.installer.InstallerInitializer; +import com.fox2code.mmm.sentry.SentryMain; import com.fox2code.mmm.utils.GMSProviderInstaller; import com.fox2code.mmm.utils.Http; import com.fox2code.rosettax.LanguageSwitcher; @@ -366,60 +367,7 @@ public class MainApplication extends FoxApplication }, "Emoji compat init.").start(); } - SentryAndroid.init(this, options -> { - // If crash reporting is disabled, stop here. - if (!isCrashReportingEnabled()) { - options.setDsn(""); - } else { - options.addIntegration(new FragmentLifecycleIntegration(this, true, true)); - // Sentry sends ABSOLUTELY NO Personally Identifiable Information (PII) by default. - // A screenshot of the app itself is only sent if the app crashes, and it only shows the last activity - // In addition, sentry is configured with a trusted third party other than sentry.io, and only trusted people have access to the sentry instance - // Add a callback that will be used before the event is sent to Sentry. - // With this callback, you can modify the event or, when returning null, also discard the event. - options.setBeforeSend((event, hint) -> { - if (BuildConfig.DEBUG) { // Debug sentry events for debug. - StringBuilder stringBuilder = new StringBuilder("Sentry report debug: "); - try { - event.serialize(new JsonObjectWriter(new Writer() { - @Override - public void write(char[] cbuf) { - stringBuilder.append(cbuf); - } - - @Override - public void write(String str) { - stringBuilder.append(str); - } - - @Override - public void write(char[] chars, int i, int i1) { - stringBuilder.append(chars, i, i1); - } - - @Override - public void write(String str, int off, int len) { - stringBuilder.append(str, off, len); - } - - @Override - public void flush() { - } - - @Override - public void close() { - } - }, 4), NoOpLogger.getInstance()); - } catch (IOException ignored) { - } - Log.i(TAG, stringBuilder.toString()); - } - // We already know that the user has opted in to crash reporting, so we don't need to ask again. - return event; - }); - } - - }); + SentryMain.initialize(this); } @Override diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java index c35a30c..278dbe8 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java @@ -24,6 +24,8 @@ import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.R; import com.fox2code.mmm.XHooks; import com.fox2code.mmm.module.ActionButtonType; +import com.fox2code.mmm.sentry.SentryBreadcrumb; +import com.fox2code.mmm.sentry.SentryMain; import com.fox2code.mmm.utils.FastException; import com.fox2code.mmm.utils.Files; import com.fox2code.mmm.utils.Hashes; @@ -50,10 +52,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; -import io.sentry.Breadcrumb; -import io.sentry.Sentry; -import io.sentry.SentryLevel; - public class InstallerActivity extends FoxActivity { private static final String TAG = "InstallerActivity"; public LinearProgressIndicator progressIndicator; @@ -109,14 +107,13 @@ public class InstallerActivity extends FoxActivity { Log.i(TAG, "Install link: " + target); // Note: Sentry only send this info on crash. if (MainApplication.isCrashReportingEnabled()) { - Breadcrumb breadcrumb = new Breadcrumb(); + SentryBreadcrumb breadcrumb = new SentryBreadcrumb(); breadcrumb.setType("install"); breadcrumb.setData("target", target); breadcrumb.setData("name", name); breadcrumb.setData("checksum", checksum); breadcrumb.setCategory("app.action.preinstall"); - breadcrumb.setLevel(SentryLevel.INFO); - Sentry.addBreadcrumb(breadcrumb); + SentryMain.addSentryBreadcrumb(breadcrumb); } boolean urlMode = target.startsWith("http://") || target.startsWith("https://"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); @@ -450,7 +447,7 @@ public class InstallerActivity extends FoxActivity { } // Note: Sentry only send this info on crash. if (MainApplication.isCrashReportingEnabled()) { - Breadcrumb breadcrumb = new Breadcrumb(); + SentryBreadcrumb breadcrumb = new SentryBreadcrumb(); breadcrumb.setType("install"); breadcrumb.setData("moduleId", moduleId == null ? "" : moduleId); breadcrumb.setData("mmtReborn", mmtReborn ? "true" : "false"); @@ -460,8 +457,7 @@ public class InstallerActivity extends FoxActivity { breadcrumb.setData("ansi", this.installerTerminal .isAnsiEnabled() ? "enabled" : "disabled"); breadcrumb.setCategory("app.action.install"); - breadcrumb.setLevel(SentryLevel.INFO); - Sentry.addBreadcrumb(breadcrumb); + SentryMain.addSentryBreadcrumb(breadcrumb); } if (mmtReborn && magiskCmdLine) { Log.w(TAG, "mmtReborn and magiskCmdLine may not work well together"); diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index ffe42a5..2dbad9f 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -47,6 +47,7 @@ import com.fox2code.mmm.repo.CustomRepoData; import com.fox2code.mmm.repo.CustomRepoManager; import com.fox2code.mmm.repo.RepoData; import com.fox2code.mmm.repo.RepoManager; +import com.fox2code.mmm.sentry.SentryMain; import com.fox2code.mmm.utils.ExternalHelper; import com.fox2code.mmm.utils.Http; import com.fox2code.mmm.utils.IntentHelper; @@ -134,13 +135,13 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { }); // Crash reporting TwoStatePreference crashReportingPreference = findPreference("pref_crash_reporting"); + if (!SentryMain.IS_SENTRY_INSTALLED) crashReportingPreference.setVisible(false); crashReportingPreference.setChecked(MainApplication.isCrashReportingEnabled()); + final Object initialValue = MainApplication.isCrashReportingEnabled(); crashReportingPreference.setOnPreferenceChangeListener((preference, newValue) -> { devModeStepFirstBootIgnore = true; devModeStep = 0; - // Save the new value and restart the app - MainApplication.getSharedPreferences().edit() - .putBoolean("crash_reporting", (boolean) newValue).apply(); + if (initialValue == newValue) return true; // Show a dialog to restart the app MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(requireContext()); materialAlertDialogBuilder.setTitle(R.string.crash_reporting_restart_title); @@ -165,12 +166,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { } System.exit(0); // Exit app process }); - // Reverse the change if the user cancels the dialog - materialAlertDialogBuilder.setNegativeButton(R.string.cancel, (dialog, which) -> { - crashReportingPreference.setChecked(!crashReportingPreference.isChecked()); - MainApplication.getSharedPreferences().edit() - .putBoolean("crash_reporting", crashReportingPreference.isChecked()).apply(); - }); + // Do not reverse the change if the user cancels the dialog + materialAlertDialogBuilder.setNegativeButton(R.string.no, (dialog, which) -> {}); materialAlertDialogBuilder.show(); return true; }); @@ -245,7 +242,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { if (!MainApplication.isDeveloper()) { findPreference("pref_disable_low_quality_module_filter").setVisible(false); } - if (!BuildConfig.DEBUG || InstallerInitializer.peekMagiskPath() == null) { + if (!SentryMain.IS_SENTRY_INSTALLED || !BuildConfig.DEBUG || + InstallerInitializer.peekMagiskPath() == null) { // Hide the pref_crash option if not in debug mode - stop users from purposely crashing the app Objects.requireNonNull((Preference) findPreference("pref_crash")).setVisible(false); } else { diff --git a/build.gradle b/build.gradle index 7fce4ea..e38dbc8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,10 +5,10 @@ buildscript { mavenCentral() gradlePluginPortal() } - project.ext.latestAboutLibsRelease = "10.4.1-a01" - project.ext.blockSentry = false // TODO: Make this block Sentry from even being added to the project + project.ext.latestAboutLibsRelease = "10.5.0" + project.ext.hasSentryConfig = false dependencies { - classpath 'com.android.tools.build:gradle:7.2.2' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${latestAboutLibsRelease}" // NOTE: Do not place your application dependencies here; they belong