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]