diff --git a/app/.gitignore b/library/.gitignore similarity index 100% rename from app/.gitignore rename to library/.gitignore diff --git a/crashhandler/build.gradle.kts b/library/build.gradle.kts similarity index 100% rename from crashhandler/build.gradle.kts rename to library/build.gradle.kts diff --git a/crashhandler/consumer-rules.pro b/library/consumer-rules.pro similarity index 100% rename from crashhandler/consumer-rules.pro rename to library/consumer-rules.pro diff --git a/app/proguard-rules.pro b/library/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to library/proguard-rules.pro diff --git a/crashhandler/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml similarity index 100% rename from crashhandler/src/main/AndroidManifest.xml rename to library/src/main/AndroidManifest.xml diff --git a/crashhandler/src/main/java/com/dzeio/crashhandler/CrashHandler.kt b/library/src/main/java/com/dzeio/crashhandler/CrashHandler.kt similarity index 80% rename from crashhandler/src/main/java/com/dzeio/crashhandler/CrashHandler.kt rename to library/src/main/java/com/dzeio/crashhandler/CrashHandler.kt index bc32284..f48cafd 100644 --- a/crashhandler/src/main/java/com/dzeio/crashhandler/CrashHandler.kt +++ b/library/src/main/java/com/dzeio/crashhandler/CrashHandler.kt @@ -1,6 +1,7 @@ package com.dzeio.crashhandler import android.app.Application +import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.os.Build @@ -17,13 +18,14 @@ import kotlin.system.exitProcess * the Crash Handler class, you can get an instance by using it's [Builder] */ class CrashHandler private constructor( - private val activity: Any, + private val application: Application?, + private val activity: Class<*>, private val prefs: SharedPreferences?, private val prefsKey: String?, @StringRes private val errorReporterCrashKey: Int?, - private var prefix: String? = null, - private var suffix: String? = null + private val prefix: String? = null, + private val suffix: String? = null ) { private companion object { @@ -34,10 +36,11 @@ class CrashHandler private constructor( * Builder for the crash handler */ class Builder() { + private var application: Application? = null private var prefs: SharedPreferences? = null private var prefsKey: String? = null private var errorReporterCrashKey: Int? = null - private var activity: Any? = ErrorActivity::class.java + private var activity: Class<*>? = ErrorActivity::class.java private var prefix: String? = null private var suffix: String? = null @@ -48,7 +51,19 @@ class CrashHandler private constructor( * * @param activity the activity class to use */ - fun withActivity(activity: Any): Builder { + fun withContext(context: Context): Builder { + this.application = context.applicationContext as Application? + return this + } + + /** + * Change the Crash activity to with your own + * + * note: you can get the backtrace text by using `intent.getStringExtra("error")` + * + * @param activity the activity class to use + */ + fun withActivity(activity: Class<*>): Builder { this.activity = activity return this } @@ -114,7 +129,24 @@ class CrashHandler private constructor( * build the Crash Handler */ fun build(): CrashHandler { - return CrashHandler(activity!!, prefs, prefsKey, errorReporterCrashKey, prefix, suffix) + return CrashHandler(application, activity!!, prefs, prefsKey, errorReporterCrashKey, prefix, suffix) + } + } + + private var oldHandler: Thread.UncaughtExceptionHandler? = null + + fun setup() { + if (application != null) { + this.setup(application) + } + } + + /** + * Destroy the handler + */ + fun destroy() { + if (oldHandler != null) { + Thread.setDefaultUncaughtExceptionHandler(oldHandler) } } @@ -126,7 +158,7 @@ class CrashHandler private constructor( */ fun setup(application: Application) { // Application Error Handling - val oldHandler = Thread.getDefaultUncaughtExceptionHandler() + oldHandler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { paramThread, paramThrowable -> // Log error to logcat if it wasn't done before has it can not be logged depending on the version @@ -199,13 +231,13 @@ class CrashHandler private constructor( data += suffix ?: "" - Log.i(TAG, "Starting ${(activity as Class<*>).name}") + Log.i(TAG, "Starting ${activity.name}") // prepare the activity - val intent = Intent(application.applicationContext, activity) + val intent = Intent(application, activity) // add flags so that it don't use the current Application context - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) // add the Data String intent.putExtra("error", data) diff --git a/crashhandler/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt b/library/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt similarity index 74% rename from crashhandler/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt rename to library/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt index f7f7c3d..05845f3 100644 --- a/crashhandler/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt +++ b/library/src/main/java/com/dzeio/crashhandler/ui/ErrorActivity.kt @@ -5,24 +5,26 @@ import android.content.ClipboardManager import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import com.dzeio.crashhandler.databinding.ActivityErrorBinding +import com.dzeio.crashhandler.databinding.CrashHandlerActivityErrorBinding class ErrorActivity : AppCompatActivity() { - private lateinit var binding: ActivityErrorBinding + private lateinit var binding: CrashHandlerActivityErrorBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityErrorBinding.inflate(layoutInflater) + binding = CrashHandlerActivityErrorBinding.inflate(layoutInflater) setContentView(binding.root) val data = intent.getStringExtra("error") // put it in the textView - binding.errorText.text = data - binding.errorText.setTextIsSelectable(true) + binding.errorText.apply { + text = data + setTextIsSelectable(true) + } // Handle the Quit button binding.errorQuit.setOnClickListener { diff --git a/crashhandler/src/main/res/layout/activity_error.xml b/library/src/main/res/layout/crash_handler_activity_error.xml similarity index 97% rename from crashhandler/src/main/res/layout/activity_error.xml rename to library/src/main/res/layout/crash_handler_activity_error.xml index 092825f..ac66020 100644 --- a/crashhandler/src/main/res/layout/activity_error.xml +++ b/library/src/main/res/layout/crash_handler_activity_error.xml @@ -2,7 +2,8 @@ diff --git a/crashhandler/src/main/res/values-fr/strings.xml b/library/src/main/res/values-fr/strings.xml similarity index 100% rename from crashhandler/src/main/res/values-fr/strings.xml rename to library/src/main/res/values-fr/strings.xml diff --git a/crashhandler/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml similarity index 100% rename from crashhandler/src/main/res/values/strings.xml rename to library/src/main/res/values/strings.xml diff --git a/crashhandler/.gitignore b/sample/.gitignore similarity index 100% rename from crashhandler/.gitignore rename to sample/.gitignore diff --git a/app/build.gradle.kts b/sample/build.gradle.kts similarity index 95% rename from app/build.gradle.kts rename to sample/build.gradle.kts index 9239fdf..7b386c7 100644 --- a/app/build.gradle.kts +++ b/sample/build.gradle.kts @@ -39,8 +39,8 @@ android { dependencies { - implementation(project(":crashhandler")) - + implementation(project(":library")) + // Material Design implementation("com.google.android.material:material:1.6.1") diff --git a/crashhandler/proguard-rules.pro b/sample/proguard-rules.pro similarity index 100% rename from crashhandler/proguard-rules.pro rename to sample/proguard-rules.pro diff --git a/app/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml similarity index 81% rename from app/src/main/AndroidManifest.xml rename to sample/src/main/AndroidManifest.xml index 4f11eb8..1854c29 100644 --- a/app/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -15,6 +15,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/dzeio/crashhandlertest/Application.kt b/sample/src/main/java/com/dzeio/crashhandlertest/Application.kt similarity index 55% rename from app/src/main/java/com/dzeio/crashhandlertest/Application.kt rename to sample/src/main/java/com/dzeio/crashhandlertest/Application.kt index 4205410..21e5f80 100644 --- a/app/src/main/java/com/dzeio/crashhandlertest/Application.kt +++ b/sample/src/main/java/com/dzeio/crashhandlertest/Application.kt @@ -1,14 +1,21 @@ package com.dzeio.crashhandlertest import com.dzeio.crashhandler.CrashHandler +import com.dzeio.crashhandlertest.ui.ErrorActivity class Application : android.app.Application() { override fun onCreate() { super.onCreate() CrashHandler.Builder() + .withActivity(ErrorActivity::class.java) + .withContext(this) .withPrefix("Pouet :D") .withSuffix("WHYYYYY") - .build().setup(this) + .build().setup() + } + + companion object { + const val TAG = "CrashHandlerTest" } } \ No newline at end of file diff --git a/sample/src/main/java/com/dzeio/crashhandlertest/ui/ErrorActivity.kt b/sample/src/main/java/com/dzeio/crashhandlertest/ui/ErrorActivity.kt new file mode 100644 index 0000000..731000a --- /dev/null +++ b/sample/src/main/java/com/dzeio/crashhandlertest/ui/ErrorActivity.kt @@ -0,0 +1,86 @@ +package com.dzeio.crashhandlertest.ui + +import android.content.ActivityNotFoundException +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Process +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.WindowCompat +import com.dzeio.crashhandlertest.Application +import com.dzeio.crashhandlertest.databinding.ActivityErrorBinding +import kotlin.system.exitProcess + +class ErrorActivity : AppCompatActivity() { + + companion object { + const val TAG = "${Application.TAG}/ErrorActivity" + } + + private lateinit var binding: ActivityErrorBinding + + override fun onCreate(savedInstanceState: Bundle?) { + WindowCompat.setDecorFitsSystemWindows(window, false) + super.onCreate(savedInstanceState) + + binding = ActivityErrorBinding.inflate(layoutInflater) + setContentView(binding.root) + + val data = intent.getStringExtra("error") + + // Get Application datas + val deviceToReport = if (Build.DEVICE.contains(Build.MANUFACTURER)) Build.DEVICE else "${Build.MANUFACTURER} ${Build.DEVICE}" + + val reportText = """ + Crash Report (Thread: ${intent?.getLongExtra("threadId", -1) ?: "unknown"}) + on $deviceToReport (${Build.MODEL}) running Android ${Build.VERSION.RELEASE} (${Build.VERSION.SDK_INT}) + + backtrace: + + """.trimIndent() + data + + // put it in the textView + binding.errorText.text = reportText + + // Handle the Quit button + binding.errorQuit.setOnClickListener { + Process.killProcess(Process.myPid()) + exitProcess(10) + } + + // Handle the Email Button + binding.errorSubmitEmail.setOnClickListener { + + // Create Intent + val intent = Intent(Intent.ACTION_SEND) + intent.data = Uri.parse("mailto:") + intent.type = "text/plain" + intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("report.openhealth@dzeio.com")) + intent.putExtra(Intent.EXTRA_SUBJECT, "Error report for application crash") + intent.putExtra(Intent.EXTRA_TEXT, "Send Report Email\n$reportText") + + try { + startActivity(Intent.createChooser(intent, "Send Report Email...")) + } catch (e: ActivityNotFoundException) { + Toast.makeText(this, "Not Email client found :(", Toast.LENGTH_LONG).show() + } + } + + // Handle the GitHub Button + binding.errorSubmitGithub.setOnClickListener { + + // Build URL + val url = "https://github.com/dzeiocom/OpenHealth/issues/new?title=Application Error&body=$reportText" + + try { + startActivity( + Intent(Intent.ACTION_VIEW, Uri.parse(url)) + ) + } catch (e: ActivityNotFoundException) { + Toast.makeText(this, "No Web Browser found :(", Toast.LENGTH_LONG).show() + } + } + } +} diff --git a/app/src/main/java/com/dzeio/crashhandlertest/ui/MainActivity.kt b/sample/src/main/java/com/dzeio/crashhandlertest/ui/MainActivity.kt similarity index 100% rename from app/src/main/java/com/dzeio/crashhandlertest/ui/MainActivity.kt rename to sample/src/main/java/com/dzeio/crashhandlertest/ui/MainActivity.kt diff --git a/app/src/main/java/com/dzeio/crashhandlertest/ui/MainFragment.kt b/sample/src/main/java/com/dzeio/crashhandlertest/ui/MainFragment.kt similarity index 100% rename from app/src/main/java/com/dzeio/crashhandlertest/ui/MainFragment.kt rename to sample/src/main/java/com/dzeio/crashhandlertest/ui/MainFragment.kt diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/sample/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to sample/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/sample/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_background.xml rename to sample/src/main/res/drawable/ic_launcher_background.xml diff --git a/sample/src/main/res/layout/activity_error.xml b/sample/src/main/res/layout/activity_error.xml new file mode 100644 index 0000000..1053f05 --- /dev/null +++ b/sample/src/main/res/layout/activity_error.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + +