Skip to content

Repository files navigation

⛩ Monk Mode

A distraction blocker for Android that actually takes you offline.

Start a session and every app you haven't explicitly allowed is shut out — it can't be opened, it's cut off the network, and its process is dropped so your contacts see you go offline. No notifications, no "last seen", no temptation. Just focus.

Kotlin · Jetpack Compose · Room · AccessibilityService · VpnService


Why it's different

Most focus apps just hide or nag — the blocked app is still running, still connected, and everyone can still see you online. Monk Mode draws a hard line between two things:

  • Blockedyou can't open the app.
  • Disabled / offline — the app is cut off so other people see you disappear.

It does both, using only public Android APIs (no root, no MDM enrolment required).

Features

  • Allow-list blocking — pick the handful of apps you're allowed during a session; everything else (plus any system apps you choose) is blocked.
  • Can't-open enforcement — an AccessibilityService plus a UsageStats poll bounce any blocked app back to the launcher the instant it's opened.
  • Goes offline — a local VpnService blackhole cuts blocked apps off the network, and their background processes are killed at session start so live connections drop immediately. Contacts see you offline instead of "online / last seen just now".
  • Total silence — Do Not Disturb for the session, plus active clearing of blocked apps' notifications from the shade (DND alone only mutes them).
  • Floating overlay — an always-on-top pill with a live session timer; tap to reveal pause / end controls, drag it around, fling it to an edge to minimise.
  • Pause / resume — briefly step out (lifts DND + network block, freezes the timer) with an automatic re-lock after 2 minutes.
  • Achievements — badges at 5 / 10 / 20 / 40 min, 1 hour, and each hour beyond; an "unlocked" badge pops up over the overlay the moment each milestone is crossed.
  • Color themes — five dark palettes (Amber, Ice, Forest, Crimson, Violet), switchable live from the Theme screen; the overlay follows your choice.
  • Survives reboots — an in-progress session resumes after a restart, continuing from the original start time.

How blocking works

Blocking is layered, so no single point of failure lets an app through:

Layer Mechanism Effect
App launch AccessibilityService + 500 ms UsageStats poll → GLOBAL_ACTION_HOME You can't open it
Network VpnService blackhole (blocked packages routed into an unread tun fd) It can't reach its servers
Live connection ActivityManager.killBackgroundProcesses() at session start / resume You drop offline now, not after a timeout
Notifications NotificationListenerService cancels + sweeps blocked apps' posts Nothing reaches the shade

Honest limitation

Without root or Device Owner (which requires a device with zero accounts — not realistic on a daily driver), Android will not let one app force-stop another. So apps that run a persistent foreground service (e.g. WhatsApp) survive the process kill and go offline via the slower network-cut timeout rather than instantly. Everything else drops offline immediately. This is the ceiling of what's possible with public APIs, and the app is built to hit exactly that ceiling.

Permissions & why each is needed

Permission Why
Display over other apps (SYSTEM_ALERT_WINDOW) The floating timer overlay
Accessibility service Detect and bounce blocked-app launches
Do Not Disturb access Silence all interruptions for the session
Usage access (PACKAGE_USAGE_STATS) Backup foreground-app detection + app list
Notification access Clear blocked apps' notifications from the shade
VPN consent (VpnService) The local network blackhole for blocked apps
Battery unrestricted Keep the services alive under aggressive OEM battery management
KILL_BACKGROUND_PROCESSES Drop blocked apps' live connections for instant offline

Build

Requires JDK 17 and the Android SDK (compileSdk 34, minSdk 29).

# Debug build
./gradlew assembleDebug

# Install debug on a connected device
./gradlew installDebug

Signed release

Create a keystore and a keystore.properties at the project root (both are git-ignored):

storeFile=monkmode-release.jks
storePassword=********
keyAlias=monkmode
keyPassword=********
keytool -genkeypair -v -keystore monkmode-release.jks -alias monkmode \
  -keyalg RSA -keysize 2048 -validity 10000

./gradlew assembleRelease
# → app/build/outputs/apk/release/app-release.apk (minified, shrunk, signed)

If keystore.properties is absent, the release build falls back to debug signing so the project still builds on a fresh checkout.

Project structure

app/src/main/java/com/monkmode/
├── MainActivity.kt              # Compose nav host (+ back handling for sub-screens)
├── MonkModeApp.kt               # Application + in-memory SessionState
├── ui/                          # HomeScreen, pickers, Achievements, Themes, About, theme palettes
├── service/
│   ├── SessionController.kt      # start / stop / pause / resume — the orchestrator
│   ├── MonkModeAccessibilityService.kt
│   ├── SessionTimerService.kt    # foreground timer + backup blocking poll + milestone badges
│   ├── NetworkBlockerService.kt  # VpnService blackhole
│   ├── NotificationBlockerService.kt
│   └── BootReceiver.kt
├── oem/                         # OemStrategy interface (+ Realme/Default stubs)
└── data/                        # Room DB, DAOs, entities

Project knowledge

This repo is maintained with the project-knowledge skill from github.com/YahyaZekry/claude-code-skills — a living .project-knowledge/ folder (stack, schema, systems, roadmap, session log) that keeps AI-assisted sessions up to speed on the project's state instead of one growing doc.

Target device

Primarily developed and tested on a Realme 7 Pro (Realme UI / ColorOS, Android 12). An OemStrategy interface is stubbed in for future OEM-specific behaviour.

License

MIT © 2026 Yahya Zekry

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages