cloudstream/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt

221 lines
7.4 KiB
Kotlin
Raw Normal View History

2021-07-26 18:29:04 +00:00
package com.lagradost.cloudstream3
import android.app.Activity
2021-07-26 18:29:04 +00:00
import android.app.Application
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.widget.Toast
2022-08-15 23:24:19 +00:00
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
import com.lagradost.cloudstream3.ui.settings.Globals.TV
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.getKeys
import com.lagradost.cloudstream3.utils.DataStore.removeKey
import com.lagradost.cloudstream3.utils.DataStore.removeKeys
import com.lagradost.cloudstream3.utils.DataStore.setKey
import kotlinx.coroutines.runBlocking
import org.acra.ACRA
2021-07-26 18:29:04 +00:00
import org.acra.ReportField
import org.acra.config.CoreConfiguration
import org.acra.data.CrashReportData
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import org.acra.sender.ReportSender
import org.acra.sender.ReportSenderFactory
import java.io.File
import java.io.FileNotFoundException
import java.io.PrintStream
import java.lang.ref.WeakReference
2021-07-26 18:29:04 +00:00
import kotlin.concurrent.thread
import kotlin.system.exitProcess
2021-07-26 18:29:04 +00:00
class CustomReportSender : ReportSender {
// Sends all your crashes to google forms
override fun send(context: Context, errorContent: CrashReportData) {
println("Sending report")
val url =
2023-08-23 16:43:55 +00:00
"https://docs.google.com/forms/d/e/1FAIpQLSfO4r353BJ79TTY_-t5KWSIJT2xfqcQWY81xjAA1-1N0U2eSg/formResponse"
val data = mapOf(
2023-08-23 16:43:55 +00:00
"entry.1993829403" to errorContent.toJSON()
)
thread { // to not run it on main thread
runBlocking {
suspendSafeApiCall {
2023-07-14 19:43:46 +00:00
app.post(url, data = data)
//println("Report response: $post")
}
2021-07-26 18:29:04 +00:00
}
}
runOnMainThread { // to run it on main looper
normalSafeApiCall {
Toast.makeText(context, R.string.acra_report_toast, Toast.LENGTH_SHORT).show()
}
2021-07-26 18:29:04 +00:00
}
}
}
class CustomSenderFactory : ReportSenderFactory {
override fun create(context: Context, config: CoreConfiguration): ReportSender {
return CustomReportSender()
}
override fun enabled(config: CoreConfiguration): Boolean {
return true
}
}
class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)) :
Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, error: Throwable) {
ACRA.errorReporter.handleException(error)
try {
PrintStream(errorFile).use { ps ->
ps.println(String.format("Currently loading extension: ${PluginManager.currentlyLoading ?: "none"}"))
ps.println(
String.format(
"Fatal exception on thread %s (%d)",
thread.name,
thread.id
)
)
error.printStackTrace(ps)
}
} catch (ignored: FileNotFoundException) {
}
try {
onError.invoke()
} catch (ignored: Exception) {
}
exitProcess(1)
}
}
2021-07-26 18:29:04 +00:00
class AcraApplication : Application() {
2023-08-23 21:57:54 +00:00
override fun onCreate() {
super.onCreate()
2023-08-23 22:25:05 +00:00
//NativeCrashHandler.initCrashHandler()
2023-08-23 21:57:54 +00:00
ExceptionHandler(filesDir.resolve("last_error")) {
val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName)
startActivity(Intent.makeRestartActivityTask(intent!!.component))
2023-08-23 21:57:54 +00:00
}.also {
exceptionHandler = it
Thread.setDefaultUncaughtExceptionHandler(it)
}
}
2021-07-26 18:29:04 +00:00
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
context = base
2021-07-26 18:29:04 +00:00
initAcra {
//core configuration:
buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.JSON
reportContent = listOf(
2021-07-26 18:29:04 +00:00
ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE,
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
ReportField.STACK_TRACE,
2021-07-26 18:29:04 +00:00
)
// removed this due to bug when starting the app, moved it to when it actually crashes
2021-07-26 18:29:04 +00:00
//each plugin you chose above can be configured in a block like this:
/*toast {
2021-07-26 18:29:04 +00:00
text = getString(R.string.acra_report_toast)
//opening this block automatically enables the plugin.
}*/
2021-07-26 18:29:04 +00:00
}
}
companion object {
2023-08-23 21:57:54 +00:00
var exceptionHandler: ExceptionHandler? = null
/** Use to get activity from Context */
tailrec fun Context.getActivity(): Activity? = this as? Activity
?: (this as? ContextWrapper)?.baseContext?.getActivity()
private var _context: WeakReference<Context>? = null
var context
get() = _context?.get()
private set(value) {
_context = WeakReference(value)
}
2023-08-02 03:30:50 +00:00
fun <T : Any> getKeyClass(path: String, valueType: Class<T>): T? {
return context?.getKey(path, valueType)
}
fun <T : Any> setKeyClass(path: String, value: T) {
context?.setKey(path, value)
}
fun removeKeys(folder: String): Int? {
return context?.removeKeys(folder)
}
fun <T> setKey(path: String, value: T) {
context?.setKey(path, value)
}
fun <T> setKey(folder: String, path: String, value: T) {
context?.setKey(folder, path, value)
}
inline fun <reified T : Any> getKey(path: String, defVal: T?): T? {
return context?.getKey(path, defVal)
}
inline fun <reified T : Any> getKey(path: String): T? {
return context?.getKey(path)
}
inline fun <reified T : Any> getKey(folder: String, path: String): T? {
return context?.getKey(folder, path)
}
inline fun <reified T : Any> getKey(folder: String, path: String, defVal: T?): T? {
return context?.getKey(folder, path, defVal)
}
fun getKeys(folder: String): List<String>? {
return context?.getKeys(folder)
}
fun removeKey(folder: String, path: String) {
context?.removeKey(folder, path)
}
fun removeKey(path: String) {
context?.removeKey(path)
}
2022-08-15 23:24:19 +00:00
/**
* If fallbackWebview is true and a fragment is supplied then it will open a webview with the url if the browser fails.
* */
fun openBrowser(url: String, fallbackWebview: Boolean = false, fragment: Fragment? = null) {
context?.openBrowser(url, fallbackWebview, fragment)
}
/** Will fallback to webview if in TV layout */
fun openBrowser(url: String, activity: FragmentActivity?) {
openBrowser(
url,
isLayout(TV or EMULATOR),
activity?.supportFragmentManager?.fragments?.lastOrNull()
)
}
}
}