2021-07-26 18:29:04 +00:00
|
|
|
package com.lagradost.cloudstream3
|
|
|
|
|
2022-08-17 16:14:36 +00:00
|
|
|
import android.app.Activity
|
2021-07-26 18:29:04 +00:00
|
|
|
import android.app.Application
|
|
|
|
import android.content.Context
|
2022-08-17 16:14:36 +00:00
|
|
|
import android.content.ContextWrapper
|
2022-09-01 12:13:54 +00:00
|
|
|
import android.content.Intent
|
2021-07-30 01:14:53 +00:00
|
|
|
import android.widget.Toast
|
2022-08-15 23:24:19 +00:00
|
|
|
import androidx.fragment.app.Fragment
|
2022-09-17 11:03:41 +00:00
|
|
|
import androidx.fragment.app.FragmentActivity
|
2021-07-30 01:14:53 +00:00
|
|
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
2022-01-29 21:25:12 +00:00
|
|
|
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
2022-09-01 12:13:54 +00:00
|
|
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
2024-03-17 02:37:09 +00:00
|
|
|
import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR
|
|
|
|
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
|
|
|
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
2021-12-16 23:45:20 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
2021-07-30 01:14:53 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
2021-12-16 23:45:20 +00:00
|
|
|
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
|
2022-01-29 21:25:12 +00:00
|
|
|
import kotlinx.coroutines.runBlocking
|
2022-09-01 12:13:54 +00:00
|
|
|
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
|
2022-09-01 12:13:54 +00:00
|
|
|
import java.io.File
|
|
|
|
import java.io.FileNotFoundException
|
|
|
|
import java.io.PrintStream
|
2021-10-04 17:54:15 +00:00
|
|
|
import java.lang.ref.WeakReference
|
2021-07-26 18:29:04 +00:00
|
|
|
import kotlin.concurrent.thread
|
2022-09-01 12:13:54 +00:00
|
|
|
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) {
|
2021-07-30 01:14:53 +00:00
|
|
|
println("Sending report")
|
|
|
|
val url =
|
2023-08-23 16:43:55 +00:00
|
|
|
"https://docs.google.com/forms/d/e/1FAIpQLSfO4r353BJ79TTY_-t5KWSIJT2xfqcQWY81xjAA1-1N0U2eSg/formResponse"
|
2021-07-30 01:14:53 +00:00
|
|
|
val data = mapOf(
|
2023-08-23 16:43:55 +00:00
|
|
|
"entry.1993829403" to errorContent.toJSON()
|
2021-07-30 01:14:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
thread { // to not run it on main thread
|
2022-01-29 21:25:12 +00:00
|
|
|
runBlocking {
|
|
|
|
suspendSafeApiCall {
|
2023-07-14 19:43:46 +00:00
|
|
|
app.post(url, data = data)
|
|
|
|
//println("Report response: $post")
|
2022-01-29 21:25:12 +00:00
|
|
|
}
|
2021-07-26 18:29:04 +00:00
|
|
|
}
|
2021-07-30 01:14:53 +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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-17 11:03:41 +00:00
|
|
|
class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)) :
|
|
|
|
Thread.UncaughtExceptionHandler {
|
2022-09-01 12:13:54 +00:00
|
|
|
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"}"))
|
2022-09-17 11:03:41 +00:00
|
|
|
ps.println(
|
|
|
|
String.format(
|
|
|
|
"Fatal exception on thread %s (%d)",
|
|
|
|
thread.name,
|
|
|
|
thread.id
|
|
|
|
)
|
|
|
|
)
|
2022-09-01 12:13:54 +00:00
|
|
|
error.printStackTrace(ps)
|
|
|
|
}
|
2022-09-17 11:03:41 +00:00
|
|
|
} catch (ignored: FileNotFoundException) {
|
|
|
|
}
|
2022-09-01 12:13:54 +00:00
|
|
|
try {
|
|
|
|
onError.invoke()
|
2022-09-17 11:03:41 +00:00
|
|
|
} catch (ignored: Exception) {
|
|
|
|
}
|
2022-09-01 12:13:54 +00:00
|
|
|
exitProcess(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-07-26 18:29:04 +00:00
|
|
|
class AcraApplication : Application() {
|
2023-08-23 21:57:54 +00:00
|
|
|
|
2022-09-01 12:13: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")) {
|
2022-09-01 12:13:54 +00:00
|
|
|
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)
|
|
|
|
}
|
2022-09-01 12:13:54 +00:00
|
|
|
}
|
|
|
|
|
2021-07-26 18:29:04 +00:00
|
|
|
override fun attachBaseContext(base: Context?) {
|
|
|
|
super.attachBaseContext(base)
|
2021-10-04 17:54:15 +00:00
|
|
|
context = base
|
2021-07-26 18:29:04 +00:00
|
|
|
|
|
|
|
initAcra {
|
|
|
|
//core configuration:
|
|
|
|
buildConfigClass = BuildConfig::class.java
|
|
|
|
reportFormat = StringFormat.JSON
|
|
|
|
|
2023-08-17 21:11:59 +00:00
|
|
|
reportContent = listOf(
|
2021-07-26 18:29:04 +00:00
|
|
|
ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE,
|
|
|
|
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
|
2023-08-17 21:11:59 +00:00
|
|
|
ReportField.STACK_TRACE,
|
2021-07-26 18:29:04 +00:00
|
|
|
)
|
|
|
|
|
2021-07-30 01:14:53 +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:
|
2021-07-30 01:14:53 +00:00
|
|
|
/*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-30 01:14:53 +00:00
|
|
|
}*/
|
2021-07-26 18:29:04 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-04 17:54:15 +00:00
|
|
|
|
|
|
|
companion object {
|
2023-08-23 21:57:54 +00:00
|
|
|
var exceptionHandler: ExceptionHandler? = null
|
|
|
|
|
2022-08-17 16:14:36 +00:00
|
|
|
/** Use to get activity from Context */
|
|
|
|
tailrec fun Context.getActivity(): Activity? = this as? Activity
|
|
|
|
?: (this as? ContextWrapper)?.baseContext?.getActivity()
|
|
|
|
|
2021-10-04 17:54:15 +00:00
|
|
|
private var _context: WeakReference<Context>? = null
|
|
|
|
var context
|
|
|
|
get() = _context?.get()
|
|
|
|
private set(value) {
|
|
|
|
_context = WeakReference(value)
|
|
|
|
}
|
2021-12-16 23:45:20 +00:00
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-12-16 23:45:20 +00:00
|
|
|
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)
|
2021-12-16 23:45:20 +00:00
|
|
|
}
|
2022-09-17 11:03:41 +00:00
|
|
|
|
|
|
|
/** Will fallback to webview if in TV layout */
|
|
|
|
fun openBrowser(url: String, activity: FragmentActivity?) {
|
|
|
|
openBrowser(
|
|
|
|
url,
|
2024-03-17 02:37:09 +00:00
|
|
|
isLayout(TV or EMULATOR),
|
2022-09-17 11:03:41 +00:00
|
|
|
activity?.supportFragmentManager?.fragments?.lastOrNull()
|
|
|
|
)
|
|
|
|
}
|
2021-10-04 17:54:15 +00:00
|
|
|
}
|
2023-08-17 21:11:59 +00:00
|
|
|
}
|