An Android app that listens to every notification on your device and forwards matching ones to user-defined API endpoints β powered by Room, OkHttp, and Jetpack Compose.
- π Real-time interception β listens to all device notifications via
NotificationListenerService - π Rule-based routing β match notifications by package name and forward them to different API endpoints
- π Flexible API calls β supports
POST,GET,PUT,PATCH, andDELETEwith custom headers - πΎ Persistent rules β rules saved locally with Room database (survives app restarts)
- π§ͺ Built-in test tool β send a dummy notification to validate your rules without a real app
- π¨ Premium dark UI β built with Jetpack Compose + Material 3
com.karuhundeveloper.notification/
β
βββ data/
β βββ local/
β β βββ entity/ InterceptRule.kt β Room @Entity
β β βββ dao/ InterceptRuleDao.kt β CRUD + Flow
β β βββ converter/ Converters.kt β List/Map TypeConverters
β β βββ AppDatabase.kt β Room singleton
β βββ model/
β βββ NotificationPayload.kt β API request body
β
βββ network/
β βββ NotificationPusher.kt β OkHttp call builder
β βββ PushResult.kt β Sealed result type
β
βββ service/
β βββ AppNotificationListener.kt β NotificationListenerService
β
βββ ui/
βββ theme/ Theme.kt β Material3 dark theme
βββ component/ MethodBadge.kt β Shared composables
βββ screen/
β βββ MainScreen.kt β Rules list
β βββ AddRuleScreen.kt β Add/create rule form
βββ viewmodel/ RulesViewModel.kt β AndroidViewModel
βββ MainActivity.kt β NavHost entry point
| Layer | Library | Version |
|---|---|---|
| UI | Jetpack Compose + Material 3 | BOM 2024.09.00 |
| Navigation | Navigation Compose | 2.8.1 |
| ViewModel | Lifecycle ViewModel Compose | 2.8.6 |
| Database | Room | 2.6.1 |
| Networking | OkHttp | 4.12.0 |
| JSON | Gson | 2.10.1 |
| Min SDK | 24 (Android 7.0) | |
| Target SDK | 36 | |
| Language | Kotlin 2.0.21 + KSP |
- Android Studio Hedgehog (2023.1.1) or newer
- JDK 11
- Android device or emulator running API 24+
# Clone the repo
git clone https://github.com/your-username/NotificationInterceptor.git
cd NotificationInterceptor
# Open in Android Studio and let Gradle sync, or build from CLI:
./gradlew assembleDebug
# Install on connected device
./gradlew installDebugThe app requires two special permissions that must be granted manually by the user.
The app will show a red warning banner on the main screen if this is not granted.
- Tap the Grant button in the banner, or go to: Settings β Apps β Special app access β Notification access
- Find Notification Interceptor and toggle it ON
- Return to the app β the banner disappears automatically
On Android 13+ (API 33), the app will prompt for this permission the first time you tap Send Dummy.
-
Tap οΌ Add Rule on the main screen
-
Fill in the fields:
Field Example Notes Rule Name WhatsApp β SlackHuman-readable label Target Apps com.whatsapp, com.telegram.messengerComma-separated package names API URL https://hooks.slack.com/services/β¦Must start with http://orhttps://HTTP Method POSTChoose from GET / POST / PUT / PATCH / DELETE Custom Headers {"Authorization": "Bearer xyz"}Optional flat JSON object -
Tap Save β the rule appears in the list immediately
- Create a rule with Target Apps set to this app's own package name:
com.karuhundeveloper.notification - Tap Send Dummy on the main screen
- The service intercepts the notification and calls your API
- Check Logcat (tag:
AppNotificationListener) to see the push result
Every matched notification is forwarded as a JSON body:
{
"app_name": "WhatsApp",
"notification_title": "John Doe",
"notification_text": "Hey, are you free tonight?",
"timestamp_ms": 1720432800000
}For GET requests, the same fields are sent as URL query parameters instead of a body.
Custom headers from the rule (e.g. Authorization, X-Source) are attached to every request.
@Entity(tableName = "intercept_rules")
data class InterceptRule(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val ruleName: String,
val targetApps: List<String>, // stored as JSON array
val apiUrl: String,
val apiMethod: String, // "POST", "GET", etc.
val customHeaders: Map<String, String> // stored as JSON object
)NotificationPusher.push() returns a sealed PushResult β no exceptions propagate to the caller:
when (result) {
is PushResult.Success -> // HTTP 2xx β
is PushResult.HttpError -> // HTTP 4xx / 5xx β οΈ
is PushResult.NetworkError -> // No connectivity / timeout β
is PushResult.UnsupportedMethod -> // Unknown HTTP method β
}Filter in Android Studio by tag to see real-time pipeline activity:
tag:AppNotificationListener
| Emoji | Meaning |
|---|---|
| β | Notification successfully delivered to API |
| Server returned a non-2xx status | |
| β | Network failure or unsupported method |
- Rule enable/disable toggle
- Edit existing rules
- Per-rule push history and success rate counter
- Retry with exponential backoff
- Hilt dependency injection
- Rule import / export (JSON file)
- Filter by notification title / body keyword (regex support)
- Webhook test ping from rule card
Pull requests are welcome! For major changes, please open an issue first to discuss what you'd like to change.
MIT License β Copyright (c) 2026 karuhundeveloper
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

