Skip to content

Commit d8b7740

Browse files
Implement system settings restriction management
Added system settings restriction management to enhance app lock functionality and prevent unauthorized access to sensitive settings.
1 parent 8e3dfa3 commit d8b7740

1 file changed

Lines changed: 165 additions & 6 deletions

File tree

app/src/main/java/dev/pranav/applock/services/AppLockAccessibilityService.kt

Lines changed: 165 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import android.annotation.SuppressLint
66
import android.content.Intent
77
import android.util.Log
88
import android.view.accessibility.AccessibilityEvent
9+
import android.view.accessibility.AccessibilityNodeInfo
910
import android.view.inputmethod.InputMethodManager
1011
import androidx.core.content.getSystemService
1112
import dev.pranav.applock.core.utils.LogUtils
1213
import dev.pranav.applock.core.utils.appLockRepository
14+
import dev.pranav.applock.core.utils.systemSettingsRestrictionManager
1315
import dev.pranav.applock.data.repository.AppLockRepository
1416
import dev.pranav.applock.data.repository.BackendImplementation
1517
import dev.pranav.applock.features.lockscreen.ui.PasswordOverlayActivity
@@ -23,6 +25,11 @@ class AppLockAccessibilityService : AccessibilityService() {
2325
getKeyboardPackageNames()
2426
}
2527

28+
// NEW: System Settings Restriction Manager
29+
private val restrictionManager by lazy {
30+
applicationContext.systemSettingsRestrictionManager()
31+
}
32+
2633
private var lastForegroundPackage = ""
2734

2835
companion object {
@@ -50,7 +57,8 @@ class AppLockAccessibilityService : AccessibilityService() {
5057
eventTypes =
5158
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED or
5259
AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED or
53-
AccessibilityEvent.TYPE_WINDOWS_CHANGED
60+
AccessibilityEvent.TYPE_WINDOWS_CHANGED or
61+
AccessibilityEvent.TYPE_VIEW_CLICKED
5462

5563
feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
5664

@@ -83,7 +91,15 @@ class AppLockAccessibilityService : AccessibilityService() {
8391
val className = event.className?.toString()
8492

8593
/* ---------------------------------------------------------
86-
🔒 Restrict System Settings Access
94+
🔒 NEW: Restrict System Settings Access (Anti-Uninstall)
95+
---------------------------------------------------------- */
96+
97+
if (isSettingsPackage(packageName)) {
98+
handleSettingsPackageOpening(event)
99+
}
100+
101+
/* ---------------------------------------------------------
102+
🔒 ORIGINAL: Restrict System Settings Access
87103
---------------------------------------------------------- */
88104

89105
if (isRestrictedSettings(packageName, className)) {
@@ -103,7 +119,150 @@ class AppLockAccessibilityService : AccessibilityService() {
103119
}
104120

105121
/* ---------------------------------------------------------
106-
SETTINGS PROTECTION
122+
NEW METHODS: SYSTEM SETTINGS RESTRICTION (Anti-Uninstall)
123+
---------------------------------------------------------- */
124+
125+
/**
126+
* Determine if a package is a system settings app.
127+
*/
128+
private fun isSettingsPackage(packageName: String): Boolean {
129+
return packageName in listOf(
130+
"com.android.settings",
131+
"com.sec.android.app.personalpage",
132+
"com.oppo.safe",
133+
"com.vivo.settings",
134+
"com.huawei.systemmanager",
135+
"com.xiaomi.misettings"
136+
)
137+
}
138+
139+
/**
140+
* Handle when settings package is being opened.
141+
* Check if it's trying to access a restricted settings page.
142+
*/
143+
private fun handleSettingsPackageOpening(event: AccessibilityEvent) {
144+
try {
145+
val appLockRepo = applicationContext.appLockRepository()
146+
147+
if (!appLockRepo.isAntiUninstallEnabled()) {
148+
return
149+
}
150+
151+
if (!appLockRepo.hasAnySystemSettingsRestriction()) {
152+
return
153+
}
154+
155+
val sourceNode = event.source ?: return
156+
157+
if (detectRestrictedSettingsActivity(sourceNode, appLockRepo)) {
158+
showLockScreenForRestrictedSettings()
159+
performGlobalAction(GLOBAL_ACTION_HOME)
160+
}
161+
162+
sourceNode.recycle()
163+
} catch (e: Exception) {
164+
LogUtils.logError("Error handling settings package opening", e)
165+
}
166+
}
167+
168+
/**
169+
* Detect if a restricted settings activity is being accessed.
170+
*/
171+
private fun detectRestrictedSettingsActivity(
172+
sourceNode: AccessibilityNodeInfo,
173+
repository: AppLockRepository
174+
): Boolean {
175+
try {
176+
val text = sourceNode.text?.toString() ?: ""
177+
val contentDescription = sourceNode.contentDescription?.toString() ?: ""
178+
179+
return when {
180+
repository.isRestrictDrawOverAppsSettings() &&
181+
(text.contains("overlay", ignoreCase = true) ||
182+
text.contains("draw", ignoreCase = true)) -> {
183+
LogUtils.d(TAG, "Detected restricted Draw Over Apps settings")
184+
true
185+
}
186+
187+
repository.isRestrictUsageAccessSettings() &&
188+
(text.contains("usage", ignoreCase = true) ||
189+
text.contains("data usage", ignoreCase = true)) -> {
190+
LogUtils.d(TAG, "Detected restricted Usage Access settings")
191+
true
192+
}
193+
194+
repository.isRestrictAccessibilitySettings() &&
195+
(text.contains("accessibility", ignoreCase = true) ||
196+
contentDescription.contains("accessibility", ignoreCase = true)) -> {
197+
LogUtils.d(TAG, "Detected restricted Accessibility settings")
198+
true
199+
}
200+
201+
repository.isRestrictDeviceAdminSettings() &&
202+
(text.contains("admin", ignoreCase = true) ||
203+
text.contains("device administrator", ignoreCase = true)) -> {
204+
LogUtils.d(TAG, "Detected restricted Device Admin settings")
205+
true
206+
}
207+
208+
repository.isRequireUnrestrictedBattery() &&
209+
(text.contains("battery", ignoreCase = true) ||
210+
text.contains("power saving", ignoreCase = true)) -> {
211+
LogUtils.d(TAG, "Detected restricted Battery Optimization settings")
212+
true
213+
}
214+
215+
else -> false
216+
}
217+
} catch (e: Exception) {
218+
LogUtils.logError("Error detecting restricted settings activity", e)
219+
return false
220+
}
221+
}
222+
223+
/**
224+
* Create and show the lock screen when user tries to access restricted settings.
225+
*/
226+
private fun showLockScreenForRestrictedSettings() {
227+
try {
228+
if (AppLockManager.isLockScreenShown.get()) return
229+
230+
AppLockManager.isLockScreenShown.set(true)
231+
232+
val lockScreenIntent = Intent(applicationContext, PasswordOverlayActivity::class.java).apply {
233+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
234+
Intent.FLAG_ACTIVITY_CLEAR_TOP or
235+
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
236+
putExtra("isRestrictedSettings", true)
237+
putExtra("locked_package", "com.android.settings")
238+
}
239+
applicationContext.startActivity(lockScreenIntent)
240+
241+
LogUtils.d(TAG, "Showed lock screen for restricted settings")
242+
} catch (e: Exception) {
243+
LogUtils.logError("Failed to show lock screen for restricted settings", e)
244+
}
245+
}
246+
247+
/**
248+
* Optional: Called from broadcast receiver if needed
249+
*/
250+
protected open fun onSettingsIntentIntercepted(action: String) {
251+
try {
252+
val restrictMgr = applicationContext.systemSettingsRestrictionManager()
253+
val intent = Intent(action)
254+
255+
if (restrictMgr.isIntentRestricted(intent)) {
256+
showLockScreenForRestrictedSettings()
257+
LogUtils.d(TAG, "Settings intent intercepted for action: $action")
258+
}
259+
} catch (e: Exception) {
260+
LogUtils.logError("Error in onSettingsIntentIntercepted", e)
261+
}
262+
}
263+
264+
/* ---------------------------------------------------------
265+
ORIGINAL METHODS: SETTINGS PROTECTION
107266
---------------------------------------------------------- */
108267

109268
private fun isRestrictedSettings(pkg: String, cls: String?): Boolean {
@@ -150,7 +309,7 @@ class AppLockAccessibilityService : AccessibilityService() {
150309
}
151310

152311
/* ---------------------------------------------------------
153-
NORMAL APP LOCK LOGIC
312+
ORIGINAL METHODS: NORMAL APP LOCK LOGIC
154313
---------------------------------------------------------- */
155314

156315
private fun processPackageLocking(packageName: String) {
@@ -192,7 +351,7 @@ class AppLockAccessibilityService : AccessibilityService() {
192351
}
193352

194353
/* ---------------------------------------------------------
195-
VALIDATION
354+
ORIGINAL METHODS: VALIDATION
196355
---------------------------------------------------------- */
197356

198357
private fun isValidPackage(packageName: String): Boolean {
@@ -229,7 +388,7 @@ class AppLockAccessibilityService : AccessibilityService() {
229388
}
230389

231390
/* ---------------------------------------------------------
232-
BACKEND CONTROL
391+
ORIGINAL METHODS: BACKEND CONTROL
233392
---------------------------------------------------------- */
234393

235394
private fun startPrimaryBackendService() {

0 commit comments

Comments
 (0)