From 5ff66f5ac9393988b247c830dcd563ee8b4ceb6a Mon Sep 17 00:00:00 2001 From: Adolfo Santiago Date: Sat, 25 Jun 2022 10:00:18 +0200 Subject: [PATCH] Enable and disable CrashHandler Going to "Preferences" the user will be able to enable and disable the CrashHanlder of Husky. --- husky/app/src/husky/res/values/strings.xml | 6 +- .../com/keylesspalace/tusky/LoginActivity.kt | 2 +- .../keylesspalace/tusky/TuskyApplication.kt | 12 ++- .../preference/PreferencesFragment.kt | 26 ++++-- .../tusky/core/logging/CrashHandler.kt | 82 +++++++++++-------- .../com/keylesspalace/tusky/di/AppModule.kt | 52 +++++++++--- .../tusky/settings/SettingsConstants.kt | 2 + .../app/src/main/res/xml/app_preferences.xml | 6 +- 8 files changed, 122 insertions(+), 66 deletions(-) diff --git a/husky/app/src/husky/res/values/strings.xml b/husky/app/src/husky/res/values/strings.xml index ffbaa3f..8051e13 100644 --- a/husky/app/src/husky/res/values/strings.xml +++ b/husky/app/src/husky/res/values/strings.xml @@ -49,9 +49,9 @@ Composing Composing using zero-width space characters in emojis - ACRA Settings - Enable ACRA reporting - acra.enable + CrashHanlder Settings + Enable CrashHanlder email reporting + enableCrashHanlder Anonymize uploaded file names Hide Live Notification username diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt b/husky/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt index 5ba8c48..f6a8f2f 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt @@ -113,7 +113,7 @@ class LoginActivity : BaseActivity(), Injectable { } else { binding.toolbar.visibility = View.GONE } - +val a = 1/0 } override fun requiresLogin(): Boolean { diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt b/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt index c8f1fe0..8497f7b 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -56,12 +56,19 @@ class TuskyApplication : Application(), HasAndroidInjector { @Inject lateinit var notificationWorkerFactory: NotificationWorkerFactory + @Inject + protected lateinit var crashHandler: CrashHandler + override fun onCreate() { super.onCreate() + AppInjector.init(this) + val preferences = PreferenceManager.getDefaultSharedPreferences(this) - CrashHandler.setAsDefaultHandler(this) + if(preferences.getBoolean(PrefKeys.CRASH_HANDLER_ENABLE, false)) { + crashHandler.setAsDefaultHandler() + } if(ApplicationUtils.isDebug()) { Timber.plant(HyperlinkDebugTree()) @@ -71,9 +78,6 @@ class TuskyApplication : Application(), HasAndroidInjector { AutoDisposePlugins.setHideProxies(false) // a small performance optimization - AppInjector.init(this) - - // init the custom emoji fonts val emojiSelection = preferences.getInt(PrefKeys.EMOJI, 0) val emojiConfig = EmojiCompatFont.byId(emojiSelection) diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt b/husky/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt index 676814a..fe4b812 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt @@ -27,11 +27,10 @@ import androidx.preference.PreferenceFragmentCompat import com.keylesspalace.tusky.R import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.PreferenceChangedEvent -import com.keylesspalace.tusky.components.notifications.NotificationHelper +import com.keylesspalace.tusky.core.logging.CrashHandler import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.entity.Notification -import com.keylesspalace.tusky.service.StreamingService import com.keylesspalace.tusky.settings.AppTheme import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.settings.emojiPreference @@ -62,6 +61,9 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable { @Inject lateinit var eventHub: EventHub + @Inject + lateinit var crashHandler: CrashHandler + private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) } private var httpProxyPref: Preference? = null @@ -362,15 +364,25 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable { } } - /* - preferenceCategory(R.string.pref_acra_category) { + preferenceCategory(R.string.pref_crashhandler_category) { switchPreference { setDefaultValue(false) - key = PREF_ENABLE_ACRA - setTitle(R.string.pref_acra_body) + key = PrefKeys.CRASH_HANDLER_ENABLE + setTitle(R.string.pref_crashhandler_body) isSingleLineTitle = false + setOnPreferenceChangeListener { _, value -> + with(value as Boolean) { + if(this) { + crashHandler.setAsDefaultHandler() + } else { + crashHandler.removeDefaultHandler() + } + } + + true + } } - }*/ + } } } diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/core/logging/CrashHandler.kt b/husky/app/src/main/java/com/keylesspalace/tusky/core/logging/CrashHandler.kt index 8b6315a..3ae88ea 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/core/logging/CrashHandler.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/core/logging/CrashHandler.kt @@ -32,44 +32,33 @@ import com.keylesspalace.tusky.core.ui.callbacks.ActivityCallback import java.io.File import java.io.FileOutputStream import java.io.IOException +import java.lang.Thread.UncaughtExceptionHandler +import javax.inject.Inject import timber.log.Timber -class CrashHandler( - private val defaultHandler: Thread.UncaughtExceptionHandler, +class CrashHandler @Inject constructor( private val huskyApp: Application -) : Thread.UncaughtExceptionHandler { +) : UncaughtExceptionHandler { - private var lastActivity: Activity? = null + private val activityCallbacks = object : ActivityCallback() { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + lastActivity = activity + Timber.d("onActivityCreated[${activity::class.simpleName}]") + } - companion object { - fun setAsDefaultHandler(application: Application) { - val handler = Thread.getDefaultUncaughtExceptionHandler()?.let { - CrashHandler(it, application) - } - Thread.setDefaultUncaughtExceptionHandler(handler) + override fun onActivityResumed(activity: Activity) { + lastActivity = activity + Timber.d("onActivityResumed[${activity::class.simpleName}]") + } + + override fun onActivityStopped(activity: Activity) { + lastActivity = null + Timber.d("onActivityStopped[${activity::class.simpleName}]") } } - init { - huskyApp.registerActivityLifecycleCallbacks( - object : ActivityCallback() { - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - lastActivity = activity - Timber.d("onActivityCreated[${activity::class.simpleName}]") - } - - override fun onActivityResumed(activity: Activity) { - lastActivity = activity - Timber.d("onActivityResumed[${activity::class.simpleName}]") - } - - override fun onActivityStopped(activity: Activity) { - lastActivity = null - Timber.d("onActivityStopped[${activity::class.simpleName}]") - } - } - ) - } + private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler() + private var lastActivity: Activity? = null override fun uncaughtException(thread: Thread, throwable: Throwable) { try { @@ -77,7 +66,7 @@ class CrashHandler( } catch(e: IOException) { Timber.e("CrashHandler Exception[${e.message}]") } finally { - lastActivity?.finish() + lastActivity?.finish() ?: defaultHandler?.uncaughtException(thread, throwable) } } @@ -104,14 +93,17 @@ class CrashHandler( .appendLine() .appendLine("## Device details") .appendLine(getDeviceInfo()) - //.appendLine("## Crash details") - //.appendLine(stacktrace) + //.appendLine("## Crash details") + //.appendLine(stacktrace) }.toString() Timber.d(formattedLog) val intent = Intent(Intent.ACTION_SEND).apply { type = "message/rfc822" - putExtra(Intent.EXTRA_EMAIL, arrayOf(activity.getString(R.string.crashhandler_email))) + putExtra( + Intent.EXTRA_EMAIL, + arrayOf(activity.getString(R.string.crashhandler_email)) + ) putExtra(Intent.EXTRA_SUBJECT, "Husky ${BuildConfig.VERSION_NAME} crash") putExtra(Intent.EXTRA_TEXT, formattedLog) putExtra(Intent.EXTRA_STREAM, getCrashFileUri(activity, stacktrace)) @@ -129,7 +121,10 @@ class CrashHandler( } private fun getCrashFileUri(activity: Activity, stacktrace: String): Uri { - val file = File("${huskyApp.cacheDir}/crashes", activity.getString(R.string.crashhandler_email_report_filename)) + val file = File( + "${huskyApp.cacheDir}/crashes", + activity.getString(R.string.crashhandler_email_report_filename) + ) FileOutputStream(file).apply { write(stacktrace.toByteArray()) }.also { @@ -141,4 +136,21 @@ class CrashHandler( file ) } + + fun setAsDefaultHandler() { + val handler = defaultHandler?.let { + this@CrashHandler + } + Thread.setDefaultUncaughtExceptionHandler(handler) + huskyApp.registerActivityLifecycleCallbacks(activityCallbacks) + + Timber.d("Set default handler[${handler}]") + } + + fun removeDefaultHandler() { + Thread.setDefaultUncaughtExceptionHandler(defaultHandler) + huskyApp.unregisterActivityLifecycleCallbacks(activityCallbacks) + + Timber.d("Remove default handler") + } } diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/husky/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt index db1317e..4c7ef93 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt @@ -27,6 +27,7 @@ import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHubImpl import com.keylesspalace.tusky.components.notifications.Notifier import com.keylesspalace.tusky.components.notifications.SystemNotifier +import com.keylesspalace.tusky.core.logging.CrashHandler import com.keylesspalace.tusky.db.AppDatabase import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.TimelineCases @@ -59,8 +60,10 @@ class AppModule { } @Provides - fun providesTimelineUseCases(api: MastodonApi, - eventHub: EventHub): TimelineCases { + fun providesTimelineUseCases( + api: MastodonApi, + eventHub: EventHub + ): TimelineCases { return TimelineCasesImpl(api, eventHub) } @@ -72,20 +75,43 @@ class AppModule { @Singleton fun providesDatabase(appContext: Context): AppDatabase { return Room.databaseBuilder(appContext, AppDatabase::class.java, "tuskyDB") - .allowMainThreadQueries() - .addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, - AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8, - AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10, AppDatabase.MIGRATION_10_11, - AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13, - AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16, - AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19, - AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21, AppDatabase.MIGRATION_21_22, - AppDatabase.MIGRATION_22_23, AppDatabase.MIGRATION_23_24, AppDatabase.MIGRATION_24_25, - AppDatabase.MIGRATION_25_26, AppDatabase.MIGRATION_26_27) - .build() + .allowMainThreadQueries() + .addMigrations( + AppDatabase.MIGRATION_2_3, + AppDatabase.MIGRATION_3_4, + AppDatabase.MIGRATION_4_5, + AppDatabase.MIGRATION_5_6, + AppDatabase.MIGRATION_6_7, + AppDatabase.MIGRATION_7_8, + AppDatabase.MIGRATION_8_9, + AppDatabase.MIGRATION_9_10, + AppDatabase.MIGRATION_10_11, + AppDatabase.MIGRATION_11_12, + AppDatabase.MIGRATION_12_13, + AppDatabase.MIGRATION_10_13, + AppDatabase.MIGRATION_13_14, + AppDatabase.MIGRATION_14_15, + AppDatabase.MIGRATION_15_16, + AppDatabase.MIGRATION_16_17, + AppDatabase.MIGRATION_17_18, + AppDatabase.MIGRATION_18_19, + AppDatabase.MIGRATION_19_20, + AppDatabase.MIGRATION_20_21, + AppDatabase.MIGRATION_21_22, + AppDatabase.MIGRATION_22_23, + AppDatabase.MIGRATION_23_24, + AppDatabase.MIGRATION_24_25, + AppDatabase.MIGRATION_25_26, + AppDatabase.MIGRATION_26_27 + ) + .build() } @Provides @Singleton fun notifier(context: Context): Notifier = SystemNotifier(context) + + @Provides + @Singleton + fun crashHandler(app: Application) = CrashHandler(app) } diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/settings/SettingsConstants.kt b/husky/app/src/main/java/com/keylesspalace/tusky/settings/SettingsConstants.kt index 5d7d307..4721f67 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/settings/SettingsConstants.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/settings/SettingsConstants.kt @@ -93,4 +93,6 @@ object PrefKeys { const val TAB_FILTER_HOME_REPLIES = "tabFilterHomeReplies" const val TAB_FILTER_HOME_BOOSTS = "tabFilterHomeBoosts" + + const val CRASH_HANDLER_ENABLE = "enableCrashHanlder" } diff --git a/husky/app/src/main/res/xml/app_preferences.xml b/husky/app/src/main/res/xml/app_preferences.xml index 8e0dac1..0649729 100644 --- a/husky/app/src/main/res/xml/app_preferences.xml +++ b/husky/app/src/main/res/xml/app_preferences.xml @@ -10,12 +10,12 @@ - + + android:key="@string/pref_crashhandler_key" + android:title="@string/pref_crashhandler_body" />