diff --git a/app/build.gradle b/app/build.gradle index 94fb2f7..a2f42dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,8 +83,6 @@ configurations { } dependencies { - // Error reporting - implementation 'io.sentry:sentry-android:6.4.0' // UI implementation 'androidx.appcompat:appcompat:1.5.0' implementation 'androidx.emoji2:emoji2:1.2.0' @@ -100,16 +98,20 @@ 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.0' + implementation 'com.github.Fox2Code:FoxCompat:0.1.2' // Utils implementation 'androidx.work:work-runtime:2.7.1' implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3' implementation 'com.squareup.okhttp3:okhttp-brotli:4.9.3' implementation 'com.github.topjohnwu.libsu:io:5.0.1' - implementation 'com.github.Fox2Code:RosettaX:1.0.8' + implementation 'com.github.Fox2Code:RosettaX:1.0.9' implementation 'com.github.Fox2Code:AndroidANSI:1.0.1' + // Error reporting + implementation 'io.sentry:sentry-android:6.4.0' + implementation 'io.sentry:sentry-android-fragment:6.4.0' + // Markdown implementation "io.noties.markwon:core:4.6.2" implementation "io.noties.markwon:html:4.6.2" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4b5533d..cfe77ad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,23 +74,23 @@ android:parentActivityName=".MainActivity" android:screenOrientation="portrait" tools:ignore="LockedOrientationActivity"> - + + android:theme="@style/Theme.MagiskModuleManager" /> - + = Build.VERSION_CODES.S) { DynamicColors.applyToActivitiesIfAvailable(this, @@ -352,6 +369,7 @@ public class MainApplication extends FoxApplication Log.d("MainApplication", "Emoji compat loaded!"); }, "Emoji compat init.").start(); } + SentryAndroid.init(this, options -> { // Note: Sentry library only take a screenshot of Fox Magisk Module Manager. // The screen shot doesn't and cannot contain other applications (if in multi windows) @@ -361,6 +379,8 @@ public class MainApplication extends FoxApplication // it's a serious bug and a security issue you should report to Google // Google bug bounties on Android are huge, so you can also get rich by doing that. options.setAttachScreenshot(true); + // User interaction tracing is not needed to get context of crash + options.setEnableUserInteractionTracing(false); // 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) -> { @@ -373,6 +393,11 @@ public class MainApplication extends FoxApplication 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); @@ -399,6 +424,10 @@ public class MainApplication extends FoxApplication return event; } else { Log.i(TAG, "Blocked sentry report according to user preference"); + // 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; } }); 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 4761366..2f4d359 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -2,6 +2,7 @@ package com.fox2code.mmm.settings; import android.annotation.SuppressLint; import android.app.AlarmManager; +import android.app.Application; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -32,6 +33,7 @@ import androidx.preference.TwoStatePreference; import com.fox2code.foxcompat.FoxActivity; import com.fox2code.foxcompat.FoxDisplay; import com.fox2code.foxcompat.FoxViewCompat; +import com.fox2code.foxcompat.internal.FoxProcessExt; import com.fox2code.mmm.AppUpdateManager; import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.Constants; @@ -67,6 +69,7 @@ import java.util.Random; public class SettingsActivity extends FoxActivity implements LanguageActivity { private static final int LANGUAGE_SUPPORT_LEVEL = 1; private static final String TAG = "SettingsActivity"; + private static boolean devModeStepFirstBootIgnore = false; private static int devModeStep = 0; @Override @@ -88,7 +91,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { Intent mStartActivity = new Intent(this, MainActivity.class); mStartActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); int mPendingIntentId = 123456; - PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); + PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId, + mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); AlarmManager mgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent); System.exit(0); // Exit app process @@ -115,14 +119,15 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { themePreference.setSummaryProvider(p -> themePreference.getEntry()); themePreference.setOnPreferenceClickListener(p -> { // You need to reboot your device at least once to be able to access dev-mode - if (!MainApplication.isFirstBoot()) devModeStep = 1; + if (devModeStepFirstBootIgnore || !MainApplication.isFirstBoot()) devModeStep = 1; return false; }); themePreference.setOnPreferenceChangeListener((preference, newValue) -> { devModeStep = 0; UiThreadHandler.handler.postDelayed(() -> { MainApplication.getINSTANCE().updateTheme(); - FoxActivity.getFoxActivity(this).setThemeRecreate(MainApplication.getINSTANCE().getManagerThemeResId()); + FoxActivity.getFoxActivity(this).setThemeRecreate( + MainApplication.getINSTANCE().getManagerThemeResId()); }, 1); return true; }); @@ -130,8 +135,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { TwoStatePreference crashReportingPreference = findPreference("pref_crash_reporting"); crashReportingPreference.setChecked(MainApplication.isCrashReportingEnabled()); crashReportingPreference.setOnPreferenceChangeListener((preference, newValue) -> { + devModeStepFirstBootIgnore = true; devModeStep = 0; - getCrashReportingEditor(requireActivity()).putBoolean("crash_reporting", (boolean) newValue).apply(); return true; }); Preference enableBlur = findPreference("pref_enable_blur"); @@ -204,12 +209,14 @@ 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) { // 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 { findPreference("pref_crash").setOnPreferenceClickListener(preference -> { // Hard crash the app - throw new RuntimeException("This is a test crash"); + throw new Error("This is a test crash"); }); } if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND || !MainApplication.isDeveloper()) { @@ -217,12 +224,14 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { } Preference debugNotification = findPreference("pref_background_update_check_debug"); debugNotification.setEnabled(MainApplication.isBackgroundUpdateCheckEnabled()); - debugNotification.setVisible(MainApplication.isDeveloper()); + debugNotification.setVisible(MainApplication.isDeveloper() && !MainApplication.isWrapped()); debugNotification.setOnPreferenceClickListener(preference -> { BackgroundUpdateChecker.postNotification(this.requireContext(), new Random().nextInt(4) + 2); return true; }); - findPreference("pref_background_update_check").setOnPreferenceChangeListener((preference, newValue) -> { + Preference backgroundUpdateCheck = findPreference("pref_background_update_check"); + backgroundUpdateCheck.setVisible(!MainApplication.isWrapped()); + backgroundUpdateCheck.setOnPreferenceChangeListener((preference, newValue) -> { boolean enabled = Boolean.parseBoolean(String.valueOf(newValue)); debugNotification.setEnabled(enabled); if (!enabled) { @@ -276,11 +285,26 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { openFragment(libsBuilder.supportFragment(), R.string.licenses); return true; }); - findPreference("pref_pkg_info").setSummary(BuildConfig.APPLICATION_ID + " v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")"); + findPreference("pref_pkg_info").setSummary(BuildConfig.APPLICATION_ID + + " v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")" + + getRepackageState()); // State may not be "I am just running from myself as myself" } - private SharedPreferences.Editor getCrashReportingEditor(FragmentActivity requireActivity) { - return requireActivity.getSharedPreferences("crash_reporting", Context.MODE_PRIVATE).edit(); + @SuppressLint("RestrictedApi") + private String getRepackageState() { + Application initialApplication = null; + try { + initialApplication = FoxProcessExt.getInitialApplication(); + } catch (Throwable ignored) {} + String realPackageName; + if (initialApplication != null) { + realPackageName = initialApplication.getPackageName(); + } else { + realPackageName = this.requireContext().getPackageName(); + } + if (BuildConfig.APPLICATION_ID.equals(realPackageName)) return ""; + return "\n" + this.getString(FoxProcessExt.isRootLoader() ? + R.string.repackaged_as : R.string.wrapped_from) + realPackageName; } private void openFragment(Fragment fragment, @StringRes int title) { @@ -300,7 +324,9 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { private int currentLanguageLevel() { int declaredLanguageLevel = this.getResources().getInteger(R.integer.language_support_level); if (declaredLanguageLevel != LANGUAGE_SUPPORT_LEVEL) return declaredLanguageLevel; - if (!this.getResources().getConfiguration().locale.getLanguage().equals("en") && this.getResources().getString(R.string.notification_update_pref).equals("Background modules update check") && this.getResources().getString(R.string.notification_update_desc).equals("May increase battery usage")) { + if (!this.getResources().getConfiguration().locale.getLanguage().equals("en") && + this.getResources().getString(R.string.notification_update_pref).equals("Background modules update check") && + this.getResources().getString(R.string.notification_update_desc).equals("May increase battery usage")) { return 0; } return LANGUAGE_SUPPORT_LEVEL; @@ -310,7 +336,6 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { public static class RepoFragment extends PreferenceFragmentCompat { private static final int CUSTOM_REPO_ENTRIES = 5; - @SuppressLint("RestrictedApi") @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { getPreferenceManager().setSharedPreferencesName("mmm"); @@ -319,19 +344,24 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { setRepoData(RepoManager.ANDROIDACY_MAGISK_REPO_ENDPOINT); setRepoData(RepoManager.DG_MAGISK_REPO_GITHUB); updateCustomRepoList(true); + onCreatePreferencesAndroidacy(); + } + + @SuppressLint("RestrictedApi") + public void onCreatePreferencesAndroidacy() { + Preference androidacyTestMode = Objects.requireNonNull(findPreference("pref_androidacy_test_mode")); if (!MainApplication.isDeveloper()) { - Objects.requireNonNull((Preference) findPreference("pref_androidacy_test_mode")).setVisible(false); + androidacyTestMode.setVisible(false); } else { // Show a warning if user tries to enable test mode - Objects.requireNonNull((SwitchPreferenceCompat) findPreference("pref_androidacy_test_mode")).setOnPreferenceChangeListener((preference, newValue) -> { + androidacyTestMode.setOnPreferenceChangeListener((preference, newValue) -> { if (Boolean.parseBoolean(String.valueOf(newValue))) { new AlertDialog.Builder(this.requireContext()) .setTitle(R.string.warning) .setMessage(R.string.androidacy_test_mode_warning) .setPositiveButton(android.R.string.ok, (dialog, which) -> { // Do nothing - }) - .show(); + }).show(); } return true; }); @@ -423,7 +453,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { } Preference preference = findPreference("pref_custom_add_repo"); if (preference == null) return; - preference.setVisible(customRepoManager.canAddRepo() && customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES); + preference.setVisible(customRepoManager.canAddRepo() && + customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES); if (initial) { // Custom repo add button part. preference = findPreference("pref_custom_add_repo_button"); if (preference == null) return; @@ -470,7 +501,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { input.addTextChangedListener(new TextWatcherAdapter() { @Override public void onTextChanged(@NonNull CharSequence charSequence, int i, int i1, int i2) { - positiveButton.setEnabled(customRepoManager.canAddRepo(charSequence.toString()) && customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES); + positiveButton.setEnabled(customRepoManager.canAddRepo(charSequence.toString()) && + customRepoManager.getRepoCount() < CUSTOM_REPO_ENTRIES); } }); positiveButton.setEnabled(false); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b2ba2b6..30de2c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,7 +134,7 @@ Restore modules This operation require an internet connection Androidacy test mode - Use staging Androidacy Endpoint instead of release endpoint. (Require app process restart) + Use staging Androidacy endpoint instead of release endpoint. (Require app process restart) Found %i module updates @@ -168,4 +168,6 @@ Warning! You are setting the app to use a non-production endpoint for Androidacy. This may result in app instability and failure to load the online repo. Do NOT report bugs if you have this switch on. Change will take effect on app restart. Crash the app for testing + Repackaged as: + Wrapped from: