Add ACRA for crash reports

This commit is contained in:
Koitharu
2022-06-20 10:53:58 +03:00
parent 86d8ff3c68
commit d2bbfe01f1
11 changed files with 46 additions and 197 deletions

View File

@@ -112,6 +112,9 @@ dependencies {
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
implementation 'com.github.solkin:disk-lru-cache:1.4'
implementation 'ch.acra:acra-mail:5.9.3'
implementation 'ch.acra:acra-dialog:5.9.3'
debugImplementation 'org.jsoup:jsoup:1.15.1'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'

View File

@@ -68,11 +68,6 @@
android:name="org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="org.koitharu.kotatsu.core.ui.CrashActivity"
android:label="@string/error_occurred"
android:theme="@android:style/Theme.DeviceDefault"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name="org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity"
android:label="@string/favourites_categories"
@@ -86,9 +81,6 @@
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity
android:name="org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity"
android:label="@string/search" />
<activity
android:name="org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity"
android:label="@string/search" />

View File

@@ -1,9 +1,15 @@
package org.koitharu.kotatsu
import android.app.Application
import android.content.Context
import android.os.StrictMode
import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.strictmode.FragmentStrictMode
import org.acra.ReportField
import org.acra.config.dialog
import org.acra.config.mailSender
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import org.koin.android.ext.android.get
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
@@ -13,7 +19,6 @@ import org.koitharu.kotatsu.core.db.databaseModule
import org.koitharu.kotatsu.core.github.githubModule
import org.koitharu.kotatsu.core.network.networkModule
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.AppCrashHandler
import org.koitharu.kotatsu.core.ui.uiModule
import org.koitharu.kotatsu.details.detailsModule
import org.koitharu.kotatsu.favourites.favouritesModule
@@ -41,7 +46,6 @@ class KotatsuApp : Application() {
enableStrictMode()
}
initKoin()
Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext))
AppCompatDelegate.setDefaultNightMode(get<AppSettings>().theme)
registerActivityLifecycleCallbacks(get<AppProtectHelper>())
registerActivityLifecycleCallbacks(get<ActivityRecreationHandle>())
@@ -75,6 +79,36 @@ class KotatsuApp : Application() {
}
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
initAcra {
buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.KEY_VALUE_LIST
reportContent = listOf(
ReportField.PACKAGE_NAME,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.PHONE_MODEL,
ReportField.CRASH_CONFIGURATION,
ReportField.STACK_TRACE,
ReportField.SHARED_PREFERENCES,
)
dialog {
text = getString(R.string.crash_text)
title = getString(R.string.error_occurred)
positiveButtonText = getString(R.string.send)
resIcon = R.drawable.ic_alert_outline
resTheme = android.R.style.Theme_Material_Light_Dialog_Alert
}
mailSender {
mailTo = getString(R.string.email_error_report)
reportAsFile = true
reportFileName = "stacktrace.txt"
}
}
}
private fun enableStrictMode() {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()

View File

@@ -12,7 +12,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.ActionBarContextView
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
@@ -83,8 +82,9 @@ abstract class BaseActivity<B : ViewBinding> :
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_UP) { // TODO remove
ActivityCompat.recreate(this)
return true
// ActivityCompat.recreate(this)
throw RuntimeException("Test crash")
// return true
}
return super.onKeyDown(keyCode, event)
}

View File

@@ -1,22 +0,0 @@
package org.koitharu.kotatsu.core.ui
import android.content.Context
import android.content.Intent
import android.util.Log
import kotlin.system.exitProcess
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
class AppCrashHandler(private val applicationContext: Context) : Thread.UncaughtExceptionHandler {
override fun uncaughtException(t: Thread, e: Throwable) {
val intent = CrashActivity.newIntent(applicationContext, e)
intent.flags = (Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
try {
applicationContext.startActivity(intent)
} catch (t: Throwable) {
t.printStackTraceDebug()
}
Log.e("CRASH", e.message, e)
exitProcess(1)
}
}

View File

@@ -1,83 +0,0 @@
package org.koitharu.kotatsu.core.ui
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.databinding.ActivityCrashBinding
import org.koitharu.kotatsu.main.ui.MainActivity
import org.koitharu.kotatsu.parsers.util.ellipsize
import org.koitharu.kotatsu.utils.ShareHelper
class CrashActivity : Activity(), View.OnClickListener {
private lateinit var binding: ActivityCrashBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCrashBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView.text = intent.getStringExtra(Intent.EXTRA_TEXT)
binding.buttonClose.setOnClickListener(this)
binding.buttonRestart.setOnClickListener(this)
binding.buttonReport.setOnClickListener(this)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.opt_crash, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_share -> {
ShareHelper(this).shareText(binding.textView.text.toString())
}
else -> return super.onOptionsItemSelected(item)
}
return true
}
override fun onClick(v: View) {
when (v.id) {
R.id.button_close -> {
finish()
}
R.id.button_restart -> {
val intent = Intent(applicationContext, MainActivity::class.java)
intent.flags = (Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
R.id.button_report -> {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://github.com/nv95/Kotatsu/issues")
try {
startActivity(Intent.createChooser(intent, getString(R.string.report_github)))
} catch (_: ActivityNotFoundException) {
}
}
}
}
companion object {
private const val MAX_TRACE_SIZE = 131071
fun newIntent(context: Context, error: Throwable): Intent {
val crashInfo = error
.stackTraceToString()
.trimIndent()
.ellipsize(MAX_TRACE_SIZE)
val intent = Intent(context, CrashActivity::class.java)
intent.putExtra(Intent.EXTRA_TEXT, crashInfo)
return intent
}
}
}

View File

@@ -11,8 +11,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import com.google.android.material.R as materialR
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.CrashActivity
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.download.ui.DownloadsActivity
@@ -20,7 +20,6 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.format
import org.koitharu.kotatsu.utils.PendingIntentCompat
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import com.google.android.material.R as materialR
class DownloadNotification(private val context: Context, startId: Int) {
@@ -92,14 +91,6 @@ class DownloadNotification(private val context: Context, startId: Int) {
builder.setContentText(message)
builder.setAutoCancel(true)
builder.setOngoing(false)
builder.setContentIntent(
PendingIntent.getActivity(
context,
state.manga.hashCode(),
CrashActivity.newIntent(context, state.error),
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
)
)
builder.setCategory(NotificationCompat.CATEGORY_ERROR)
builder.setStyle(NotificationCompat.BigTextStyle().bigText(message))
}

View File

@@ -216,10 +216,5 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
works.any { x -> x.state == WorkInfo.State.RUNNING }
}
}
suspend fun getInfo(context: Context): List<WorkInfo> {
val query = WorkQuery.Builder.fromTags(listOf(TAG, TAG_ONESHOT)).build()
return WorkManager.getInstance(context).getWorkInfos(query).await().orEmpty()
}
}
}

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".core.ui.CrashActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:textIsSelectable="true" />
</ScrollView>
<Button
android:id="@+id/button_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="2dp"
android:drawableEnd="@android:drawable/ic_menu_set_as"
android:text="@string/report_github" />
<LinearLayout
style="?buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="@+id/button_close"
style="?buttonBarButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="2dp"
android:layout_marginBottom="4dp"
android:layout_weight="1"
android:text="@string/close" />
<Button
android:id="@+id/button_restart"
style="?buttonBarButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
android:layout_weight="1"
android:text="@string/restart" />
</LinearLayout>
</LinearLayout>

View File

@@ -6,6 +6,7 @@
<string name="url_twitter">https://twitter.com/kotatsuapp</string>
<string name="url_reddit">https://reddit.com/user/kotatsuapp</string>
<string name="url_weblate">https://hosted.weblate.org/engage/kotatsu</string>
<string name="email_error_report">kotatsu@waifu.club</string>
<string-array name="values_theme" translatable="false">
<item>-1</item>
<item>1</item>

View File

@@ -298,4 +298,6 @@
<string name="detect_reader_mode_summary">Automatically detect if manga is webtoon</string>
<string name="disable_battery_optimization">Disable battery optimization</string>
<string name="disable_battery_optimization_summary">Helps with background updates checks</string>
<string name="crash_text">Something went wrong. Please submit a bug report to the developers to help us fix it.</string>
<string name="send">Send</string>
</resources>