[PR #6867] [MERGED] [PM-34038] fix: Address card scanner QA findings #107138

Closed
opened 2026-06-03 13:31:14 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/bitwarden/android/pull/6867
Author: @SaintPatrck
Created: 5/4/2026
Status: Merged
Merged: 5/7/2026
Merged by: @SaintPatrck

Base: mainHead: pm-34038/card-scanner-qa-fixes


📝 Commits (10+)

  • 4eab329 [PM-36412] Apply card scans atomically in VaultAddEdit
  • 4d104e4 [PM-36360][PM-36381] feat: Show snackbar after successful card scan
  • b14475e [PM-36380] fix: Position card scanner instruction above scan frame
  • 1197702 [PM-36380] test: Assert instruction renders above scan frame Box
  • 80fcfbd [PM-36383] feat: Surface a steadiness hint when card scan stalls
  • 4cae9ad [PM-36382] fix: Gate card scanner on frame, orientation, and time
  • 63833c6 [PM-34038] fix: Hold card scan emission until expiration is observed
  • 6eefdf7 [PM-34038] polish: Edge-to-edge camera and faded scan hint
  • adfe474 [PM-34038] style: Break horizontalLines chain onto separate lines
  • 69962e8 [PM-34038] refactor: Tighten CardScanData required fields to non-null

📊 Changes

22 files changed (+1990 additions, -140 deletions)

View changed files

📝 app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt (+7 -11)
📝 app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanScreen.kt (+88 -78)
📝 app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanViewModel.kt (+54 -2)
📝 app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt (+167 -5)
📝 app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanScreenTest.kt (+48 -1)
📝 app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanViewModelTest.kt (+92 -0)
📝 ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParser.kt (+5 -3)
📝 ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParserImpl.kt (+2 -2)
📝 ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanData.kt (+11 -5)
ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanFrameFilter.kt (+242 -0)
📝 ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardTextAnalyzerImpl.kt (+105 -19)
ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ExpiryBuffer.kt (+38 -0)
ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/PanVoteBuffer.kt (+33 -0)
ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ParsedCardFields.kt (+24 -0)
ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/RecognizedText.kt (+90 -0)
📝 ui/src/main/res/values/strings.xml (+2 -0)
📝 ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParserImplTest.kt (+14 -14)
ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanFrameFilterTest.kt (+503 -0)
ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanPipelineTest.kt (+255 -0)
ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ExpiryBufferTest.kt (+65 -0)

...and 2 more files

📄 Description

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-34038

📔 Objective

  • PM-36412 — Atomic gate in VaultAddEditViewModel.handleCardScanResultReceive: require number AND month before applying, then unconditionally overwrite number / brand / month / year. Replaces per-?: field merging that left stale data from a prior scan. Drops CVV from the apply path so manually entered codes survive a re-scan.
  • PM-36382 — Three layered defenses in CardTextAnalyzerImpl before parsing: frame gating against the on-screen scan rect, orientation gating (>10° baselines rejected from Line.cornerPoints), and 2-of-3-frame temporal voting. Replaces the previous behavior of flattening the entire viewport and emitting the first Luhn-valid PAN found — ML Kit's rotationDegrees-driven auto-rotation made off-axis cards parseable. New framework-free RecognizedText abstraction enables plain JVM tests.
  • PM-36360 + PM-36381 — "Card scanned" snackbar on AddEdit after the scanner sheet dismisses, in lieu of a fullscreen "Fetching card details" loading screen (OCR completes immediately; the delay would be fake).
  • PM-36380 — Instruction text repositioned above the scan frame. Regression-guard test asserts instructionBottom <= scanFrameTop against a tagged scan-frame Box.
  • PM-36383 — After 5s with no successful scan, surfaces a "Hold steady and ensure all card details are visible" banner with Modifier.semantics { liveRegion = LiveRegionMode.Polite } for TalkBack. Partially covers PM-36384.

📸 Screenshots

https://github.com/user-attachments/assets/bc1acc05-58f4-4096-8901-dcd0204b6ab4


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/bitwarden/android/pull/6867 **Author:** [@SaintPatrck](https://github.com/SaintPatrck) **Created:** 5/4/2026 **Status:** ✅ Merged **Merged:** 5/7/2026 **Merged by:** [@SaintPatrck](https://github.com/SaintPatrck) **Base:** `main` ← **Head:** `pm-34038/card-scanner-qa-fixes` --- ### 📝 Commits (10+) - [`4eab329`](https://github.com/bitwarden/android/commit/4eab3297836a8bcae9a720129cd67fb1675a7df8) [PM-36412] Apply card scans atomically in VaultAddEdit - [`4d104e4`](https://github.com/bitwarden/android/commit/4d104e4c9efbe2051f8d6842be6f87f76165cbf4) [PM-36360][PM-36381] feat: Show snackbar after successful card scan - [`b14475e`](https://github.com/bitwarden/android/commit/b14475e8319b46a7f5f831861f8dec6771839b0a) [PM-36380] fix: Position card scanner instruction above scan frame - [`1197702`](https://github.com/bitwarden/android/commit/119770236fec905e7d473d061dfb104b5ec7ffaf) [PM-36380] test: Assert instruction renders above scan frame Box - [`80fcfbd`](https://github.com/bitwarden/android/commit/80fcfbdfc1972f0bfdb197a3e81dca53ab100609) [PM-36383] feat: Surface a steadiness hint when card scan stalls - [`4cae9ad`](https://github.com/bitwarden/android/commit/4cae9ad7ee21fc83323cf7e743239981dfefa8c7) [PM-36382] fix: Gate card scanner on frame, orientation, and time - [`63833c6`](https://github.com/bitwarden/android/commit/63833c6aa02c9bf2d94041705e47593324eb63c2) [PM-34038] fix: Hold card scan emission until expiration is observed - [`6eefdf7`](https://github.com/bitwarden/android/commit/6eefdf78949d6ef25182fb062ec5f5e53c4f4324) [PM-34038] polish: Edge-to-edge camera and faded scan hint - [`adfe474`](https://github.com/bitwarden/android/commit/adfe4746d154ebb06c4682577ef28502659ae70c) [PM-34038] style: Break horizontalLines chain onto separate lines - [`69962e8`](https://github.com/bitwarden/android/commit/69962e8e81bece31b290c0adeb112309b7ccfc80) [PM-34038] refactor: Tighten CardScanData required fields to non-null ### 📊 Changes **22 files changed** (+1990 additions, -140 deletions) <details> <summary>View changed files</summary> 📝 `app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt` (+7 -11) 📝 `app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanScreen.kt` (+88 -78) 📝 `app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanViewModel.kt` (+54 -2) 📝 `app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt` (+167 -5) 📝 `app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanScreenTest.kt` (+48 -1) 📝 `app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/cardscanner/CardScanViewModelTest.kt` (+92 -0) 📝 `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParser.kt` (+5 -3) 📝 `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParserImpl.kt` (+2 -2) 📝 `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanData.kt` (+11 -5) ➕ `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanFrameFilter.kt` (+242 -0) 📝 `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardTextAnalyzerImpl.kt` (+105 -19) ➕ `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ExpiryBuffer.kt` (+38 -0) ➕ `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/PanVoteBuffer.kt` (+33 -0) ➕ `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ParsedCardFields.kt` (+24 -0) ➕ `ui/src/main/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/RecognizedText.kt` (+90 -0) 📝 `ui/src/main/res/values/strings.xml` (+2 -0) 📝 `ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardDataParserImplTest.kt` (+14 -14) ➕ `ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanFrameFilterTest.kt` (+503 -0) ➕ `ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/CardScanPipelineTest.kt` (+255 -0) ➕ `ui/src/test/kotlin/com/bitwarden/ui/platform/feature/cardscanner/util/ExpiryBufferTest.kt` (+65 -0) _...and 2 more files_ </details> ### 📄 Description ## 🎟️ Tracking https://bitwarden.atlassian.net/browse/PM-34038 ## 📔 Objective - **PM-36412** — Atomic gate in `VaultAddEditViewModel.handleCardScanResultReceive`: require number AND month before applying, then unconditionally overwrite number / brand / month / year. Replaces per-`?:` field merging that left stale data from a prior scan. Drops CVV from the apply path so manually entered codes survive a re-scan. - **PM-36382** — Three layered defenses in `CardTextAnalyzerImpl` before parsing: frame gating against the on-screen scan rect, orientation gating (>10° baselines rejected from `Line.cornerPoints`), and 2-of-3-frame temporal voting. Replaces the previous behavior of flattening the entire viewport and emitting the first Luhn-valid PAN found — ML Kit's `rotationDegrees`-driven auto-rotation made off-axis cards parseable. New framework-free `RecognizedText` abstraction enables plain JVM tests. - **PM-36360 + PM-36381** — "Card scanned" snackbar on AddEdit after the scanner sheet dismisses, in lieu of a fullscreen "Fetching card details" loading screen (OCR completes immediately; the delay would be fake). - **PM-36380** — Instruction text repositioned above the scan frame. Regression-guard test asserts `instructionBottom <= scanFrameTop` against a tagged scan-frame `Box`. - **PM-36383** — After 5s with no successful scan, surfaces a "Hold steady and ensure all card details are visible" banner with `Modifier.semantics { liveRegion = LiveRegionMode.Polite }` for TalkBack. Partially covers PM-36384. ## 📸 Screenshots https://github.com/user-attachments/assets/bc1acc05-58f4-4096-8901-dcd0204b6ab4 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-06-03 13:31:15 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/android#107138