开发Android系统级设备管理器应用:实现系统设置禁用与变更监控
Hey there! Let's walk through how to build these two security-focused features for your system-level device manager app. Since you're working with a system app, we can leverage Android's built-in device management APIs and system privileges to make this happen:
First off, your app needs to be registered as a Device Owner or Profile Owner—this is a prerequisite for modifying system-level restrictions. Here's how to build the toggle functionality:
Step 1: Set Up Device Admin Components
First, register a DeviceAdminReceiver in your AndroidManifest.xml (this acts as the bridge between your app and Android's device policy system):
<receiver android:name=".MyDeviceAdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_policy" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
Then create the device_admin_policy.xml file in res/xml/ to declare the policies your app needs access to:
<device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <restrict-applications /> <disable-keyguard-features /> <!-- Add any other policies your app requires --> </uses-policies> </device-admin>
Step 2: Build the Toggle Logic
Use the DevicePolicyManager to apply or remove restrictions when the user toggles the feature. You can restrict specific system settings (like WiFi, Bluetooth, display) or even hide the Settings app entirely:
val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager val adminComponent = ComponentName(this, MyDeviceAdminReceiver::class.java) val settingsToggle = findViewById<ToggleButton>(R.id.settings_disable_toggle) settingsToggle.setOnCheckedChangeListener { _, isEnabled -> val restrictedSettings = setOf( UserManager.DISALLOW_CONFIG_WIFI, UserManager.DISALLOW_CONFIG_BLUETOOTH, UserManager.DISALLOW_CONFIG_DISPLAY, UserManager.DISALLOW_CONFIG_LOCATION ) if (isEnabled) { // Apply restrictions restrictedSettings.forEach { restriction -> dpm.addUserRestriction(adminComponent, restriction) } // Optional: Hide the system Settings app entirely dpm.setApplicationHidden(adminComponent, "com.android.settings", true) } else { // Remove restrictions restrictedSettings.forEach { restriction -> dpm.clearUserRestriction(adminComponent, restriction) } dpm.setApplicationHidden(adminComponent, "com.android.settings", false) } }
Even with restrictions in place, it's good to add a monitoring layer as a safety net. We'll use a ContentObserver to watch for changes to system settings and revert them if needed:
Step 1: Create a Custom ContentObserver
This observer will trigger whenever a monitored setting changes:
class SettingsMonitorObserver( handler: Handler, private val contentResolver: ContentResolver, private val isRestrictionActive: () -> Boolean ) : ContentObserver(handler) { override fun onChange(selfChange: Boolean, uri: Uri?) { super.onChange(selfChange, uri) uri ?: return // Only act if the restriction feature is enabled if (!isRestrictionActive()) return when (uri) { // Example: Revert WiFi state if changed Settings.Global.getUriFor(Settings.Global.WIFI_ON) -> { Settings.Global.putInt(contentResolver, Settings.Global.WIFI_ON, 0) } // Example: Revert screen brightness to a preset value Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS) -> { Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, 100) } // Add more settings URIs to monitor as needed } } }
Step 2: Register/Unregister the Observer
Register the observer when the restriction is enabled, and unregister it when it's turned off to save resources:
private lateinit var settingsObserver: SettingsMonitorObserver private val mainHandler = Handler(Looper.getMainLooper()) private var isRestrictionEnabled = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) settingsObserver = SettingsMonitorObserver( mainHandler, contentResolver ) { isRestrictionEnabled } } private fun startMonitoringSettings() { contentResolver.apply { registerContentObserver( Settings.Global.getUriFor(Settings.Global.WIFI_ON), true, settingsObserver ) registerContentObserver( Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), true, settingsObserver ) // Register more URIs here } } private fun stopMonitoringSettings() { contentResolver.unregisterContentObserver(settingsObserver) } // Update this in your toggle's onCheckedChangeListener settingsToggle.setOnCheckedChangeListener { _, isEnabled -> isRestrictionEnabled = isEnabled if (isEnabled) startMonitoringSettings() else stopMonitoringSettings() // ... rest of your restriction logic from earlier ... }
Key Notes for System Apps
- Your app must be installed in
/system/priv-app(privileged system app) and signed with the system's signing key to access these APIs. - For Android 11+, use the
MANAGE_DEVICE_POLICIES_SETTINGSpermission to manage setting restrictions. - Always test across different Android versions—some restriction constants or API behaviors may vary.
内容的提问来源于stack exchange,提问作者ManDev

