DEV Community

Weavri
Weavri

Posted on

Getting the Current Foreground App on Android Without Root (AccessibilityService)

If you need to know which app the user is looking at right now — for a focus timer, a parental-control tool, an anti-distraction app — you hit the same wall at step one: how do you get the current foreground app without root?

I shipped a tool that does exactly this, and this post is the part I wish someone had written for me.

The obvious options, and why they all fail

Approach Verdict
ActivityManager.getRunningTasks() Deprecated since Android 5.0. Returns only your own task.
getRunningAppProcesses() Returns only your own process (Android 8+).
UsageStatsManager ("Usage access") Works, but latency is up to ~10 minutes. Useless for real-time.
AccessibilityService TYPE_WINDOW_STATE_CHANGED fires the instant the window changes. ✅

AccessibilityService is the only real-time, no-root option.

The price: the user must enable the service manually (Settings → Accessibility). There is no legitimate way to toggle it programmatically, and you shouldn't try — that's a Play-policy landmine.

Minimal working implementation

class WarnService : AccessibilityService() {

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
        if (event?.eventType != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) return

        val pkg = event.packageName?.toString() ?: return
        if (pkg == packageName) return   // ignore our own windows

        checkAndWarn(pkg)
    }

    override fun onInterrupt() {}
}
Enter fullscreen mode Exit fullscreen mode

The manifest — every attribute matters here:

<service
    android:name=".WarnService"
    android:exported="true"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_config" />
</service>
Enter fullscreen mode Exit fullscreen mode

And res/xml/accessibility_config.xml:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="100" />
Enter fullscreen mode Exit fullscreen mode

Four pitfalls that actually bit me

  1. Use TYPE_WINDOW_STATE_CHANGED, not TYPE_WINDOW_CONTENT_CHANGED. The latter fires on every content update — your battery graph will look like a ski slope.

  2. Guard against self-triggering. When your own warning overlay appears, that's also a window-state change. Filter out your own package name or you get an infinite loop.

  3. Throttle. A 30-second cooldown after each warning. Without it, a user who is genuinely distracted gets spammed and uninstalls.

  4. Don't try to block. Blocking an app launch requires root. "Detect + notify" is the correct no-root design — and it keeps you on the right side of Play policy.

What I built with it

WiFi Beacon (wifiwarn): you configure a target WiFi SSID + a target app. When the phone is connected to that WiFi and the app opens, it fires a sound, a notification, and a full-screen overlay.

Use cases: a parent policing games on the home WiFi; or self-discipline when you're supposed to be working on the office WiFi.

The whole thing runs locally — no cloud, no data collection, Android 8–15.

Source: github.com/weavrikx/wifiwarn — stars and issues are welcome.


I'm Weavri, an indie Android developer. I test on real hardware (Android 14) and ship reproducible builds.

Top comments (0)