Skip to content

Commit

Permalink
feat: matomo analytics (#3888)
Browse files Browse the repository at this point in the history
* Matomo integration

* Show bottom sheet asking for analytics service

* rebase

Co-authored-by: Philippe Auriach <p.auriach@gmail.com>
  • Loading branch information
naivekook and philippeauriach committed Mar 18, 2021
1 parent 35503a2 commit 0952459
Show file tree
Hide file tree
Showing 29 changed files with 420 additions and 46 deletions.
5 changes: 5 additions & 0 deletions app/build.gradle.kts
Expand Up @@ -163,6 +163,7 @@ dependencies {

// Crash analytics
implementation("io.sentry:sentry-android:4.3.0")
implementation("org.matomo.sdk:tracker:4.1.2")

// ShowCaseView dependency
implementation("com.github.mreram:showcaseview:1.0.5")
Expand Down Expand Up @@ -286,6 +287,7 @@ android {
buildConfigField("String", "OFWEBSITE", "\"https://world.openfoodfacts.org/\"")
buildConfigField("String", "WIKIDATA", "\"https://www.wikidata.org/wiki/Special:EntityData/\"")
buildConfigField("String", "STATICURL", "\"https://static.openfoodfacts.org\"")
buildConfigField("String", "MATOMO_URL", "\"https://analytics.openfoodfacts.org/piwik.php\"")
dimension = "versionCode"
}
create("obf") {
Expand All @@ -297,6 +299,7 @@ android {
buildConfigField("String", "OFWEBSITE", "\"https://world.openbeautyfacts.org/\"")
buildConfigField("String", "WIKIDATA", "\"https://www.wikidata.org/wiki/Special:EntityData/\"")
buildConfigField("String", "STATICURL", "\"https://static.openbeautyfacts.org\"")
buildConfigField("String", "MATOMO_URL", "\"https://analytics.openfoodfacts.org/piwik.php\"")
dimension = "versionCode"
}
create("opff") {
Expand All @@ -308,6 +311,7 @@ android {
buildConfigField("String", "OFWEBSITE", "\"https://world.openpetfoodfacts.org/\"")
buildConfigField("String", "WIKIDATA", "\"https://www.wikidata.org/wiki/Special:EntityData/\"")
buildConfigField("String", "STATICURL", "\"https://static.openpetfoodfacts.org\"")
buildConfigField("String", "MATOMO_URL", "\"https://analytics.openfoodfacts.org/piwik.php\"")
dimension = "versionCode"
}
create("opf") {
Expand All @@ -319,6 +323,7 @@ android {
buildConfigField("String", "OFWEBSITE", "\"https://world.openproductsfacts.org/\"")
buildConfigField("String", "WIKIDATA", "\"https://www.wikidata.org/wiki/Special:EntityData/\"")
buildConfigField("String", "STATICURL", "\"https://static.openproductsfacts.org\"")
buildConfigField("String", "MATOMO_URL", "\"https://analytics.openfoodfacts.org/piwik.php\"")
dimension = "versionCode"
}
create("playstore") {
Expand Down
Expand Up @@ -58,6 +58,10 @@ import io.reactivex.schedulers.Schedulers
import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF
import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.analytics.AnalyticsEvent
import openfoodfacts.github.scrachx.openfood.analytics.AnalyticsView
import openfoodfacts.github.scrachx.openfood.analytics.MatomoAnalytics
import openfoodfacts.github.scrachx.openfood.app.OFFApplication
import openfoodfacts.github.scrachx.openfood.databinding.ActivityContinuousScanBinding
import openfoodfacts.github.scrachx.openfood.features.ImagesManageActivity
import openfoodfacts.github.scrachx.openfood.features.compare.ProductCompareActivity
Expand Down Expand Up @@ -112,6 +116,9 @@ class ContinuousScanActivity : AppCompatActivity() {
@Inject
lateinit var daoSession: DaoSession

@Inject
lateinit var productRepository: ProductRepository

private val cameraPref by lazy { getSharedPreferences("camera", 0) }

private val commonDisp = CompositeDisposable()
Expand Down Expand Up @@ -226,6 +233,7 @@ class ContinuousScanActivity : AppCompatActivity() {
putExtra(ProductCompareActivity.KEY_PRODUCT_ALREADY_EXISTS, true)
} else {
productsToCompare += product
MatomoAnalytics.trackEvent(AnalyticsEvent.AddProductToComparison(product.code))
}
putExtra(ProductCompareActivity.KEY_PRODUCTS_TO_COMPARE, productsToCompare)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
Expand Down Expand Up @@ -362,9 +370,6 @@ class ContinuousScanActivity : AppCompatActivity() {
}
}

@Inject
lateinit var productRepository: ProductRepository

private fun showProductNotFound(text: String) {
hideAllViews()
quickViewBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
Expand Down Expand Up @@ -519,6 +524,7 @@ class ContinuousScanActivity : AppCompatActivity() {
if (quickViewBehavior.state != BottomSheetBehavior.STATE_EXPANDED) {
binding.barcodeScanner.resume()
}
MatomoAnalytics.trackView(AnalyticsView.Scanner)
}

override fun onSaveInstanceState(outState: Bundle) {
Expand Down Expand Up @@ -711,10 +717,12 @@ class ContinuousScanActivity : AppCompatActivity() {
lastBarcode = null
binding.txtProductCallToAction.visibility = View.GONE
}
else -> {
binding.barcodeScanner.pause()
}
BottomSheetBehavior.STATE_EXPANDED -> {
binding.barcodeScanner.pause()
MatomoAnalytics.trackEvent(AnalyticsEvent.ScannedBarcodeResultExpanded(lastBarcode))
}
else -> binding.barcodeScanner.pause()
}


if (binding.quickViewSearchByBarcode.visibility == View.VISIBLE) {
Expand Down Expand Up @@ -796,7 +804,11 @@ class ContinuousScanActivity : AppCompatActivity() {
if (beepActive) {
beepManager.playBeepSound()
}
lastBarcode = result.text.also { if (!isFinishing) setShownProduct(it) }
lastBarcode = result.text
if (!isFinishing) {
setShownProduct(result.text)
MatomoAnalytics.trackEvent(AnalyticsEvent.ScannedBarcode(result.text))
}

}

Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -48,6 +48,7 @@
<meta-data
android:name="io.sentry.session-tracking.enable"
android:value="true" />
<meta-data android:name="io.sentry.auto-init" android:value="false" />

<!-- 18:9 aspect ratio support -->
<meta-data
Expand Down
@@ -0,0 +1,36 @@
package openfoodfacts.github.scrachx.openfood.analytics

sealed class AnalyticsEvent(val category: String, val action: String, val name: String?, val value: Float?) {

data class ScannedBarcode(val barcode: String) : AnalyticsEvent("scanner", "scanned", barcode, null)

data class ScannedBarcodeResultExpanded(val barcode: String?) : AnalyticsEvent("scanner", "result-expanded", barcode, null)

data class AllergenAlertCreated(val allergenTag: String) : AnalyticsEvent("allergen-alerts", "created", allergenTag, null)

data class ProductCreated(val barcode: String?) : AnalyticsEvent("products", "created", barcode, null)

data class ProductEdited(val barcode: String?) : AnalyticsEvent("products", "edited", barcode, null)

data class ProductIngredientsPictureEdited(val barcode: String?) : AnalyticsEvent("products", "edited-ingredients-picture", barcode, null)

object UserLogin : AnalyticsEvent("user-account", "login", null, null)

object UserLogout : AnalyticsEvent("user-account", "logout", null, null)

object RobotoffLoginPrompt : AnalyticsEvent("user-account", "login-prompt", "robotoff", null)

object RobotoffLoggedInAfterPrompt : AnalyticsEvent("user-account", "logged-in-after-prompt", "robotoff", null)

object ShoppingListCreated : AnalyticsEvent("shopping-lists", "created", null, null)

object ShoppingListExported : AnalyticsEvent("shopping-lists", "exported", null, null)

data class IngredientAnalysisEnabled(val type: String) : AnalyticsEvent("ingredient-analysis", "enabled", type, null)

data class IngredientAnalysisDisabled(val type: String) : AnalyticsEvent("ingredient-analysis", "disabled", type, null)

data class AddProductToComparison(val barcode: String) : AnalyticsEvent("products", "compare-add", barcode, null)

data class CompareProducts(val count: Float) : AnalyticsEvent("products", "compare-multiple", null, count)
}
@@ -0,0 +1,8 @@
package openfoodfacts.github.scrachx.openfood.analytics

enum class AnalyticsView(val path: String) {
Scanner("scanner"),
ProductEditOverview("products/edit/overview"),
ProductEditIngredients("products/edit/ingredients"),
ProductEditNutritionFacts("products/edit/nutrition_facts");
}
@@ -0,0 +1,54 @@
package openfoodfacts.github.scrachx.openfood.analytics

import androidx.fragment.app.FragmentManager
import androidx.preference.PreferenceManager
import openfoodfacts.github.scrachx.openfood.BuildConfig
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.app.OFFApplication
import openfoodfacts.github.scrachx.openfood.features.analyticsusage.AnalyticsUsageDialogFragment
import org.matomo.sdk.Matomo
import org.matomo.sdk.TrackerBuilder
import org.matomo.sdk.extra.TrackHelper


object MatomoAnalytics {

//TODO: change matomo url and id from properties
private val tracker = TrackerBuilder
.createDefault(BuildConfig.MATOMO_URL, 1)
.build(Matomo.getInstance(OFFApplication._instance))
.apply {
isOptOut = PreferenceManager.getDefaultSharedPreferences(OFFApplication._instance)
.getBoolean(OFFApplication._instance.getString(R.string.pref_analytics_reporting_key), false)
}
.also {
TrackHelper.track().download().with(it)
}

fun trackView(view: AnalyticsView) {
TrackHelper.track()
.screen(view.path)
.with(tracker)
}

fun trackEvent(event: AnalyticsEvent) {
TrackHelper.track()
.event(event.category, event.action)
.name(event.name)
.value(event.value)
.with(tracker)
}

fun showAnalyticsBottomSheetIfNeeded(childFragmentManager: FragmentManager) {
if (PreferenceManager.getDefaultSharedPreferences(OFFApplication._instance).contains(OFFApplication._instance.getString(R.string.pref_analytics_reporting_key))) {
//key already exists, do not show
return
}
val bottomSheet = AnalyticsUsageDialogFragment()
bottomSheet.show(childFragmentManager, AnalyticsUsageDialogFragment.TAG)
}

fun onAnalyticsEnabledToggled(enabled: Boolean) {
tracker.isOptOut = !enabled
}
}
@@ -0,0 +1,43 @@
package openfoodfacts.github.scrachx.openfood.analytics

import androidx.preference.PreferenceManager
import io.sentry.Sentry
import io.sentry.android.core.SentryAndroid
import openfoodfacts.github.scrachx.openfood.BuildConfig
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.app.OFFApplication


object SentryAnalytics {

// isCrashReportingEnabled is not dynamic, as sentry can not be enabled / disabled, so it takes the value at startup, and changes will only be taken into account after an app restart
private val isCrashReportingEnabled by lazy {
PreferenceManager.getDefaultSharedPreferences(OFFApplication._instance)
.getBoolean(OFFApplication._instance.getString(R.string.pref_crash_reporting_key), true)
}

fun init() {
if (isCrashReportingEnabled) {
SentryAndroid.init(OFFApplication._instance)
Sentry.configureScope { scope ->
scope.setTag("flavor", BuildConfig.FLAVOR)
}
}
}

fun setBarcode(barcode: String) {
setTag("barcode", barcode)
}

fun setTag(key: String, value: String) {
if (isCrashReportingEnabled) {
Sentry.setTag(key, value)
}
}

fun record(exception: Throwable) {
if (isCrashReportingEnabled) {
Sentry.captureException(exception)
}
}
}

This file was deleted.

Expand Up @@ -28,7 +28,7 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.greendao.query.QueryBuilder
import java.io.IOException
import javax.inject.Inject
import openfoodfacts.github.scrachx.openfood.app.AnalyticsService.init as initAnalytics
import openfoodfacts.github.scrachx.openfood.analytics.SentryAnalytics.init as initAnalytics

@HiltAndroidApp
class OFFApplication : MultiDexApplication(), Configuration.Provider {
Expand Down Expand Up @@ -87,4 +87,4 @@ class OFFApplication : MultiDexApplication(), Configuration.Provider {
@Synchronized
private set
}
}
}
Expand Up @@ -38,6 +38,8 @@ import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF
import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors
import openfoodfacts.github.scrachx.openfood.BuildConfig
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.analytics.AnalyticsEvent
import openfoodfacts.github.scrachx.openfood.analytics.MatomoAnalytics
import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper
import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabsHelper
import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback
Expand Down Expand Up @@ -147,6 +149,9 @@ class LoginActivity : BaseActivity() {
}
binding.txtInfoLogin.setTextColor(ContextCompat.getColor(this, R.color.green_500))
binding.txtInfoLogin.setText(R.string.txtInfoLoginOk)

MatomoAnalytics.trackEvent(AnalyticsEvent.UserLogin)

setResult(RESULT_OK)
finish()
}
Expand Down Expand Up @@ -235,4 +240,4 @@ class LoginActivity : BaseActivity() {
override fun parseResult(resultCode: Int, intent: Intent?) = resultCode == RESULT_OK
}
}
}
}
Expand Up @@ -72,6 +72,8 @@ import openfoodfacts.github.scrachx.openfood.AppFlavors
import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors
import openfoodfacts.github.scrachx.openfood.BuildConfig
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.analytics.AnalyticsEvent
import openfoodfacts.github.scrachx.openfood.analytics.MatomoAnalytics
import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper
import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabsHelper
import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback
Expand Down Expand Up @@ -519,6 +521,7 @@ class MainActivity : BaseActivity(), NavigationDrawerListener {
private fun logout() {
getSharedPreferences(PreferencesFragment.LOGIN_PREF, MODE_PRIVATE).edit { clear() }
updateConnectedState()
MatomoAnalytics.trackEvent(AnalyticsEvent.UserLogout)
}

override fun onSaveInstanceState(outState: Bundle) {
Expand Down Expand Up @@ -728,6 +731,7 @@ class MainActivity : BaseActivity(), NavigationDrawerListener {
public override fun onResume() {
super.onResume()
binding.bottomNavigationInclude.bottomNavigation.selectNavigationItem(R.id.home_page)
MatomoAnalytics.showAnalyticsBottomSheetIfNeeded(supportFragmentManager)

// change drawer menu item from "install" to "open" when navigating back from play store.
if (isApplicationInstalled(this@MainActivity, BuildConfig.OFOTHERLINKAPP)) {
Expand Down

0 comments on commit 0952459

Please sign in to comment.