From 097251db5710dbe29f16ea010b5faa580bbd480e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:00:56 +0000 Subject: [PATCH 1/6] Add TelemetryDeck SDK integration for privacy-focused analytics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrates TelemetryDeck Kotlin SDK (v6.3.0) using manifest-based auto-initialization. Tracks screen navigation and root check events. The app ID is injected via manifestPlaceholders — replace the placeholder in build.gradle.kts with your TelemetryDeck App ID. https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- app/build.gradle.kts | 2 ++ app/src/main/AndroidManifest.xml | 5 +++++ .../basicrootchecker/analytics/Analytics.kt | 21 +++++++++++++++++++ .../navigation/AppNavigation.kt | 21 +++++++++++++++---- .../basicrootchecker/ui/main/MainViewModel.kt | 3 +++ gradle/libs.versions.toml | 2 ++ 6 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1a2b38e6..1bfaf357 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"] = "YOUR-TELEMETRYDECK-APP-ID" } 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..f49eadef --- /dev/null +++ b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt @@ -0,0 +1,21 @@ +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 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..9bfe3493 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/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/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] From 5344a615d1898de8b207aa45804b154cd0591f17 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:07:14 +0000 Subject: [PATCH 2/6] Add telemetry for other app link clicks in about screen Sends an "otherAppClicked" signal with the package name when a user taps one of the other app links in the OtherAppsCard. https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- .../com/iboalali/basicrootchecker/analytics/Analytics.kt | 7 +++++++ .../iboalali/basicrootchecker/ui/about/OtherAppsCard.kt | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt index f49eadef..c904605f 100644 --- a/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt +++ b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt @@ -12,6 +12,13 @@ object Analytics { TelemetryDeck.signal("rootCheckStarted") } + fun trackOtherAppClicked(packageName: String) { + TelemetryDeck.signal( + "otherAppClicked", + mapOf("packageName" to packageName), + ) + } + fun trackRootCheckResult(result: String) { TelemetryDeck.signal( "rootCheckCompleted", 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) + }, ) } } From c80c551c001c154fc0c13710bfe9479a6f2582d2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:12:39 +0000 Subject: [PATCH 3/6] Use path-style strings for navigation signals Matches TelemetryDeck's recommended convention for navigation funnel visualization in the dashboard. https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- .../iboalali/basicrootchecker/navigation/AppNavigation.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 9bfe3493..438bfc4b 100644 --- a/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt +++ b/app/src/main/java/com/iboalali/basicrootchecker/navigation/AppNavigation.kt @@ -49,11 +49,11 @@ fun AppNavigation() { entry { MainScreen( onNavigateToAbout = { - Analytics.trackNavigation("Main", "About") + Analytics.trackNavigation("/main", "/about") backStack.add(AboutRoute) }, onNavigateToLicence = { - Analytics.trackNavigation("Main", "Licence") + Analytics.trackNavigation("/main", "/licence") backStack.add(LicenceRoute) }, ) @@ -62,7 +62,7 @@ fun AppNavigation() { entry { AboutScreen( onNavigateBack = { - Analytics.trackNavigation("About", "Main") + Analytics.trackNavigation("/about", "/main") backStack.removeLastOrNull() }, ) @@ -71,7 +71,7 @@ fun AppNavigation() { entry { LicenceScreen( onNavigateBack = { - Analytics.trackNavigation("Licence", "Main") + Analytics.trackNavigation("/licence", "/main") backStack.removeLastOrNull() }, ) From b609701104abc148809469bbecf8cb4fc9b4467d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:36:55 +0000 Subject: [PATCH 4/6] Set TelemetryDeck app ID https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1bfaf357..b258fd49 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,7 +16,7 @@ android { versionName = "v2.0vc$versionCode" @Suppress("UnstableApiUsage") androidResources.localeFilters += listOf("en", "ar", "de") - manifestPlaceholders["telemetryDeckAppId"] = "YOUR-TELEMETRYDECK-APP-ID" + manifestPlaceholders["telemetryDeckAppId"] = "613251CD-B223-443A-9583-3A18586FAB55" } buildTypes { release { From a18ba88df9a1e199a7854b4087d05236466f5dcf Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:43:44 +0000 Subject: [PATCH 5/6] Add privacy policy menu item to main screen Opens https://iboalali.com/app/basic_root_checker/ in the browser. String resource added for all three locales (en, ar, de). https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- .../basicrootchecker/ui/main/MainScreen.kt | 15 +++++++++++++++ app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 4 files changed, 18 insertions(+) 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..f313df19 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,6 +73,7 @@ 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.ui.theme.BasicRootCheckerTheme import com.iboalali.basicrootchecker.util.PreviewLocales @@ -101,6 +103,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 +140,18 @@ fun MainScreenContent( onNavigateToLicence() }, ) + DropdownMenuItem( + text = { Text(stringResource(R.string.action_privacy_policy)) }, + onClick = { + menuExpanded = false + 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/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… From 925e66ccb92e4ddca48bee726476295b857f854d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Apr 2026 19:44:55 +0000 Subject: [PATCH 6/6] Add telemetry for privacy policy menu click https://claude.ai/code/session_016VUojgLuQwrpJxB4Wy7VCP --- .../java/com/iboalali/basicrootchecker/analytics/Analytics.kt | 4 ++++ .../java/com/iboalali/basicrootchecker/ui/main/MainScreen.kt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt index c904605f..d40ca068 100644 --- a/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt +++ b/app/src/main/java/com/iboalali/basicrootchecker/analytics/Analytics.kt @@ -12,6 +12,10 @@ object Analytics { TelemetryDeck.signal("rootCheckStarted") } + fun trackPrivacyPolicyClicked() { + TelemetryDeck.signal("privacyPolicyClicked") + } + fun trackOtherAppClicked(packageName: String) { TelemetryDeck.signal( "otherAppClicked", 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 f313df19..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 @@ -75,6 +75,7 @@ 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 @@ -144,6 +145,7 @@ fun MainScreenContent( text = { Text(stringResource(R.string.action_privacy_policy)) }, onClick = { menuExpanded = false + Analytics.trackPrivacyPolicyClicked() context.startActivity( Intent( Intent.ACTION_VIEW,