4.3 KiB
Cards
Unified card management screen for both MIB and BML cards. Supports a horizontally-paged stack, freeze / unfreeze, default-card and hide-from-dashboard toggles, and launches the Tap to Pay NFC flow.
Fragment — CardsFragment
File: ui/home/PayWithCardFragment.kt. Bound to nav id R.id.nav_pay_with_card.
Opened via:
- Navigation slot ("Cards")
OPEN_PAY_WITH_CARDintentTAP_TO_PAYintent — auto-enters tap mode for the user's default BML card- Dashboard NFC button — auto-enters tap mode for the selected card
newInstanceWithAutoTapMode(accountNumber? = null) (PayWithCardFragment.kt:1203-1208) is the factory for the auto-tap entry points.
Card Stack
A horizontal RecyclerView driven by CardStackAdapter with a PagerSnapHelper. Off-centre cards are scaled to 82% and faded to 60% via applyCardScales(). Page dots beneath the stack are rebuilt on each scroll-idle.
Sources
rebuildCards() (PayWithCardFragment.kt:894-958) merges two lists:
- BML:
viewModel.accountsfiltered toprofileType in (BML_PREPAID, BML_CREDIT, BML_DEBIT) - MIB:
viewModel.mibCards
The combined order is bmlActive + mibActive + bmlInactive + mibInactive. The user's default card (CredentialStore.getDefaultCardAccountNumber()) is moved to position 0. Initial data is seeded from CardsCache so the stack appears immediately; a background HomeActivity.triggerRefreshCards() refreshes it.
Card Art
| Source | Asset path |
|---|---|
MIB cardType → asset |
CardsFragment.cardImageAsset(card) — 51 → cards/mib/faisa_card.png, 53 → visa_black_platinum.png, 57 → visa_blue_everyday.png, 70 → visa_business.png, 701/702 → visa_bingaa_mvr.png / visa_bingaa_usd.png |
| BML | BmlCardParser.cardImageAsset(account) |
Status chips use bindCardStatus(...). MIB statuses: CHST0 = active (no chip), CHST20 = "Temporary blocked by client", other values shown verbatim.
Pay Buttons
| Button | Behaviour |
|---|---|
Scan to Pay (btnScanToPay) |
Launches QrScannerActivity. BML cards route the result to TransferFragment (BML QR mode or PayMV pre-fill). MIB cards show "not supported" |
Tap to Pay (btnTapToPay) |
NfcPaymentUtil.checkAndProceed(...). If biometrics_transfer_confirm is on, shows a BIOMETRIC_STRONG prompt first, then enters tap mode. MIB cards show "not supported" |
Manage Mode
Toggle: btnManageCard. Animates the focused card up into a single full-width "manage card" panel, hides the carousel, and exposes:
| Control | Effect |
|---|---|
| Default card switch | CredentialStore.setDefaultCardAccountNumber() — BML only |
| Hide from dashboard switch | CredentialStore.setCardHiddenFromDashboard(accountNumber, hidden) |
| Freeze / Unfreeze | BML: BmlCardClient.setCardFreezeState(session, internalId, "freeze"/"unfreeze"). MIB: prompts for a comments string, then MibCardsClient().setCardFreezeState(session, cardId, action, comments) serialised through app.mibMutex with a profile switch first |
| Change PIN / Block | Wired but currently shows a "work in progress" toast |
Manage mode can be dismissed by tapping the button again or swipe-down on the manage card.
Tap Mode
Entered via setTapMode(true, item). Hides the carousel, animates the selected card to the top, draws an NfcTapAnimationView and a Cancel button.
fetchAndArmToken():
- Generates a TOTP from the BML OTP seed
BmlTapToPayClient().fetchTokens(session, internalId, otp)returns a single-useBmlWalletTokenBmlHostCardEmulatorService.setToken(token)- Sets
BmlHostCardEmulatorService.onTransactionComplete— on success shows a "Payment complete" toast and refreshes balances
Exiting tap mode clears the token and the callback. See Tap to Pay for the HCE protocol details.
Inactive Cards
Inactive cards remain in the stack at 45% alpha. Tap-to-pay and "default card" are disabled for them. Hide-from-dashboard is force-enabled and locked on for inactive cards (PayWithCardFragment.kt:522-530).
Back Handling
onBackPressed() returns true while in manage mode or tap mode so HomeActivity does not pop the back stack — instead the fragment exits the current mode.
← Dashboard Next → Tap to Pay