Notification Guard

Notification Guard filters incoming Android notifications against weekday + time-based profiles (night, lunch break, working hours, weekend, custom) and fully custom per-app rules with multiple exception types per rule (keyword or contact). A hardcoded privacy filter ensures that notifications from sensitive app categories — banking, authenticator, medical, public-sector — are always let through without their content ever entering the store.
| Property | Value |
|---|---|
| Platform | Android 7+ (API 24) |
| Stack | Tauri v2 · Rust · Svelte 5 |
| Languages | 7 |
| Repository | git.pronix.org/oiv1Ni3o/notification-guard |
flowchart LR
A[App notifications] --> B[Local capture<br/>on-device only]
B --> C[(Encrypted local storage)]
C --> D[User view]
D --> E[Manual export]
B -.->|never| F[("Cloud / Server")]
style F stroke-dasharray: 5 5,stroke:#c00,color:#c00
What the app does
- 🕒 Weekday + time profiles — Profiles activate by day of week AND time of day. Built-in profiles (night, lunch break, working hours, weekend) plus user-defined profiles. App categories are bundled into profiles — no need to author a rule per app.
- ✏️ Visual rule editor — Add and edit per-app rules in a dedicated editor view. Each rule supports multiple exceptions of two types: by keyword (notification text matches) or by contact (sender / messenger contact).
- 📦 Catalogued top apps — 77 curated app presets across five categories (Social, Games, News, Shopping, Streaming). Filterable by installed apps.
- 🧠 Sub-10 ms rules engine — Rust-based evaluation in under 10 ms per notification. Privacy filter runs first; user rules take priority over profiles; profiles match by weekday and time-of-day. Per-rule exceptions of two types: contact or keyword.
- 🗑️ TTL cleanup — Blocked notifications are deleted automatically after a configurable retention (24 h default). “Clear all” with a tap.
Privacy
Local-only architecture. No server, no account, no tracking, no analytics. The Android manifest declares no internet permission.
What you can expect
- Fully local — all data stays on the device
- No servers, no cloud, no third-party SDKs
- No internet access (manifest contains no
android.permission.INTERNET) - No crash reporters, no analytics, no telemetry
- SQLite database in the app-private storage
- Automatic cleanup of blocked notifications via TTL
- Manual “Clear all” available at any time
Privacy filter — sensitive apps are never blocked
The NotificationListenerService unavoidably sees every notification.
A pre-filter sorts sensitive app categories out BEFORE the rules engine
ever sees them — these notifications never enter the store, and their
content is never persisted.
Protected categories (auto-detected):
- 🏦 Banking — major banks, savings banks, neobanks
- 🔐 Authenticator / 2FA — Google Authenticator, FreeOTP, Aegis, app-specific 2FA flows
- 🏥 Medical — health insurance (TK, AOK, Barmer, …), pharmacy and medication-tracker apps
- 🏛️ Government — federal services, tax authorities (Elster), public-sector identity apps
Regular apps pass through to the rules engine unchanged.
Google Play compliance
Six hard architectural constraints derived from current Google Play policies (Data Safety, Permissions Declaration, Notification Listener). Each one is tracked as a Gitea issue.
| ID | Requirement | Status & implementation |
|---|---|---|
| C1 | Prominent disclosure & consent | ✓ Met — 4-step wizard covering disclosure, profile selection, category selection, permission activation. Clear notes: local, no server, no network. |
| C2 | No SYSTEM_ALERT_WINDOW | ✓ Met — The manifest does not declare the permission. Re-notifications go through NotificationManager. |
| C3 | Data retention TTL | ✓ Met — Configurable retention (24 h default). Periodic cleanup task (Tokio interval, 60 min). “Clear all” button with confirmation dialog. |
| C4 | Contact picker instead of READ_CONTACTS | ○ Planned — Will be added as an optional opt-in module using the Android Contact Picker — no READ_CONTACTS. |
| C5 | Privacy filter (blocklist of sensitive app categories) | ✓ Met — Hardcoded default blocklist as a pre-filter inside the rules engine. First check in evaluate() — match → immediate Pass, no evaluation, no storage. |
| C6 | No network layer | ✓ Met — Manifest verified (aapt dump badging). No HTTP client dependencies in any Cargo.toml. The app runs entirely in airplane mode. |
Declared permissions
Four manifest permissions, each with a concrete functional purpose. No runtime permissions, no restricted special access beyond the core listener.
android.permission.BIND_NOTIFICATION_LISTENER_SERVICE— Core function. Without this permission the app cannot read or filter any notifications. Activated explicitly by the user via system settings.android.permission.RECEIVE_BOOT_COMPLETED— Reconnects the listener service after a device restart. Without it, the app would be blind after every reboot until launched manually.android.permission.WAKE_LOCK— Reliably triggers snooze timers from Doze mode (planned for phase 2).android.permission.POST_NOTIFICATIONS— Surfaces our own re-notifications (released or snoozed) — instead of an overlay window (see C2).
Technology
- Frontend — Svelte 5 (Runes) inside the Tauri WebView, responsive from 360 px, bottom-tab layout on mobile.
- Localization —
svelte-i18nwith OS-locale detection viatauri-plugin-os. Available languages: English, German, French, Spanish, Chinese, Japanese, Korean. - Backend — Rust + Tauri v2 host. Three in-house plugins (Listener, Rules Engine, Store) plus the official Notification and OS plugins.
- Mobile layer — Android Kotlin:
NotificationListenerServicebridges events through the Tauri plugin API into the Rust pipeline. - Database — SQLite via
rusqlite(WAL, foreign keys on). 5 migrations. App-private file, no external access. - Build & signing — Universal APK and AAB (Google Play AAB requirement). Dev builds signed with a local keystore. APK currently ~14 MB.
Architecture highlights
- Plugin isolation — The three in-house plugins (
notif-listener,rules-engine,notif-store) have no cross-dependencies. Communication goes exclusively through the Tauri host as a mediator. - Privacy filter at the pipeline entry — Sensitive apps are filtered out before the rules engine sees them — the content of sensitive notifications is never logged or stored.
- Profiles vs. rules — Beginner UX via predefined profiles + app categories; power-user UX via individual rules in an “advanced” view. Both paths share the same engine.
- Mobile specifics — Custom plugin Android modules with AndroidManifest merging. Permission onboarding handles the Android 13 restricted-settings lockout for sideloaded APKs.
Notification Guard — Repository: git.pronix.org/oiv1Ni3o/notification-guard