diff --git a/Core2/Matomo/build.gradle.kts b/Core2/Matomo/build.gradle.kts
new file mode 100644
index 000000000..7784304a9
--- /dev/null
+++ b/Core2/Matomo/build.gradle.kts
@@ -0,0 +1,42 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+}
+
+android {
+ namespace = "com.infomaniak.matomo"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+
+ buildConfigField("String", "MATOMO_URL", "\"https://analytics.infomaniak.com/matomo.php\"")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ buildFeatures {
+ buildConfig = true
+ }
+
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+ api(core2.matomo)
+}
diff --git a/Core2/Matomo/consumer-rules.pro b/Core2/Matomo/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/Core2/Matomo/proguard-rules.pro b/Core2/Matomo/proguard-rules.pro
new file mode 100644
index 000000000..f1b424510
--- /dev/null
+++ b/Core2/Matomo/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/Core2/Matomo/src/main/java/com/infomaniak/matomo/Matomo.kt b/Core2/Matomo/src/main/java/com/infomaniak/matomo/Matomo.kt
new file mode 100644
index 000000000..ca4ec78b4
--- /dev/null
+++ b/Core2/Matomo/src/main/java/com/infomaniak/matomo/Matomo.kt
@@ -0,0 +1,107 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.matomo
+
+import android.app.Activity
+import android.content.Context
+import android.util.Log
+import org.matomo.sdk.Matomo
+import org.matomo.sdk.Tracker
+import org.matomo.sdk.TrackerBuilder
+import org.matomo.sdk.extra.DownloadTracker
+import org.matomo.sdk.extra.TrackHelper
+
+interface Matomo {
+
+ val Context.tracker: Tracker
+ val siteId: Int
+
+ fun Context.buildTracker(shouldOptOut: Boolean = false): Tracker {
+ return TrackerBuilder(BuildConfig.MATOMO_URL, siteId, "AndroidTracker").build(Matomo.getInstance(this)).also {
+ // Put a tracker on app installs to have statistics on the number of times the app is installed or updated
+ TrackHelper.track().download().identifier(DownloadTracker.Extra.ApkChecksum(this)).with(it)
+ it.isOptOut = shouldOptOut
+ }
+ }
+
+ fun Context.addTrackingCallbackForDebugLog() {
+ if (BuildConfig.DEBUG) {
+ tracker.addTrackingCallback { trackMe ->
+ trackMe.also {
+ it.toMap().forEach { entry ->
+ when (entry.key) {
+ "action_name" -> Log.d("TrackerScreen", entry.value)
+ "e_c" -> Log.d("TrackerEvent", "Category : ${entry.value}")
+ "e_n" -> Log.d("TrackerEvent", "Name : ${entry.value}")
+ "e_a" -> Log.d("TrackerEvent", "Action : ${entry.value}")
+ "e_v" -> Log.d("TrackerEvent", "Value : ${entry.value}")
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fun Context.trackUserId(userId: Int) {
+ tracker.userId = userId.toString()
+ }
+
+ //region Track screens
+ fun Activity.trackScreen() {
+ TrackHelper.track().screen(this).title(this::class.java.simpleName).with(tracker)
+ }
+
+ fun Context.trackScreen(path: String, title: String) {
+ TrackHelper.track().screen(path).title(title).with(tracker)
+ }
+ //endregion
+
+ //region Track events
+ fun Context.trackEvent(category: String, name: String, action: TrackerAction = TrackerAction.CLICK, value: Float? = null) {
+ TrackHelper.track()
+ .event(category, action.toString())
+ .name(name)
+ .let { if (value != null) it.value(value) else it }
+ .with(tracker)
+ }
+
+ fun Context.trackAccountEvent(name: String, action: TrackerAction = TrackerAction.CLICK, value: Float? = null) {
+ trackEvent("account", name, action, value)
+ }
+ //endregion
+
+ fun Boolean.toFloat() = if (this) 1.0f else 0.0f
+
+ fun shouldOptOut(context: Context, shouldOptOut: Boolean) {
+ context.tracker.isOptOut = shouldOptOut
+ }
+
+ enum class TrackerAction {
+ CLICK,
+ DATA,
+ DRAG,
+ INPUT,
+ LONG_PRESS;
+
+ override fun toString() = name.lowercase().snakeToCamelCase()
+
+ private fun String.snakeToCamelCase(): String {
+ return replace("_[a-zA-Z]".toRegex()) { it.value.replace("_", "").uppercase() }
+ }
+ }
+}
diff --git a/Core2/gradle/core2.versions.toml b/Core2/gradle/core2.versions.toml
index d11dbef7c..1738542a1 100644
--- a/Core2/gradle/core2.versions.toml
+++ b/Core2/gradle/core2.versions.toml
@@ -1,5 +1,7 @@
[versions]
sentry-android = "7.15.0"
+matomo = "4.1.4"
[libraries]
sentry-android = { module = "io.sentry:sentry-android", version.ref = "sentry-android" }
+matomo = { module = "com.github.matomo-org:matomo-sdk-android", version.ref = "matomo" }
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 750d67140..b10844a1f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -82,6 +82,7 @@ sentry {
dependencies {
implementation(project(":Core2"))
implementation(project(":Core2:Sentry"))
+ implementation(project(":Core2:Matomo"))
implementation(project(":FileTypes"))
implementation(kotlin("reflect"))
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt
index 25df5f2ec..c2145d13b 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/MainActivity.kt
@@ -28,6 +28,7 @@ import androidx.compose.runtime.getValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.infomaniak.multiplatform_swisstransfer.common.models.Theme
+import com.infomaniak.swisstransfer.ui.MatomoSwissTransfer.trackScreen
import com.infomaniak.swisstransfer.ui.screen.main.MainScreen
import com.infomaniak.swisstransfer.ui.screen.main.settings.SettingsViewModel
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
@@ -48,6 +49,7 @@ class MainActivity : ComponentActivity() {
MainScreen()
}
}
+ trackScreen()
}
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/MatomoSwissTransfer.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/MatomoSwissTransfer.kt
new file mode 100644
index 000000000..9da166052
--- /dev/null
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/MatomoSwissTransfer.kt
@@ -0,0 +1,28 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.swisstransfer.ui
+
+import android.content.Context
+import com.infomaniak.matomo.Matomo
+import org.matomo.sdk.Tracker
+
+object MatomoSwissTransfer : Matomo {
+
+ override val Context.tracker: Tracker get() = (this as MainActivity).buildTracker() //TODO fetch appSettings for opt out
+ override val siteId: Int = -1 //TODO replace with the right site ID when we have one
+}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/NewTransferActivity.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/NewTransferActivity.kt
index 7621d7333..97c971267 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/NewTransferActivity.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/NewTransferActivity.kt
@@ -21,6 +21,7 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import com.infomaniak.swisstransfer.ui.MatomoSwissTransfer.trackScreen
import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferScreen
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import dagger.hilt.android.AndroidEntryPoint
@@ -36,5 +37,6 @@ class NewTransferActivity : ComponentActivity() {
NewTransferScreen(closeActivity = { finish() })
}
}
+ trackScreen()
}
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4a8de3dc0..8c3abc6e3 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -31,4 +31,5 @@ rootProject.name = "android-SwissTransfer"
include(":app")
include(":Core2")
include(":Core2:Sentry")
+include(":Core2:Matomo")
include(":FileTypes")