Keyword Filtering System
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/fathiraz/flowbell/core/utils/NotificationFilterUtil.kt
- app/src/main/kotlin/com/fathiraz/flowbell/core/utils/FilterDisplayUtil.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt
- app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/apps/AppDetailScreen.kt
- app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/settings/SettingsScreen.kt
- app/src/main/kotlin/com/fathiraz/flowbell/domain/usecases/ManageUserSettingsUseCase.kt
- CHANGELOG.md
The Keyword Filtering System in FlowBell is a core architectural component designed to provide granular control over which device notifications are forwarded to a user's configured webhook. It operates as a "whitelist" mechanism, ensuring that only notifications containing specific, user-defined keywords are processed and transmitted. This system reduces noise and enhances privacy by allowing users to exclude irrelevant or sensitive notifications from being sent to external endpoints.
The system supports two levels of configuration: Global Filtering, which applies across all enabled applications, and Per-App Filtering, which allows for specific keyword lists tailored to individual applications. Per-app filters take precedence over global filters when they are defined.
Sources: CHANGELOG.md:46-51, app/src/main/kotlin/com/fathiraz/flowbell/core/utils/NotificationFilterUtil.kt:7-11
Core Logic and Architecture
The filtering logic is primarily encapsulated in the NotificationFilterUtil object, which provides a stateless utility for evaluating notification content. The system analyzes both the Title and Text of an incoming notification to find matches against a list of active keywords.
Filtering Logic Flow
- Filter Selection: The system first checks if per-app filter words are available for the package that generated the notification. If found, these are used exclusively. If the app has no specific filters, the system falls back to the global filter list.
- Normalization: Both the notification content (Title + Text) and the filter keywords are converted to lowercase to ensure case-insensitive matching. Filter words are also trimmed of whitespace.
- Whitelist Matching: The system performs a partial match search. If any active filter word is found within the notification content, the notification is marked as "allowed."
- Fallback: If no filters are defined at either the app or global level, the notification is allowed by default.
The diagram shows the prioritization of app-specific filters over global filters and the whitelist logic used to decide if a notification proceeds to the webhook.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/core/utils/NotificationFilterUtil.kt:22-60, app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt:182-192
Component Roles
| Component | Responsibility | Relevant Files |
|---|---|---|
NotificationFilterUtil | Contains the core shouldAllowNotification logic and performs string matching. | NotificationFilterUtil.kt |
NotificationListenerService | Intercepts system notifications and invokes the filtering utility before batching for webhooks. | NotificationListenerService.kt |
AppDetailScreen | UI for configuring per-app keyword lists (comma-separated input). | AppDetailScreen.kt |
SettingsScreen | UI for managing global keyword filters and toggling the filtering system on/off. | SettingsScreen.kt |
FilterDisplayUtil | Formats active filters for display in the UI (e.g., limiting to 10 words + count). | FilterDisplayUtil.kt |
ManageUserSettingsUseCase | Handles business logic for persisting filter changes to the repository. | ManageUserSettingsUseCase.kt |
Sources: app/src/main/kotlin/com/fathiraz/flowbell/core/utils/NotificationFilterUtil.kt:11, app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt:182-192, app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/apps/AppDetailScreen.kt:167-200, app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/settings/SettingsScreen.kt:173-200
User Interface and Configuration
The filtering system provides interactive management through the application's Compose-based UI.
Global Filters
In the Settings screen, users can toggle "Advanced Filters" to enable or disable the entire global filtering mechanism. When enabled, users provide a comma-separated list of keywords. The UI displays the count of active words and a formatted preview of the filters currently in effect.
Per-App Filters
In the App Details screen for a specific application, users can configure unique keyword lists. This allows for specific behavior, such as only forwarding "OTP" messages from a messaging app while ignoring other social chats.
Visual Representation of Configuration Flow
The sequence shows how user-provided strings are transformed into persistent filtering configurations.
Sources: app/src/main/kotlin/com/fathiraz/flowbell/presentation/screens/settings/SettingsScreen.kt:181-224, app/src/main/kotlin/com/fathiraz/flowbell/domain/usecases/ManageUserSettingsUseCase.kt:53-73
Technical Implementation Details
Data Formatting
Keywords are managed as List<String>. The FilterDisplayUtil is used to ensure the UI remains clean even with large keyword lists by truncating the display after 10 words.
// Example of filter formatting for UI
fun formatActiveFilters(filters: List<String>): String {
return if (filters.size <= 10) {
filters.joinToString(", ")
} else {
val displayWords = filters.take(10).joinToString(", ")
val remaining = filters.size - 10
"$displayWords +$remaining more"
}
}
Sources: app/src/main/kotlin/com/fathiraz/flowbell/core/utils/FilterDisplayUtil.kt:15-23
Integration with Notification Interception
The NotificationListenerService calls the filter check immediately after validating that the source application itself is enabled for forwarding.
// snippet from NotificationListenerService.kt
val isAppEnabled = appPreferencesRepository.getForwardingStatus(data.packageName)
if (!isAppEnabled) return@launch
val appFilters = appPreferencesRepository.getFilterWords(data.packageName)
val globalFilters = userPreferencesRepository.getGlobalFilterWords()
if (!NotificationFilterUtil.shouldAllowNotification(
data.title, data.text, appFilters, globalFilters
)) {
return@launch // Discarded by filter
}
Sources: app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt:170-192
Conclusion
The Keyword Filtering System provides an essential layer of control within FlowBell, enabling precise notification bridging. By utilizing a prioritized whitelist approach and offering both global and per-app configurations, the system ensures that only relevant data reaches the user's webhook, effectively managing both data volume and privacy.