diff --git a/.gitignore b/.gitignore
index 6a955c3..07544b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,3 @@
*.log
keystore.properties
*.jks
-sentry.properties
diff --git a/app/acra.properties.sample b/app/acra.properties.sample
new file mode 100644
index 0000000..c0c912f
--- /dev/null
+++ b/app/acra.properties.sample
@@ -0,0 +1,3 @@
+url=ACRA_URL
+user=ACRA_USER
+pass=ACRA_PASS
diff --git a/app/build.gradle b/app/build.gradle
index f6c35c1..e04aba7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,6 +3,7 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'jacoco'
+apply plugin: 'com.google.firebase.crashlytics'
def keystoreProperties = new Properties()
try {
@@ -110,8 +111,9 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'com.commonsware.cwac:anddown:0.3.0'
playImplementation 'com.android.billingclient:billing:3.0.0'
- playImplementation 'com.google.firebase:firebase-core:17.5.0'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
+ playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
+ playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation "androidx.core:core-ktx:1.3.1"
implementation 'androidx.browser:browser:1.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
@@ -132,7 +134,6 @@ android.productFlavors.each { flavor ->
}
repositories {
mavenCentral()
- jcenter()
}
jacoco {
diff --git a/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt b/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt
new file mode 100644
index 0000000..7bc5eda
--- /dev/null
+++ b/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt
@@ -0,0 +1,22 @@
+package com.wbrawner.simplemarkdown.utility
+
+import kotlin.reflect.KProperty
+
+class errorHandlerImpl {
+ operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
+ return implementation
+ }
+
+ companion object {
+ // Default no-op error handler for debugging
+ val implementation: ErrorHandler = object : ErrorHandler {
+ override fun enable(enable: Boolean) {
+ // no-op
+ }
+
+ override fun reportException(t: Throwable, message: String?) {
+ Log.e("ErrorHandler", "Caught non-fatal exception. Message: $message", t)
+ }
+ }
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 70f1d5d..ea4d80f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,6 +43,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/Privacy Policy.md b/app/src/main/assets/Privacy Policy.md
new file mode 100644
index 0000000..74416b3
--- /dev/null
+++ b/app/src/main/assets/Privacy Policy.md
@@ -0,0 +1,12 @@
+## Privacy Policy
+
+The internet access permission is requested primarily for retrieving images from the internet in
+ case you embed them in your markdown, but it also allows me to send automated error and crash
+ reports to myself whenever the app runs into an issue. These error reports are opt-out, and are
+ powered by [Firebase Crashlytics] (https://firebase.google.com/docs/crashlytics/), which is a
+ free error reporting solution provided by Google. These error reports are used exclusively for
+ fixing problems that occur while you're using the app, along with some analytics info like how
+ long you use the app for, how often, and which features of the app you use. This helps me to
+ determine how to spend my very limited time on building out new features. I'll have to defer to
+ [Google's Privacy Policy](https://policies.google.com/privacy) to explain how they handle the
+ data. As for me, I don't knowingly or willingly sell or share your data.
diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt b/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt
new file mode 100644
index 0000000..a961b4b
--- /dev/null
+++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt
@@ -0,0 +1,6 @@
+package com.wbrawner.simplemarkdown.utility
+
+interface ErrorHandler {
+ fun enable(enable: Boolean)
+ fun reportException(t: Throwable, message: String? = null)
+}
diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt
index 1eb789f..b0ea4cf 100644
--- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt
+++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt
@@ -24,6 +24,8 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.R
+import com.wbrawner.simplemarkdown.utility.ErrorHandler
+import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
import kotlinx.android.synthetic.main.fragment_main.*
@@ -37,6 +39,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
override val coroutineContext: CoroutineContext = Dispatchers.Main
private val viewModel: MarkdownViewModel by viewModels()
private var appBarConfiguration: AppBarConfiguration? = null
+ private val errorHandler: ErrorHandler by errorHandlerImpl()
override fun onAttach(context: Context) {
super.onAttach(context)
@@ -137,6 +140,17 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
}
}
+ override fun onStart() {
+ super.onStart()
+ launch {
+ withContext(Dispatchers.IO) {
+ val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .getBoolean(getString(R.string.pref_key_error_reports_enabled), true)
+ errorHandler.enable(enableErrorReports)
+ }
+ }
+ }
+
override fun onPause() {
super.onPause()
launch {
diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MarkdownInfoFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MarkdownInfoFragment.kt
index ef68e66..96a205e 100644
--- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MarkdownInfoFragment.kt
+++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MarkdownInfoFragment.kt
@@ -12,6 +12,8 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.wbrawner.simplemarkdown.R
+import com.wbrawner.simplemarkdown.utility.ErrorHandler
+import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
import com.wbrawner.simplemarkdown.utility.readAssetToString
import com.wbrawner.simplemarkdown.utility.toHtml
import kotlinx.android.synthetic.main.fragment_markdown_info.*
@@ -23,6 +25,7 @@ import kotlin.coroutines.CoroutineContext
class MarkdownInfoFragment : Fragment(), CoroutineScope {
override val coroutineContext: CoroutineContext = Dispatchers.Main
+ private val errorHandler: ErrorHandler by errorHandlerImpl()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -60,6 +63,7 @@ class MarkdownInfoFragment : Fragment(), CoroutineScope {
"UTF-8", null
)
} catch (e: Exception) {
+ errorHandler.reportException(e)
Toast.makeText(view.context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
findNavController().navigateUp()
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e32611c..d5cee08 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -34,7 +34,7 @@
Lock Swiping
Select
Privacy
- acra.enable
+ crashlytics.enable
Enable automated error reports
Error reports will not be sent
Error reports will be sent
diff --git a/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt b/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt
new file mode 100644
index 0000000..cfc8d81
--- /dev/null
+++ b/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt
@@ -0,0 +1,32 @@
+package com.wbrawner.simplemarkdown.utility
+
+import android.util.Log
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.wbrawner.simplemarkdown.BuildConfig
+import kotlin.reflect.KProperty
+
+class CrashlyticsErrorHandler : ErrorHandler {
+ private val crashlytics = FirebaseCrashlytics.getInstance()
+
+ override fun enable(enable: Boolean) {
+ crashlytics.setCrashlyticsCollectionEnabled(enable)
+ }
+
+ override fun reportException(t: Throwable, message: String?) {
+ @Suppress("ConstantConditionIf")
+ if (BuildConfig.DEBUG) {
+ Log.e("CrashlyticsErrorHandler", "Caught exception: $message", t)
+ }
+ crashlytics.recordException(t)
+ }
+}
+
+class errorHandlerImpl {
+ operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
+ return impl
+ }
+
+ companion object {
+ val impl = CrashlyticsErrorHandler()
+ }
+}
diff --git a/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt b/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt
index fae79e7..3b515c5 100644
--- a/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt
+++ b/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt
@@ -27,6 +27,7 @@ object ReviewHelper : Application.ActivityLifecycleCallbacks {
private lateinit var application: Application
private lateinit var reviewManager: ReviewManager
private lateinit var sharedPreferences: SharedPreferences
+ private val errorHandler: ErrorHandler by errorHandlerImpl()
private var currentActivity: Activity? = null
private var activityCount = 0
set(value) {
diff --git a/build.gradle b/build.gradle
index 1da8f69..a5a151f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,6 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.google.gms:google-services:4.3.3'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 7730d7d..d5089a9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Wed Jun 10 07:53:53 MST 2020
+#Mon Sep 21 10:36:14 MST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME