Screen Pinning Plugin - Flutter Kiosk Mode & Lock Task Mode

A powerful Flutter plugin for Android screen pinning, kiosk mode, and lock task mode. Perfect for creating dedicated device apps, kiosks, digital signage, point-of-sale (POS) systems, and restricted-access applications. Pin your Flutter app to the screen and prevent users from navigating away.

pub package License: MIT

Features

Screen Pinning - Pin your app to the screen (Android Lock Task mode)
📡 Real-time Monitoring - Event stream for status changes
🔒 Device Owner Detection - Check if app has full lock task capabilities
🎯 Simple API - Easy-to-use helper methods
Minimal Dependencies - Uses wakelock_plus only for keep screen on feature
🔧 Customizable - Full control over UI and behavior
🏢 Dual Mode Support - Works with both managed devices (full admin) and unmanaged devices (user confirmation)
📱 Native Android APIs - Uses Android's built-in app pinning and lock task mode features
💡 Keep Screen On - Prevent device from sleeping with built-in wakelock support
🖥️ Immersive Mode - Hide system UI (status bar, navigation bar) for true fullscreen
🔄 Orientation Lock - Lock device orientation for consistent UX
📸 Screenshot Prevention - Optional screenshot blocking for secure environments
⚙️ Centralized Configuration - Single config object for all features

How It Works

This plugin leverages Android's native App Pinning and Lock Task Mode capabilities:

🔓 Unmanaged Devices (Standard Mode)

  • Uses Android App Pinning (available on all Android 5.0+ devices)
  • Requires user confirmation via system dialog
  • User can exit by holding Back + Recent Apps buttons
  • Perfect for: Public kiosks, retail displays, temporary restrictions
  • No device admin/MDM setup required

🔒 Managed Devices (Full Kiosk Mode)

  • Uses Lock Task Mode with Device Owner/Admin privileges
  • No user confirmation required - automatically locks
  • User cannot exit without app permission
  • Perfect for: Corporate deployments, dedicated devices, MDM-managed tablets
  • Requires device owner setup (ADB or MDM)

The plugin automatically detects device capabilities and uses the appropriate mode!

Use Cases

🏪 Kiosk Applications - Retail displays, information kiosks, self-service terminals
🏥 Healthcare Apps - Patient check-in, medical device apps, hospital kiosks
🎓 Educational Apps - Student testing apps, exam mode, classroom devices
🍔 Point of Sale (POS) - Restaurant ordering, payment terminals, checkout systems
📺 Digital Signage - Public displays, menu boards, information screens
🏭 Industrial Apps - Factory floor tablets, warehouse management, inventory systems
🚗 Vehicle Apps - In-car tablets, fleet management, driver apps
👶 Parental Control - Child-safe devices, restricted access apps
🏢 Corporate Devices - Dedicated employee apps, single-purpose devices

Platform Support

Android iOS

Note: Screen pinning is an Android-only feature. iOS has Guided Access but is not currently supported by this plugin.

Installation

Add this to your pubspec.yaml:

dependencies:
  screen_pinning: ^1.0.0

Or install via command:

flutter pub add screen_pinning

Permissions

The plugin will automatically add required permissions to your Android manifest. No manual configuration needed!

Usage

Basic Usage

import 'package:screen_pinning_plugin/screen_pinning_plugin.dart';

// Initialize the helper
final helper = ScreenPinningHelper();
await helper.initialize();

// Start screen pinning
await helper.startScreenPinning();

// Stop screen pinning
await helper.stopScreenPinning();

// Check if currently pinned
if (helper.isScreenPinningEnabled) {
  print('Screen is pinned!');
}

Advanced Usage with Configuration

import 'package:screen_pinning_plugin/screen_pinning_plugin.dart';

// Create configuration
final config = ScreenPinningConfig(
  keepScreenOn: true,        // Prevent device from sleeping
  immersiveMode: true,       // Hide system UI (status bar, navigation)
  autoStart: true,           // Auto-start screen pinning
  preventScreenshots: false, // Prevent screenshots (optional)
  preferredOrientations: [   // Lock orientation (optional)
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
  ],
);

// Initialize with configuration
final helper = ScreenPinningHelper();
await helper.initialize(config);

// Check status
print('Keep screen on: ${helper.isKeepScreenOnEnabled}');
print('Immersive mode: ${helper.isImmersiveModeEnabled}');
print('Screen pinned: ${helper.isPinned}');

Individual Feature Control

final helper = ScreenPinningHelper();

// Control keep screen on independently
await helper.enableKeepScreenOn();
await helper.disableKeepScreenOn();

// Control immersive mode independently
helper.enableImmersiveMode();
helper.disableImmersiveMode();

// Update configuration dynamically
final newConfig = ScreenPinningConfig(
  keepScreenOn: false,
  immersiveMode: true,
);
await helper.updateConfig(newConfig);

With User Confirmation Dialog

// Show confirmation dialog and start
final confirmed = await ScreenPinningHelper.showConfirmationDialog(context);
if (confirmed) {
  await ScreenPinningHelper().startScreenPinning();
}

Watch Status Changes

// Get real-time updates
ScreenPinningChannel().watchScreenPinningStatus().listen((isPinned) {
  print('Screen pinning status: $isPinned');
  setState(() {}); // Update UI
});

Check Device Capabilities

// Check if app is device owner (for full lock task mode)
final isOwner = await ScreenPinningHelper().isDeviceOwner();
if (isOwner) {
  print('Full lock task mode available');
} else {
  print('Using screen pinning mode (user can exit)');
}

// Check if supported
final isSupported = await ScreenPinningHelper().isSupported();

Complete Example

import 'package:flutter/material.dart';
import 'package:screen_pinning_plugin/screen_pinning_plugin.dart';

class MyScreen extends StatefulWidget {
  @override
  State<MyScreen> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  final helper = ScreenPinningHelper();

  @override
  void initState() {
    super.initState();
    helper.initialize();
  }

  Future<void> toggleScreenPinning() async {
    if (helper.isScreenPinningEnabled) {
      await helper.stopScreenPinning();
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Screen pinning disabled')),
      );
    } else {
      final confirmed = await ScreenPinningHelper.showConfirmationDialog(context);
      if (confirmed) {
        await helper.startScreenPinning();
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Screen pinning enabled')),
        );
      }
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen Pinning Demo'),
        actions: [
          IconButton(
            icon: Icon(
              helper.isScreenPinningEnabled ? Icons.lock : Icons.lock_open,
            ),
            onPressed: toggleScreenPinning,
          ),
        ],
      ),
      body: Center(
        child: Text(
          helper.isScreenPinningEnabled
              ? 'Screen is Pinned'
              : 'Screen is Not Pinned',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
      ),
    );
  }
}

How It Works

Not Device Owner (Default)

When your app is NOT a device owner:

  • Screen pinning mode is used
  • ✅ System shows confirmation dialog to user
  • ✅ User can exit by pressing Back + Recent Apps buttons simultaneously
  • ⚠️ Not a complete "lock" - determined users can exit

Device Owner Mode

When your app IS a device owner:

  • True lock task mode (no user exit)
  • No confirmation dialog required
  • ✅ Only your app or whitelisted apps can run
  • ✅ User cannot exit without app permission

Making Your App a Device Owner

⚠️ Requires factory reset!

# Factory reset device
# Skip Google account during setup
# Enable developer mode and USB debugging

# Run this command:
adb shell dpm set-device-owner com.yourpackage/.YourDeviceAdminReceiver

Note: This requires implementing a DeviceAdminReceiver in your app.

API Reference

ScreenPinningHelper

Main helper class for screen pinning operations.

Methods

  • initialize() - Initialize the plugin and start monitoring
  • startScreenPinning() - Start screen pinning mode
  • stopScreenPinning() - Stop screen pinning mode
  • isSupported() - Check if device supports screen pinning
  • isDeviceOwner() - Check if app is device owner

Properties

  • isScreenPinningEnabled - bool - Current pinning status
  • isPinned - bool - Alias for isScreenPinningEnabled

Static Methods

  • showConfirmationDialog(BuildContext) - Show default confirmation dialog

ScreenPinningChannel

Low-level platform channel interface.

Methods

  • startScreenPinning() - Direct channel call to start pinning
  • stopScreenPinning() - Direct channel call to stop pinning
  • isScreenPinned() - Check current status
  • isScreenPinningSupported() - Check device support
  • watchScreenPinningStatus() - Stream of status changes
  • isDeviceOwner() - Check device owner status

Testing

Testing on Unmanaged Devices (Standard Users)

  1. Run your app on an Android device (no special setup needed)
  2. Call startScreenPinning()
  3. Confirm the system security dialog - user must accept
  4. Try pressing Home button → Shows "Screen pinned" message
  5. Try pressing Recent Apps → Shows "Screen pinned" message
  6. Exit by holding Back + Recent Apps together for 2-3 seconds

Testing on Managed Devices (Device Owner)

  1. Set your app as device owner via ADB:
    adb shell dpm set-device-owner com.yourapp/.DeviceAdminReceiver
    
  2. Call startScreenPinning() - No dialog shown, immediately locks
  3. User cannot exit without app permission
  4. Call stopScreenPinning() to unlock programmatically

Troubleshooting

Screen pinning doesn't start / Kiosk mode not working

  • Ensure user confirmed the system dialog
  • Check Android logs: flutter logs or adb logcat
  • Verify device is API 23+ (Android 6.0+)

Flutter kiosk mode not locking properly

  • User must confirm the system security dialog
  • If device owner, pinning is automatic without dialog
  • Check if REORDER_TASKS permission is in manifest

How to exit screen pinning / kiosk mode

  • Hold Back + Recent Apps buttons together for 2-3 seconds
  • Or call stopScreenPinning() programmatically

Difference between screen pinning and kiosk mode

  • Screen Pinning: User mode - requires confirmation, user can exit
  • Kiosk/Lock Task Mode: Device owner mode - fully locked, no exit without code

Can't exit screen pinning

  • Hold Back + Recent Apps buttons together for 2-3 seconds
  • Or use the in-app stop method
  • If stuck: Restart device

Want full lock task mode?

  • Make your app a device owner (see instructions above)
  • Implement DeviceAdminReceiver
  • Factory reset device and configure via ADB

Technical Details

Architecture

Flutter (Dart)
    ↓
ScreenPinningHelper (High-level API)
    ↓
ScreenPinningChannel (Platform Channel)
    ↓
MethodChannel + EventChannel
    ↓
Native Android (Kotlin)
    ↓
Android Lock Task API

Platform Channels

  • Method Channel: com.vaib.screenpinning/methods
  • Event Channel: com.vaib.screenpinning/events

Android Implementation

Uses Android's Lock Task Mode API:

  • Activity.startLockTask()
  • Activity.stopLockTask()
  • ActivityManager.getLockTaskModeState()

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

# Clone the repository
git clone https://github.com/yourusername/screen_pinning_plugin.git

# Get dependencies
cd screen_pinning_plugin
flutter pub get

# Run example
cd example
flutter run

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

If you find this plugin useful, please consider:

  • ⭐ Starring the repository
  • 🐛 Reporting issues
  • 💡 Suggesting new features
  • 📖 Improving documentation

Changelog

See CHANGELOG.md for version history.

Author

Created by Vaibhav Nayak

Keywords

flutter screen pinning, flutter kiosk mode, flutter lock task mode, android kiosk flutter, flutter dedicated device, flutter pin screen, flutter task lock, android screen pinning flutter, flutter kiosk app, flutter single app mode, flutter app pinning, flutter immersive mode, flutter kiosk browser, flutter restricted access, flutter device owner, flutter full screen lock

Acknowledgments

  • Flutter team for the excellent platform channel documentation
  • Android documentation for Lock Task mode details

Libraries

screen_pinning