screen_lock_plugin 0.0.3
screen_lock_plugin: ^0.0.3 copied to clipboard
A Flutter plugin that allows you to lock the Android device screen programmatically using Device Admin permissions.
Screen Lock Plugin #
A Flutter plugin that allows you to programmatically lock the Android device screen.
Features #
- Lock the device screen programmatically
- Check device admin permission status
- Request device admin permissions
- Check current screen state (
isScreenOn) - Stream screen on/off events (
onScreenStateChanged) from a dedicated foreground service so events keep firing while the app is backgrounded - Multi-source screen-state detection (broadcast +
DisplayManager+PowerManagerpolling fallback), de-duplicated into a single stream - Adaptive foreground service type:
systemExemptedfor device-owner kiosks,specialUseotherwise - Simple and easy-to-use API
Platform Support #
| Platform | Supported |
|---|---|
| Android | ✅ |
| iOS | ❌ |
| Web | ❌ |
| Windows | ❌ |
| macOS | ❌ |
| Linux | ❌ |
Android Setup #
No additional manifest setup is required. The plugin automatically configures the necessary permissions, the device admin receiver, and the ScreenEventService foreground service used to deliver screen on/off events.
Notification permission (Android 13+) #
While onScreenStateChanged() has an active listener, the plugin starts a foreground service that posts a persistent low-importance notification ("Screen monitor active"). The service still runs if the user denies POST_NOTIFICATIONS, but the notification will be suppressed. To make the service visible and to match user expectations, request the notification permission from your app before subscribing, for example with permission_handler:
import 'package:permission_handler/permission_handler.dart';
await Permission.notification.request();
Usage #
Import the package #
import 'package:screen_lock_plugin/screen_lock_plugin.dart';
Create an instance #
final screenLockPlugin = ScreenLockPlugin();
Check if device admin is enabled #
bool? isEnabled = await screenLockPlugin.isDeviceAdminEnabled();
if (isEnabled == true) {
print('Device admin is enabled');
} else {
print('Device admin is not enabled');
}
Request device admin permissions #
await screenLockPlugin.requestDeviceAdmin();
This will show a system dialog asking the user to grant device admin permissions to your app.
Lock the screen #
bool? result = await screenLockPlugin.lockScreen();
if (result == true) {
print('Screen locked successfully');
} else {
print('Failed to lock screen. Device admin may not be enabled.');
}
Check the current screen state #
bool? isOn = await screenLockPlugin.isScreenOn();
print('Screen is currently ${isOn == true ? "ON" : "OFF"}');
Listen for screen on/off events #
final subscription = screenLockPlugin.onScreenStateChanged().listen(
(event) {
// event is either 'SCREEN_ON' or 'SCREEN_OFF'
print('Screen event: $event');
},
onError: (Object error) {
// e.g. 'FGS_START_FAILED' if the foreground service could not start
print('Screen event error: $error');
},
);
// Later, when you no longer need events:
await subscription.cancel();
The first active listener starts ScreenEventService as a foreground service and shows an ongoing notification. When the last listener is cancelled, the service is stopped.
How It Works #
This plugin uses Android's DevicePolicyManager API to lock the screen and a dedicated foreground service to monitor the display state. Here's what happens:
-
Device Admin Permissions: The app must be registered as a device administrator to lock the screen. This is a security requirement by Android.
-
User Consent: Users must explicitly grant device admin permissions through a system dialog. This cannot be done automatically.
-
Screen Lock: Once permissions are granted, the plugin can lock the screen immediately using
DevicePolicyManager.lockNow(). -
Screen Event Monitoring: While a Dart listener is attached to
onScreenStateChanged(), the plugin runsScreenEventServiceas a foreground service. It combines three independent signals and emits only real transitions:ACTION_SCREEN_ON/ACTION_SCREEN_OFFbroadcastsDisplayManager.DisplayListenerstate changes (catches AOD / doze transitions that do not broadcast on some OEMs)- A periodic
PowerManager.isInteractivepoll as a safety net against broadcast throttling
-
Adaptive Foreground Service Type (Android 14+): If the app is provisioned as the device owner, the service starts with
FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTEDfor the broadest kiosk exemption. Otherwise it usesFOREGROUND_SERVICE_TYPE_SPECIAL_USE, backed by thePROPERTY_SPECIAL_USE_FGS_SUBTYPEdeclared in the manifest.
Important Notes #
-
User Permission Required: Users must manually grant device admin permissions. This is a security feature and cannot be bypassed.
-
Revoking Permissions: Users can revoke device admin permissions at any time through:
- Settings → Security → Device administrators
-
Uninstalling: If users want to uninstall your app, they must first disable device admin permissions in Settings.
-
Best Practices:
- Always check if device admin is enabled before attempting to lock the screen
- Provide clear UI feedback about permission status
- Explain why your app needs this permission
Permissions #
The plugin automatically adds the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
BIND_DEVICE_ADMIN— required to lock the screen viaDevicePolicyManager.FOREGROUND_SERVICE(+ theSPECIAL_USE/SYSTEM_EXEMPTEDsubtypes) — required to runScreenEventServiceso screen events are delivered reliably in the background.POST_NOTIFICATIONS— runtime permission on Android 13+ for the service's ongoing notification. The service still runs if denied, but the notification is suppressed.
Troubleshooting #
Screen doesn't lock when button is pressed #
- Verify device admin is enabled by checking
isDeviceAdminEnabled() - If not enabled, call
requestDeviceAdmin()to prompt the user
App won't uninstall #
- Users must disable device admin permissions before uninstalling
- Go to Settings → Security → Device administrators → Disable your app
onScreenStateChanged() never emits events #
- Make sure a listener is attached — the foreground service only starts while a subscription is active.
- Check the system logs for
ScreenLockPlugin/ScreenEventServicetags. Startup failures are logged there and are also surfaced on the stream as an error with codeFGS_START_FAILED. - On Android 13+, grant
POST_NOTIFICATIONSso you can see the "Screen monitor active" notification and confirm the service is running. - Some OEMs aggressively restrict background execution. Provisioning the app as a device owner (kiosk) lets the service use
FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTEDand bypass most of those restrictions.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
Support #
If you encounter any issues or have questions, please file an issue on the GitHub repository.
Changelog #
See CHANGELOG.md for a list of changes in each version.