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.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
implementation 'com.github.solkin:disk-lru-cache:1.4' 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 'org.jsoup:jsoup:1.15.1'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.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:name="org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:windowSoftInputMode="adjustResize" /> 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 <activity
android:name="org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity" android:name="org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity"
android:label="@string/favourites_categories" android:label="@string/favourites_categories"
@@ -86,9 +81,6 @@
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name="org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity"
android:label="@string/search" />
<activity <activity
android:name="org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity" android:name="org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity"
android:label="@string/search" /> android:label="@string/search" />

View File

@@ -1,9 +1,15 @@
package org.koitharu.kotatsu package org.koitharu.kotatsu
import android.app.Application import android.app.Application
import android.content.Context
import android.os.StrictMode import android.os.StrictMode
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.strictmode.FragmentStrictMode 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.android.get
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin 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.github.githubModule
import org.koitharu.kotatsu.core.network.networkModule import org.koitharu.kotatsu.core.network.networkModule
import org.koitharu.kotatsu.core.prefs.AppSettings 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.core.ui.uiModule
import org.koitharu.kotatsu.details.detailsModule import org.koitharu.kotatsu.details.detailsModule
import org.koitharu.kotatsu.favourites.favouritesModule import org.koitharu.kotatsu.favourites.favouritesModule
@@ -41,7 +46,6 @@ class KotatsuApp : Application() {
enableStrictMode() enableStrictMode()
} }
initKoin() initKoin()
Thread.setDefaultUncaughtExceptionHandler(AppCrashHandler(applicationContext))
AppCompatDelegate.setDefaultNightMode(get<AppSettings>().theme) AppCompatDelegate.setDefaultNightMode(get<AppSettings>().theme)
registerActivityLifecycleCallbacks(get<AppProtectHelper>()) registerActivityLifecycleCallbacks(get<AppProtectHelper>())
registerActivityLifecycleCallbacks(get<ActivityRecreationHandle>()) 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() { private fun enableStrictMode() {
StrictMode.setThreadPolicy( StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder() StrictMode.ThreadPolicy.Builder()

View File

@@ -12,7 +12,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.ActionBarContextView import androidx.appcompat.widget.ActionBarContextView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@@ -83,8 +82,9 @@ abstract class BaseActivity<B : ViewBinding> :
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_UP) { // TODO remove if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_UP) { // TODO remove
ActivityCompat.recreate(this) // ActivityCompat.recreate(this)
return true throw RuntimeException("Test crash")
// return true
} }
return super.onKeyDown(keyCode, event) 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.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import com.google.android.material.R as materialR
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.CrashActivity
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.domain.DownloadState import org.koitharu.kotatsu.download.domain.DownloadState
import org.koitharu.kotatsu.download.ui.DownloadsActivity 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.parsers.util.format
import org.koitharu.kotatsu.utils.PendingIntentCompat import org.koitharu.kotatsu.utils.PendingIntentCompat
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import com.google.android.material.R as materialR
class DownloadNotification(private val context: Context, startId: Int) { class DownloadNotification(private val context: Context, startId: Int) {
@@ -92,14 +91,6 @@ class DownloadNotification(private val context: Context, startId: Int) {
builder.setContentText(message) builder.setContentText(message)
builder.setAutoCancel(true) builder.setAutoCancel(true)
builder.setOngoing(false) 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.setCategory(NotificationCompat.CATEGORY_ERROR)
builder.setStyle(NotificationCompat.BigTextStyle().bigText(message)) 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 } 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_twitter">https://twitter.com/kotatsuapp</string>
<string name="url_reddit">https://reddit.com/user/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="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"> <string-array name="values_theme" translatable="false">
<item>-1</item> <item>-1</item>
<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="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">Disable battery optimization</string>
<string name="disable_battery_optimization_summary">Helps with background updates checks</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> </resources>