Files
thijooree/docs/thijooree/24-notifications.md
T
shihaam a8cd22cbe1
Auto Tag on Version Change / check-version (push) Failing after 13m32s
update docs
2026-06-13 21:30:12 +05:00

3.8 KiB

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.


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 (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 for the full flow.


 


← Tap to Pay     Next → QR Scanner