Skip to content

Commit caaf064

Browse files
committed
Add anti uninstall for user apps (#155)
You must be using Shizuku for now
1 parent b22fb08 commit caaf064

10 files changed

Lines changed: 1370 additions & 215 deletions

File tree

app/src/main/java/dev/pranav/applock/core/navigation/AppNavigator.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import androidx.navigation.compose.composable
1717
import dev.pranav.applock.AppLockApplication
1818
import dev.pranav.applock.core.utils.LogUtils
1919
import dev.pranav.applock.data.repository.PreferencesRepository
20+
import dev.pranav.applock.features.antiuninstall.ui.AntiUninstallScreen
2021
import dev.pranav.applock.features.appintro.ui.AppIntroScreen
2122
import dev.pranav.applock.features.applist.ui.MainScreen
2223
import dev.pranav.applock.features.lockscreen.ui.PasswordOverlayScreen
@@ -109,6 +110,10 @@ fun AppNavHost(navController: NavHostController, startDestination: String) {
109110
composable(Screen.TriggerExclusions.route) {
110111
TriggerExclusionsScreen(navController)
111112
}
113+
114+
composable(Screen.AntiUninstall.route) {
115+
AntiUninstallScreen(navController)
116+
}
112117
}
113118
}
114119

app/src/main/java/dev/pranav/applock/core/navigation/Screen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ sealed class Screen(val route: String) {
99
object PasswordOverlay : Screen("password_overlay")
1010
object Settings : Screen("settings")
1111
object TriggerExclusions : Screen("trigger_exclusions")
12+
object AntiUninstall: Screen("anti_uninstall")
1213
}
13-
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package dev.pranav.applock.core.utils
2+
3+
import android.os.Process
4+
import rikka.shizuku.ShizukuBinderWrapper
5+
import rikka.shizuku.SystemServiceHelper
6+
7+
val pm = SystemServiceHelper.getSystemService("package")
8+
.let(::ShizukuBinderWrapper)
9+
.let(android.content.pm.IPackageManager.Stub::asInterface)
10+
11+
fun blockUninstallForUser(packageName: String) {
12+
pm.setBlockUninstallForUser(packageName, true, Process.myUserHandle().describeContents())
13+
}
14+
15+
fun unblockUninstallForUser(packageName: String) {
16+
pm.setBlockUninstallForUser(packageName, false, Process.myUserHandle().describeContents())
17+
}

app/src/main/java/dev/pranav/applock/data/repository/AppLockRepository.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ class AppLockRepository(private val context: Context) {
3030
fun isAppTriggerExcluded(packageName: String): Boolean =
3131
lockedAppsRepository.isAppTriggerExcluded(packageName)
3232

33+
fun getAntiUninstallApps(): Set<String> = lockedAppsRepository.getAntiUninstallApps()
34+
fun addAntiUninstallApp(packageName: String) =
35+
lockedAppsRepository.addAntiUninstallApp(packageName)
36+
37+
fun removeAntiUninstallApp(packageName: String) =
38+
lockedAppsRepository.removeAntiUninstallApp(packageName)
39+
40+
fun isAppAntiUninstall(packageName: String): Boolean =
41+
lockedAppsRepository.isAppAntiUninstall(packageName)
42+
3343
fun getPassword(): String? = preferencesRepository.getPassword()
3444
fun setPassword(password: String) = preferencesRepository.setPassword(password)
3545
fun validatePassword(inputPassword: String): Boolean =

app/src/main/java/dev/pranav/applock/data/repository/LockedAppsRepository.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,30 @@ class LockedAppsRepository(context: Context) {
6262
preferences.edit { putStringSet(KEY_TRIGGER_EXCLUDED_APPS, emptySet()) }
6363
}
6464

65+
// Anti-Uninstall Apps Management
66+
fun getAntiUninstallApps(): Set<String> {
67+
return preferences.getStringSet(KEY_ANTI_UNINSTALL_APPS, emptySet())?.toSet() ?: emptySet()
68+
}
69+
70+
fun addAntiUninstallApp(packageName: String) {
71+
if (packageName.isBlank()) return
72+
val updated = getAntiUninstallApps() + packageName
73+
preferences.edit { putStringSet(KEY_ANTI_UNINSTALL_APPS, updated) }
74+
}
75+
76+
fun removeAntiUninstallApp(packageName: String) {
77+
val updated = getAntiUninstallApps() - packageName
78+
preferences.edit { putStringSet(KEY_ANTI_UNINSTALL_APPS, updated) }
79+
}
80+
81+
fun isAppAntiUninstall(packageName: String): Boolean {
82+
return getAntiUninstallApps().contains(packageName)
83+
}
84+
85+
fun clearAllAntiUninstallApps() {
86+
preferences.edit { putStringSet(KEY_ANTI_UNINSTALL_APPS, emptySet()) }
87+
}
88+
6589
// Bulk operations
6690
fun addMultipleLockedApps(packageNames: Set<String>) {
6791
val validPackageNames = packageNames.filter { it.isNotBlank() }.toSet()
@@ -79,5 +103,6 @@ class LockedAppsRepository(context: Context) {
79103
private const val PREFS_NAME = "app_lock_prefs"
80104
private const val KEY_LOCKED_APPS = "locked_apps"
81105
private const val KEY_TRIGGER_EXCLUDED_APPS = "trigger_excluded_apps"
106+
private const val KEY_ANTI_UNINSTALL_APPS = "anti_uninstall_apps"
82107
}
83108
}

0 commit comments

Comments
 (0)