Files
fksar/docs/thijooree/24-notifications.md
T
2026-06-13 21:30:12 +05:00

76 lines
3.8 KiB
Markdown

# Notifications
Background polling that surfaces new bank activity as system notifications, plus an in-app bottom sheet for reading them. Opt-in only — the polling service is started from [Settings → Notifications](27-settings-notifications.md).
---
## Foreground Service — `NotificationPollingService`
File: `service/NotificationPollingService.kt`. Runs as a foreground service while the user has notifications enabled. Polls every **30 seconds** (`POLL_INTERVAL_MS = 30_000L`) on a `SupervisorJob` IO scope.
### Lifecycle
1. `onCreate`: creates the service channel (low importance, no badge), calls `startForeground(SERVICE_NOTIF_ID, ...)` with a persistent low-priority notification, then starts the polling loop
2. `onStartCommand`: returns `START_STICKY` so Android relaunches the service after kills
3. `onDestroy`: cancels the coroutine scope
### Poll Cycle
Each tick calls `pollBml()` and `pollMib()` sequentially. Both share the same shape:
| Step | Description |
|---|---|
| 1 | For every active session in `app.bmlSessions` / `app.mibSessions`, fetch the latest activity page |
| 2 | Compare with `NotificationsCache.loadBml(loginId)` / `loadMib(loginId, readIds)` |
| 3 | If the cache is empty (first run), persist the page silently — no system notifications are emitted on first sync |
| 4 | Otherwise, find IDs not in the cache, persist the merged list, and post a system notification per new item |
MIB activity is fetched via `MibActivityHistoryClient.fetchActivity(session, loginId, 1, 100)`. BML uses `BmlNotificationsClient.fetchNotifications(session, loginId, page = 1)`. Errors are caught per-loginId so one bad session does not block the rest.
### Channels
`ensureLoginChannel(bank, loginId)` lazily creates a `NotificationChannel` named `bank_{bank}_{loginId}` with `IMPORTANCE_DEFAULT`. The channel display name uses the profile's `name` from `bmlProfilesMap` / `mibProfilesMap` ("BML · Personal Name" etc.), falling back to the bare login id. This gives the user per-bank-per-profile channel control in system settings.
System notifications use `R.drawable.ic_bell` and a content intent that re-launches the app via `getLaunchIntentForPackage(packageName)`.
---
## In-App Sheet — `NotificationsSheetFragment`
Opened from the bell icon in the toolbar (`HomeActivity.openNotificationsSheet()` at line 687). A `BottomSheetDialogFragment` containing:
- A `TabLayout` + `ViewPager2` with one page per active bank login
- Each page is a `RecyclerView` of `AppNotification` grouped by date headers
- An "Mark all read" action
Notifications are loaded from `NotificationsCache` first for instant display, then refreshed from the network. Read state is tracked in `NotificationsCache` (`getMibReadIds()` etc.) so the bell toolbar icon (`HomeActivity.kt:640-684`) can switch between `ic_bell` and `ic_bell_read`.
`onUnreadCountChanged` callback is wired from `HomeActivity` so the bell icon updates whenever the sheet's contents change.
---
## Cache — `util/NotificationsCache`
Encrypted JSON files in `filesDir` (via `CacheEncryption`), one per bank+loginId. Stores the full notifications payload plus a separate "read IDs" set. Cleared along with the rest of the per-account history when the user invokes [Settings → Storage → Clear All Caches](17-settings-storage.md) (read state is excluded from that clear — verified in `17-settings-storage.md`).
---
## Opt-In
The polling service is not started automatically. The user must:
1. Tap Settings → Notifications
2. Toggle the switch on
3. Grant `POST_NOTIFICATIONS` (API 33+)
4. Optionally allow battery-optimisation exemption
See [Settings → Notifications](27-settings-notifications.md) for the full flow.
---
 
---
[← Tap to Pay](23-tap-to-pay.md)     **Next →** [QR Scanner](25-qr-scanner.md)