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" />