@@ -21,6 +21,7 @@ import androidx.compose.material3.MaterialTheme
2121import androidx.compose.material3.Scaffold
2222import androidx.compose.material3.TopAppBarDefaults
2323import androidx.compose.material3.rememberTopAppBarState
24+ import androidx.compose.runtime.DisposableEffect
2425import androidx.compose.runtime.LaunchedEffect
2526import androidx.compose.runtime.getValue
2627import androidx.compose.runtime.mutableStateOf
@@ -31,6 +32,9 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
3132import androidx.compose.ui.platform.LocalContext
3233import androidx.compose.ui.unit.dp
3334import androidx.core.net.toUri
35+ import androidx.lifecycle.Lifecycle
36+ import androidx.lifecycle.LifecycleEventObserver
37+ import androidx.lifecycle.compose.LocalLifecycleOwner
3438import com.sameerasw.essentials.ui.components.ReusableTopAppBar
3539import com.sameerasw.essentials.ui.theme.EssentialsTheme
3640import com.sameerasw.essentials.utils.HapticFeedbackType
@@ -70,7 +74,8 @@ class FeatureSettingsActivity : ComponentActivity() {
7074 " Snooze system notifications" to " Automatically snooze persistent notifications" ,
7175 " Quick Settings Tiles" to " All available QS tiles" ,
7276 " Pixel IMS" to " Force enable IMS for Pixels" ,
73- " Button remap" to " Remap hardware buttons"
77+ " Button remap" to " Remap hardware buttons" ,
78+ " Screen locked security" to " Protect network settings from lock screen"
7479 )
7580 val description = featureDescriptions[feature] ? : " "
7681 setContent {
@@ -86,6 +91,29 @@ class FeatureSettingsActivity : ComponentActivity() {
8691 }
8792
8893 val viewModel: MainViewModel = viewModel()
94+ val statusBarViewModel: StatusBarIconViewModel = viewModel()
95+ val caffeinateViewModel: CaffeinateViewModel = viewModel()
96+
97+ // Automatic refresh on resume
98+ val lifecycleOwner = LocalLifecycleOwner .current
99+ DisposableEffect (lifecycleOwner) {
100+ val observer = LifecycleEventObserver { _, event ->
101+ if (event == Lifecycle .Event .ON_RESUME ) {
102+ viewModel.check(context)
103+ if (feature == " Statusbar icons" ) {
104+ statusBarViewModel.check(context)
105+ }
106+ if (feature == " Caffeinate" ) {
107+ caffeinateViewModel.check(context)
108+ }
109+ }
110+ }
111+ lifecycleOwner.lifecycle.addObserver(observer)
112+ onDispose {
113+ lifecycleOwner.lifecycle.removeObserver(observer)
114+ }
115+ }
116+
89117 LaunchedEffect (Unit ) {
90118 viewModel.check(context)
91119 }
@@ -118,6 +146,7 @@ class FeatureSettingsActivity : ComponentActivity() {
118146 " Button remap" -> ! isAccessibilityEnabled
119147 " Dynamic night light" -> ! isAccessibilityEnabled || ! isWriteSecureSettingsEnabled
120148 " Snooze system notifications" -> ! isNotificationListenerEnabled
149+ " Screen locked security" -> ! isAccessibilityEnabled || ! isWriteSecureSettingsEnabled || ! viewModel.isDeviceAdminEnabled.value
121150 else -> false
122151 }
123152 showPermissionSheet = hasMissingPermissions
@@ -252,6 +281,44 @@ class FeatureSettingsActivity : ComponentActivity() {
252281 isGranted = isNotificationListenerEnabled
253282 )
254283 )
284+ " Screen locked security" -> listOf (
285+ PermissionItem (
286+ iconRes = R .drawable.rounded_settings_accessibility_24,
287+ title = " Accessibility Service" ,
288+ description = " Required to detect lock screen interactions and dismiss panel" ,
289+ dependentFeatures = PermissionRegistry .getFeatures(" ACCESSIBILITY" ),
290+ actionLabel = " Enable in Settings" ,
291+ action = {
292+ context.startActivity(Intent (Settings .ACTION_ACCESSIBILITY_SETTINGS ))
293+ },
294+ isGranted = isAccessibilityEnabled
295+ ),
296+ PermissionItem (
297+ iconRes = R .drawable.rounded_security_24,
298+ title = " Write Secure Settings" ,
299+ description = " Required to temporarily adjust animation scale for spam prevention" ,
300+ dependentFeatures = PermissionRegistry .getFeatures(" WRITE_SECURE_SETTINGS" ),
301+ actionLabel = " Copy ADB" ,
302+ action = {
303+ val adbCommand = " adb shell pm grant com.sameerasw.essentials android.permission.WRITE_SECURE_SETTINGS"
304+ val clipboard = context.getSystemService(Context .CLIPBOARD_SERVICE ) as ClipboardManager
305+ val clip = ClipData .newPlainText(" adb_command" , adbCommand)
306+ clipboard.setPrimaryClip(clip)
307+ },
308+ isGranted = isWriteSecureSettingsEnabled
309+ ),
310+ PermissionItem (
311+ iconRes = R .drawable.rounded_security_24,
312+ title = " Device Administrator" ,
313+ description = " Required to hard-lock the device (disabling biometrics) on unauthorized access attempts" ,
314+ dependentFeatures = PermissionRegistry .getFeatures(" DEVICE_ADMIN" ),
315+ actionLabel = " Enable Admin" ,
316+ action = {
317+ viewModel.requestDeviceAdmin(context)
318+ },
319+ isGranted = viewModel.isDeviceAdminEnabled.value
320+ )
321+ )
255322 else -> emptyList()
256323 }
257324
@@ -298,20 +365,12 @@ class FeatureSettingsActivity : ComponentActivity() {
298365 )
299366 }
300367 " Statusbar icons" -> {
301- val statusBarViewModel: StatusBarIconViewModel = viewModel()
302- LaunchedEffect (Unit ) {
303- statusBarViewModel.check(context)
304- }
305368 StatusBarIconSettingsUI (
306369 viewModel = statusBarViewModel,
307370 modifier = Modifier .padding(top = 16 .dp)
308371 )
309372 }
310373 " Caffeinate" -> {
311- val caffeinateViewModel: CaffeinateViewModel = viewModel()
312- LaunchedEffect (Unit ) {
313- caffeinateViewModel.check(context)
314- }
315374 CaffeinateSettingsUI (
316375 viewModel = caffeinateViewModel,
317376 modifier = Modifier .padding(top = 16 .dp)
@@ -341,6 +400,12 @@ class FeatureSettingsActivity : ComponentActivity() {
341400 modifier = Modifier .padding(top = 16 .dp)
342401 )
343402 }
403+ " Screen locked security" -> {
404+ com.sameerasw.essentials.ui.composables.configs.ScreenLockedSecuritySettingsUI (
405+ viewModel = viewModel,
406+ modifier = Modifier .padding(top = 16 .dp)
407+ )
408+ }
344409 " Quick Settings Tiles" -> {
345410 QuickSettingsTilesSettingsUI (
346411 modifier = Modifier .padding(top = 16 .dp)
0 commit comments