Pocket Mode in Flutter – Proximity Sensor Integration (Android)

By VisioFolio Admin
June 25, 2025
Pocket Mode in Flutter – Proximity Sensor Integration (Android)

📱 Pocket Mode in Flutter – Proximity Sensor Integration (Android)

Use your phone’s proximity sensor in Flutter to detect whether the device is near your pocket, face, or another object. This project demonstrates how to communicate between Flutter and native Android using MethodChannel and control screen behavior using Android’s PROXIMITY_SCREEN_OFF_WAKE_LOCK.

✅ Real-world use cases: screen auto-lock in pockets, ambient interaction, call behavior, gesture control.


🔥 Features

  • ✅ Detect proximity sensor state (near/far)
  • 🔁 Real-time updates from Android to Flutter
  • 🌙 Automatically manage screen wake state
  • 🔗 Uses MethodChannel for Flutter ↔ Android communication
  • 📦 Clean, modular code structure

🏗️ Project Structure

lib/ ├── services/ │ └── proximity_service.dart # Flutter bridge to native Android ├── views/ │ └── home_screen.dart # UI to observe proximity state └── main.dart # Entry point with lifecycle handling

android/ └── MainActivity.kt # Kotlin sensor + wake lock logic


✅ Requirements

  • Flutter SDK
  • Real Android device (proximity sensor required)
  • Kotlin configured in Android module

🚀 Getting Started

1. main.dart – App Entry & Lifecycle Observer

import 'package:flutter/material.dart';
import 'package:pocket_mode/services/proximity_service.dart';
import 'package:pocket_mode/views/home_screen.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget with WidgetsBindingObserver {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pocket Mode',
      home: const HomeScreen(),
    );
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.detached) {
      ProximityService.stopListening();
    }
  }
}

2. home_screen.dart – UI to Observe Proximity

import 'package:flutter/material.dart';
import 'package:pocket_mode/services/proximity_service.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  void initState() {
    super.initState();
    ProximityService.startListening((isNear) {
      debugPrint('isNear: $isNear');
    });
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: Text('Pocket Mode (Proximity Sensor)')),
    );
  }
}

###. 3. proximity_service.dart – Flutter ↔ Android Communication

import 'package:flutter/services.dart';

class ProximityService {
  static const _channel = MethodChannel('pocket_mode');

  static Future<void> startListening(Function(bool isNear) onChange) async {
    _channel.setMethodCallHandler((call) async {
      if (call.method == 'onProximityChanged') {
        final bool isNear = call.arguments == true;
        onChange(isNear);
      }
    });

    try {
      await _channel.invokeMethod('startProximity');
    } catch (e) {
      print('Error starting proximity sensor: $e');
    }
  }

  static Future<void> stopListening() async {
    try {
      await _channel.invokeMethod('stopProximity');
    } catch (e) {
      print('Error stopping proximity sensor: $e');
    }
  }
}

4. MainActivity.kt – Native Android Sensor & Wake Lock

package com.example.pocket_mode

import android.content.Context
import android.hardware.*
import android.os.PowerManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity(), SensorEventListener {
    private val CHANNEL = "pocket_mode"
    private val WAKE_LOCK_TAG = "pocket_mode:WakeLock"

    private lateinit var sensorManager: SensorManager
    private var proximitySensor: Sensor? = null
    private var powerManager: PowerManager? = null
    private var wakeLock: PowerManager.WakeLock? = null
    private var methodChannel: MethodChannel? = null

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
        powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
        wakeLock = powerManager?.newWakeLock(
            PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, WAKE_LOCK_TAG
        )

        methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
        methodChannel?.setMethodCallHandler { call, result ->
            when (call.method) {
                "startProximity" -> startProximity(result)
                "stopProximity" -> stopProximity(result)
                else -> result.notImplemented()
            }
        }
    }

    private fun startProximity(result: MethodChannel.Result) {
        proximitySensor?.let {
            sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_NORMAL)
            if (wakeLock?.isHeld == false) wakeLock?.acquire()
            result.success(null)
        } ?: result.error("UNAVAILABLE", "Proximity sensor not available", null)
    }

    private fun stopProximity(result: MethodChannel.Result) {
        sensorManager.unregisterListener(this)
        if (wakeLock?.isHeld == true) wakeLock?.release()
        result.success(null)
    }

    override fun onSensorChanged(event: SensorEvent?) {
        if (event?.sensor?.type != Sensor.TYPE_PROXIMITY) return
        val isNear = event.values[0] < (proximitySensor?.maximumRange ?: 0f)
        methodChannel?.invokeMethod("onProximityChanged", isNear)
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}

🛡 Required Permission

In your AndroidManifest.xml:

<uses-permission android:name="android.permission.WAKE_LOCK" />

🧪 How to Test

  • Deploy the app to a physical Android device (emulator won’t work).

  • Cover the top of your device (where the proximity sensor is).

  • Observe logs in the console:

isNear: true

⚠️ Notes

  • Works only on Android.

  • PROXIMITY_SCREEN_OFF_WAKE_LOCK is deprecated in some Android versions but still functional.

  • iOS doesn't support proximity sensor access via Flutter directly.

🙌 Credits Built with ❤️ using Flutter + native Android integration.

📦 Source Code: GitHub Repository

AI Powered Summary

Too busy to read the full article? Get a quick AI-generated summary below.