Improve analytics

- Automatic page view tracking wasn't helpful since it was based on the Activities viewed, and SimpleMarkdown is a single-Activity app, so page views are now tracked manually
- User preferences are now reported so I can remove preferences that aren't used and focus my time on features that are actively used
- Opting out of crash reports is no longer possible. I need crash reports to be able to improve the app. It would also simplify the code a bit to not need to take that into account. Existing opt-outs will be respected but moving forward, new users will need to download the app from Fdroid if they'd like to avoid interactions with Google.
This commit is contained in:
William Brawner 2022-10-23 23:44:02 -06:00
parent c315439763
commit 3108114b60
10 changed files with 100 additions and 11 deletions

View file

@ -0,0 +1,19 @@
package com.wbrawner.simplemarkdown.utility
import android.content.Context
import com.wbrawner.simplemarkdown.BuildConfig
import timber.log.Timber
class NoopAnalyticsHelper(context: Context): AnalyticsHelper() {
override fun setUserProperty(name: String, value: String) {
if (BuildConfig.DEBUG) {
Timber.tag("NoopAnalyticsHelper").d("setting user property $name to $value")
}
}
override fun trackPageView(name: String) {
Timber.tag("NoopAnalyticsHelper").d("user viewed $name page")
}
}
fun AnalyticsHelper.Companion.init(context: Context) = NoopAnalyticsHelper(context)

View file

@ -0,0 +1,8 @@
package com.wbrawner.simplemarkdown.utility
abstract class AnalyticsHelper {
abstract fun setUserProperty(name: String, value: String)
abstract fun trackPageView(name: String)
companion object
}

View file

@ -1,16 +1,30 @@
package com.wbrawner.simplemarkdown.view.activity package com.wbrawner.simplemarkdown.view.activity
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.AnalyticsHelper
import com.wbrawner.simplemarkdown.utility.init
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback { class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
private val analyticsHelper = AnalyticsHelper.init(this)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
analyticsHelper.setUserProperty("autosave", sharedPreferences.getBoolean("autosave", true).toString())
val usingCustomCss = !getStringPref(R.string.pref_custom_css, null).isNullOrBlank()
analyticsHelper.setUserProperty("using_custom_css", usingCustomCss.toString())
val darkModeSetting = getStringPref(R.string.pref_key_dark_mode, "auto").toString()
analyticsHelper.setUserProperty("dark_mode", darkModeSetting)
analyticsHelper.setUserProperty("error_reports_enabled", getBooleanPref(R.string.pref_key_error_reports_enabled, true).toString())
analyticsHelper.setUserProperty("readability_enabled", getBooleanPref(R.string.readability_enabled, false).toString())
} }
override fun onBackPressed() { override fun onBackPressed() {
@ -19,3 +33,13 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
} }
} }
} }
fun Context.getBooleanPref(@StringRes key: Int, defaultValue: Boolean) = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
getString(key),
defaultValue
)
fun Context.getStringPref(@StringRes key: Int, defaultValue: String?) = PreferenceManager.getDefaultSharedPreferences(this).getString(
getString(key),
defaultValue
)

View file

@ -23,8 +23,10 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.AnalyticsHelper
import com.wbrawner.simplemarkdown.utility.ErrorHandler import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.utility.errorHandlerImpl import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
import com.wbrawner.simplemarkdown.utility.init
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
import kotlinx.android.synthetic.main.fragment_main.* import kotlinx.android.synthetic.main.fragment_main.*
@ -144,6 +146,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
AnalyticsHelper.init(requireContext()).trackPageView("Edit")
lifecycleScope.launch { lifecycleScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(requireContext()) val enableErrorReports = PreferenceManager.getDefaultSharedPreferences(requireContext())

View file

@ -13,15 +13,13 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.ErrorHandler import com.wbrawner.simplemarkdown.utility.*
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.* import kotlinx.android.synthetic.main.fragment_markdown_info.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class MarkdownInfoFragment : Fragment() { class MarkdownInfoFragment : Fragment() {
private val errorHandler: ErrorHandler by errorHandlerImpl() private val errorHandler: ErrorHandler by errorHandlerImpl()
private lateinit var analyticsHelper: AnalyticsHelper
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -74,6 +72,13 @@ class MarkdownInfoFragment : Fragment() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun onStart() {
super.onStart()
arguments?.getString(EXTRA_FILE)?.let {
AnalyticsHelper.init(requireContext()).trackPageView(it)
}
}
companion object { companion object {
const val FORMAT_CSS = "<style>" + const val FORMAT_CSS = "<style>" +
"%s" + "%s" +

View file

@ -9,6 +9,8 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.AnalyticsHelper
import com.wbrawner.simplemarkdown.utility.init
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
class SettingsContainerFragment : Fragment() { class SettingsContainerFragment : Fragment() {
@ -25,4 +27,9 @@ class SettingsContainerFragment : Fragment() {
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean = findNavController().navigateUp() override fun onOptionsItemSelected(item: MenuItem): Boolean = findNavController().navigateUp()
override fun onStart() {
super.onStart()
AnalyticsHelper.init(requireContext()).trackPageView("Settings")
}
} }

View file

@ -13,7 +13,9 @@ import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.AnalyticsHelper
import com.wbrawner.simplemarkdown.utility.SupportLinkProvider import com.wbrawner.simplemarkdown.utility.SupportLinkProvider
import com.wbrawner.simplemarkdown.utility.init
import kotlinx.android.synthetic.main.fragment_support.* import kotlinx.android.synthetic.main.fragment_support.*
class SupportFragment : Fragment() { class SupportFragment : Fragment() {
@ -51,7 +53,12 @@ class SupportFragment : Fragment() {
}) })
} }
// override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onStart() {
super.onStart()
AnalyticsHelper.init(requireContext()).trackPageView("Support")
}
// override fun onOptionsItemSelected(item: MenuItem): Boolean {
// if (item.itemId == android.R.id.home) { // if (item.itemId == android.R.id.home) {
// findNavController().navigateUp() // findNavController().navigateUp()
// return true // return true

View file

@ -17,12 +17,6 @@
android:defaultValue="@string/pref_key_dark_mode_auto" android:defaultValue="@string/pref_key_dark_mode_auto"
android:key="@string/pref_key_dark_mode" android:key="@string/pref_key_dark_mode"
android:title="@string/title_dark_mode" /> android:title="@string/title_dark_mode" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/pref_key_error_reports_enabled"
android:summaryOff="@string/pref_error_reports_off"
android:summaryOn="@string/pref_error_reports_on"
android:title="@string/pref_title_error_reports" />
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="@string/readability_enabled" android:key="@string/readability_enabled"

View file

@ -8,6 +8,9 @@
<meta-data <meta-data
android:name="firebase_crashlytics_collection_enabled" android:name="firebase_crashlytics_collection_enabled"
android:value="false" /> android:value="false" />
<meta-data
android:name="google_analytics_automatic_screen_reporting_enabled"
android:value="false" />
</application> </application>
</manifest> </manifest>

View file

@ -0,0 +1,19 @@
package com.wbrawner.simplemarkdown.utility
import android.content.Context
import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
class FirebaseAnalyticsHelper(context: Context): AnalyticsHelper() {
private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
override fun setUserProperty(name: String, value: String) {
firebaseAnalytics.setUserProperty(name, value)
}
override fun trackPageView(name: String) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, Bundle().apply { putString(FirebaseAnalytics.Param.SCREEN_NAME, name) })
}
}
fun AnalyticsHelper.Companion.init(context: Context) = FirebaseAnalyticsHelper(context)