Enable and disable CrashHandler
Going to "Preferences" the user will be able to enable and disable the CrashHanlder of Husky.
This commit is contained in:
parent
c4a4b26320
commit
5ff66f5ac9
8 changed files with 122 additions and 66 deletions
|
@ -49,9 +49,9 @@
|
|||
<string name="pref_title_composing">Composing</string>
|
||||
<string name="pref_title_composing_title">Composing using zero-width space characters in emojis</string>
|
||||
|
||||
<string name="pref_acra_category">ACRA Settings</string>
|
||||
<string name="pref_acra_body">Enable ACRA reporting</string>
|
||||
<string name="key_enable_acra">acra.enable</string>
|
||||
<string name="pref_crashhandler_category">CrashHanlder Settings</string>
|
||||
<string name="pref_crashhandler_body">Enable CrashHanlder email reporting</string>
|
||||
<string name="pref_crashhandler_key">enableCrashHanlder</string>
|
||||
|
||||
<string name="pref_title_anonymize_upload_filenames">Anonymize uploaded file names</string>
|
||||
<string name="pref_title_hide_live_notification_description">Hide Live Notification username</string>
|
||||
|
|
|
@ -113,7 +113,7 @@ class LoginActivity : BaseActivity(), Injectable {
|
|||
} else {
|
||||
binding.toolbar.visibility = View.GONE
|
||||
}
|
||||
|
||||
val a = 1/0
|
||||
}
|
||||
|
||||
override fun requiresLogin(): Boolean {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/pref_acra_category">
|
||||
<PreferenceCategory android:title="@string/pref_crashhandler_category">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_enable_acra"
|
||||
android:title="@string/pref_acra_body" />
|
||||
android:key="@string/pref_crashhandler_key"
|
||||
android:title="@string/pref_crashhandler_body" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
|
Loading…
Reference in a new issue