diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 1a2b38e6..b258fd49 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -16,6 +16,7 @@ android {
versionName = "v2.0vc$versionCode"
@Suppress("UnstableApiUsage")
androidResources.localeFilters += listOf("en", "ar", "de")
+ manifestPlaceholders["telemetryDeckAppId"] = "613251CD-B223-443A-9583-3A18586FAB55"
}
buildTypes {
release {
@@ -68,5 +69,6 @@ dependencies {
// Third-party
implementation(libs.boehrsi.devicemarketingnames)
+ implementation(libs.telemetrydeck.sdk)
implementation(libs.topjohnwu.libsu.core)
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6fcce9a6..39c3f9d1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,8 @@
+
+
+
diff --git a/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt
new file mode 100644
index 00000000..d40ca068
--- /dev/null
+++ b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt
@@ -0,0 +1,32 @@
+package com.iboalali.basicrootchecker.analytics
+
+import com.telemetrydeck.sdk.TelemetryDeck
+
+object Analytics {
+
+ fun trackNavigation(sourcePath: String, destinationPath: String) {
+ TelemetryDeck.navigate(sourcePath, destinationPath)
+ }
+
+ fun trackRootCheckStarted() {
+ TelemetryDeck.signal("rootCheckStarted")
+ }
+
+ fun trackPrivacyPolicyClicked() {
+ TelemetryDeck.signal("privacyPolicyClicked")
+ }
+
+ fun trackOtherAppClicked(packageName: String) {
+ TelemetryDeck.signal(
+ "otherAppClicked",
+ mapOf("packageName" to packageName),
+ )
+ }
+
+ fun trackRootCheckResult(result: String) {
+ TelemetryDeck.signal(
+ "rootCheckCompleted",
+ mapOf("result" to result),
+ )
+ }
+}
diff --git a/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt b/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt
index c66c8b78..438bfc4b 100644
--- a/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt
+++ b/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt
@@ -12,6 +12,7 @@ import androidx.compose.runtime.remember
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.ui.NavDisplay
+import com.iboalali.basicrootchecker.analytics.Analytics
import com.iboalali.basicrootchecker.ui.about.AboutScreen
import com.iboalali.basicrootchecker.ui.licence.LicenceScreen
import com.iboalali.basicrootchecker.ui.main.MainScreen
@@ -47,20 +48,32 @@ fun AppNavigation() {
entryProvider = entryProvider {
entry {
MainScreen(
- onNavigateToAbout = { backStack.add(AboutRoute) },
- onNavigateToLicence = { backStack.add(LicenceRoute) },
+ onNavigateToAbout = {
+ Analytics.trackNavigation("/main", "/about")
+ backStack.add(AboutRoute)
+ },
+ onNavigateToLicence = {
+ Analytics.trackNavigation("/main", "/licence")
+ backStack.add(LicenceRoute)
+ },
)
}
entry {
AboutScreen(
- onNavigateBack = { backStack.removeLastOrNull() },
+ onNavigateBack = {
+ Analytics.trackNavigation("/about", "/main")
+ backStack.removeLastOrNull()
+ },
)
}
entry {
LicenceScreen(
- onNavigateBack = { backStack.removeLastOrNull() },
+ onNavigateBack = {
+ Analytics.trackNavigation("/licence", "/main")
+ backStack.removeLastOrNull()
+ },
)
}
},
diff --git a/app/src/main/java/com/iboalali/basicrootchecker/ui/about/OtherAppsCard.kt b/app/src/main/java/com/iboalali/basicrootchecker/ui/about/OtherAppsCard.kt
index 44f92f46..1795ada6 100644
--- a/app/src/main/java/com/iboalali/basicrootchecker/ui/about/OtherAppsCard.kt
+++ b/app/src/main/java/com/iboalali/basicrootchecker/ui/about/OtherAppsCard.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.iboalali.basicrootchecker.R
+import com.iboalali.basicrootchecker.analytics.Analytics
import com.iboalali.basicrootchecker.ui.theme.BasicRootCheckerTheme
import com.iboalali.basicrootchecker.util.PreviewLocales
import androidx.core.net.toUri
@@ -74,7 +75,10 @@ fun OtherAppsCard(
filteredApps.forEach { app ->
OtherAppItem(
app = app,
- onClick = { openPlayStoreListing(context, app.packageName) },
+ onClick = {
+ Analytics.trackOtherAppClicked(app.packageName)
+ openPlayStoreListing(context, app.packageName)
+ },
)
}
}
diff --git a/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainScreen.kt b/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainScreen.kt
index 594e765a..cf60b581 100644
--- a/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainScreen.kt
+++ b/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainScreen.kt
@@ -3,6 +3,7 @@ package com.iboalali.basicrootchecker.ui.main
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
+import android.content.Intent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
@@ -72,7 +73,9 @@ import androidx.compose.ui.tooling.preview.PreviewScreenSizes
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
+import androidx.core.net.toUri
import com.iboalali.basicrootchecker.R
+import com.iboalali.basicrootchecker.analytics.Analytics
import com.iboalali.basicrootchecker.ui.theme.BasicRootCheckerTheme
import com.iboalali.basicrootchecker.util.PreviewLocales
import kotlinx.coroutines.launch
@@ -101,6 +104,7 @@ fun MainScreenContent(
onNavigateToAbout: () -> Unit,
onNavigateToLicence: () -> Unit,
) {
+ val context = LocalContext.current
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
var menuExpanded by remember { mutableStateOf(false) }
@@ -137,6 +141,19 @@ fun MainScreenContent(
onNavigateToLicence()
},
)
+ DropdownMenuItem(
+ text = { Text(stringResource(R.string.action_privacy_policy)) },
+ onClick = {
+ menuExpanded = false
+ Analytics.trackPrivacyPolicyClicked()
+ context.startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ "https://iboalali.com/app/basic_root_checker/".toUri(),
+ )
+ )
+ },
+ )
DropdownMenuItem(
text = { Text(stringResource(R.string.action_about)) },
onClick = {
diff --git a/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainViewModel.kt b/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainViewModel.kt
index 18c5c167..f763dd46 100644
--- a/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainViewModel.kt
+++ b/app/src/main/java/com/iboalali/basicrootchecker/ui/main/MainViewModel.kt
@@ -5,6 +5,7 @@ import android.os.Build
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.iboalali.basicrootchecker.R
+import com.iboalali.basicrootchecker.analytics.Analytics
import com.iboalali.basicrootchecker.data.RootChecker
import com.iboalali.basicrootchecker.util.DeviceInfo
import de.boehrsi.devicemarketingnames.DeviceMarketingNames
@@ -54,6 +55,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun checkRoot() {
viewModelScope.launch {
_uiState.update { it.copy(rootStatus = RootStatus.CHECKING) }
+ Analytics.trackRootCheckStarted()
val result = RootChecker.checkRoot()
val status = when (result) {
true -> RootStatus.ROOTED
@@ -61,6 +63,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
null -> RootStatus.UNKNOWN
}
_uiState.update { it.copy(rootStatus = status) }
+ Analytics.trackRootCheckResult(status.name)
}
}
}
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 59aa26ac..07bed54d 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -8,6 +8,7 @@
لا يوجد خاصية الـ Root
حقوق
عنا
+ سياسة الخصوصية
حقوق الطبع محفوظ 2026 iboalali\n\n
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 81ea5bef..cc4150ce 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -8,6 +8,7 @@ Diese app erfordert ROOT zugriff, benutzen auf eigener gefahr.\n
Diese app sammelt keine daten oder persönliche informationen.\n\n\n
Kontaktiere mich:
Über
+ Datenschutzerklärung
Lizenzen
Root zugriff vorhanden
Root zugriff konnte nicht ermittelt werden
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e65b0936..3664ba65 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,6 +9,7 @@
Your Device doesn\'t have Root access
Licenses
About
+ Privacy Policy
Android
Your Device
Checking for Root…
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index da34caf5..a1d11ab7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -14,6 +14,7 @@ boehrsi-devicemarketingnames = "1.0.5" # https://github.com/Boehrsi/Dev
google-material = "1.13.0"
kotlinx-collections-immutable = "0.4.0"
kotlinx-serialization-core = "1.10.0"
+telemetrydeck = "6.3.0" # https://github.com/TelemetryDeck/KotlinSDK/releases
topjohnwu-libsu-core = "6.0.0" # https://github.com/topjohnwu/libsu/releases
[libraries]
@@ -35,6 +36,7 @@ boehrsi-devicemarketingnames = { module = "de.boehrsi:devicemarketingnames", ver
google-material = { module = "com.google.android.material:material", version.ref = "google-material" }
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization-core" }
+telemetrydeck-sdk = { module = "com.telemetrydeck:kotlin-sdk", version.ref = "telemetrydeck" }
topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version.ref = "topjohnwu-libsu-core" }
[plugins]