Skip to content

Add flags for Fayda barcode reading and full-resolution OCR crops - #1870

Open
BurningAXE wants to merge 2 commits into
bugfix/fayda-fan-date-false-positivefrom
feature/fayda-barcode-and-native-res-ocr
Open

BurningAXE wants to merge 2 commits into
bugfix/fayda-fan-date-false-positivefrom
feature/fayda-barcode-and-native-res-ocr

Conversation

@BurningAXE

@BurningAXE BurningAXE commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

JIRA ticket
Will be released in: 2026.3.1

Stacked on #1869 (FAN pattern fix). The base will be switched to release/2026.3.1 once that PR is merged.

Root cause analysis (for bugfixes only)

First known affected version: 2026.3.0

  • Field users found it very hard to capture Fayda cards. On-device diagnostics on a Galaxy J6 (SM-J610FN) showed:
    • With ocrHighRes on (the default), each frame is a full-quality still capture that is scaled down to the preview size before the scan area is cropped. The crop ended up 664×415 and the FAN text 7–9px tall, below what ML Kit reads reliably. OCR read the FAN in only 3 of 8 frames (one with a wrong digit), and a capture took ~48s.
    • The FAN is also encoded in a Code 128 barcode below the printed number. ML Kit decoded it correctly in 6 of 8 frames from the same images, in ~200–300ms each.

Notable changes

Two independent commits, each behind an experimental custom-config flag that defaults to false, so there is no behaviour change unless enabled per project. Either commit can be reverted on its own.

  1. ocrKeepHighResDetail: crop OCR frames from the full-resolution capture
    • NormalizeHighResBitmapToPreviewUseCase gets a scaleToPreview parameter (default true). CameraFrameProvider.initialiseCamera gets keepHighResolutionDetail (default false), which the OCR screen sets from the flag.
    • FrameCropToTargetUseCase already supports bitmaps of any size, so it is unchanged.
    • Only applies when ocrHighRes is on, and only on the OCR screen (all MFID card types). Face capture and the QR scanners never use high-res capture and are not affected.
  2. ocrReadFaydaBarcode: read the FAN from the card's barcode first, falling back to OCR
    • New ReadBarcodesFromImageUseCase (ML Kit, Code 128 only) and FaydaCardOcrReaderUseCase.fromBarcodes(). The first barcode whose value is exactly 16 digits wins, and its box is extended upwards so the zoomed preview also shows the printed FAN.
    • ScanMfidDocumentUseCase takes a readFaydaBarcode parameter, passed from the view model's OcrConfig like the existing OCR flags. When the barcode gives a FAN, OCR is skipped for that frame. If barcode detection fails (e.g. the Play Services barcode module isn't downloaded yet), the frame falls back to OCR. NHIS and Ghana ID scans never read barcodes.
    • OcrScanResult.FaydaCard gets an isFromBarcode field (default false). When any capture came from a barcode, BuildMfidDocumentUseCase uses the most frequent complete barcode value instead of per-digit voting. This way OCR misreads can't outvote the checksummed value, and differing barcode reads can't be merged into a FAN that was never decoded. Per-digit voting is still used when all captures came from OCR.
    • Adds play-services-mlkit-barcode-scanning to feature:external-credential. The app already ships it via infra:camera for QR scanning.

Results on the Galaxy J6 (same card, each feature tested in isolation):

Before ocrKeepHighResDetail ocrReadFaydaBarcode ocrReadFaydaBarcode + ocrHighRes: false
Frames matched 3/8 6/7 12/15 Whole card: 5/18 · Close to FAN: 10/10
Wrong FANs 1 1 0 1 (whole card, outvoted) · 0 (close)
Time per capture ~48s 23–26s 10–20s ~11–25s · ~1s
  • ocrKeepHighResDetail makes OCR on each frame slower (1.6–3s vs 0.4–2s) and makes saved scan images bigger.
  • ocrHighRes: false (existing flag) is only fast when users hold the phone close to the barcode. With the whole card in frame, stream frames are too low-res for the barcode.

Testing guidance

  • Unit tests: ExperimentalProjectConfigurationTest, NormalizeHighResBitmapToPreviewUseCaseTest, FrameCropToTargetUseCaseTest, FaydaCardOcrReaderUseCaseTest, ScanMfidDocumentUseCaseTest, BuildMfidDocumentUseCaseTest, ExternalCredentialScanOcrViewModelTest.
  • Manual: with an MFID project configured for Fayda cards:
    • No flags set: behaviour is identical to before.
    • "ocrReadFaydaBarcode": true: framing the whole card should capture in ~10–20s. Holding the phone very close (barcode out of view) still works via OCR.
    • "ocrKeepHighResDetail": true: OCR should pick up the FAN with the whole card in frame. Check frame times on low-end devices.
    • Optionally "ocrHighRes": false with the barcode flag: holding the phone close to the barcode should capture in ~1s.
    • Regression: NHIS and Ghana ID scans with and without ocrKeepHighResDetail.

Additional work checklist

  • Effect on other features and security has been considered
  • Design document marked as "In development" (if applicable)
  • External (Gitbook) and internal (Confluence) Documentation is up to date (or ticket created)
  • Test cases in Testiny are up to date (or ticket created)
  • Other teams notified about the changes (if applicable)

🤖 Generated with Claude Code

@cla-bot cla-bot Bot added the ... label Oct 19, 2026
@BurningAXE
BurningAXE force-pushed the feature/fayda-barcode-and-native-res-ocr branch from 223bbfa to b3a1548 Compare October 19, 2026 21:54
@BurningAXE
BurningAXE added this pull request to stack #1873 October 20, 2026 11:03
@BurningAXE
BurningAXE requested a balanced review from Copilot October 20, 2026 11:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Barcode aggregation can produce a FAN that was never decoded or checksum-verified.

1 open issue
What changed in this PR

Adds two opt-in improvements to MFID scanning: full-resolution OCR crops and barcode-first Fayda FAN reading. Both flags default to disabled.

Changes:

  • Preserve capture detail without downscaling to preview size.
  • Read Fayda Code 128 barcodes, falling back to OCR and preferring barcode results.
  • Add configuration, crop, reader, and flag-propagation tests.
File Description
infra/​config-store/​src/​test/​java/​com/​simprints/​infra/​config/​store/​models/​ExperimentalProjectConfigurationTest.kt Tests both flag defaults and values.
infra/​config-store/​src/​main/​java/​com/​simprints/​infra/​config/​store/​models/​ExperimentalProjectConfiguration.kt Defines the experimental flags.
infra/​camera/​src/​test/​java/​com/​simprints/​infra/​camera/​usecase/​NormalizeHighResBitmapToPreviewUseCaseTest.kt Tests skipped downscaling.
infra/​camera/​src/​test/​java/​com/​simprints/​infra/​camera/​postprocess/​FrameCropToTargetUseCaseTest.kt Tests native-resolution cropping.
infra/​camera/​src/​main/​java/​com/​simprints/​infra/​camera/​usecase/​NormalizeHighResBitmapToPreviewUseCase.kt Makes preview downscaling optional.
infra/​camera/​src/​main/​java/​com/​simprints/​infra/​camera/​CameraFrameProvider.kt Passes the resolution preference.
feature/​external-credential/​src/​test/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​ScanMfidDocumentUseCaseTest.kt Tests barcode routing and OCR fallback.
feature/​external-credential/​src/​test/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​FaydaCardOcrReaderUseCaseTest.kt Tests barcode validation and bounds.
feature/​external-credential/​src/​test/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​BuildMfidDocumentUseCaseTest.kt Tests barcode preference.
feature/​external-credential/​src/​test/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​ExternalCredentialScanOcrViewModelTest.kt Tests barcode flag propagation.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​ScanMfidDocumentUseCase.kt Adds barcode-first Fayda scanning.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​ReadBarcodesFromImageUseCase.kt Adds Code 128 detection.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​FaydaCardOcrReaderUseCase.kt Converts barcodes into FAN results.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​usecase/​BuildMfidDocumentUseCase.kt Prioritizes barcode readouts.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​reader/​ScannedBarcode.kt Models decoded barcode data.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​model/​OcrScanResult.kt Records barcode provenance.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​model/​OcrConfig.kt Carries both scanning flags.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​ExternalCredentialScanOcrViewModel.kt Loads and forwards configuration.
feature/​external-credential/​src/​main/​java/​com/​simprints/​feature/​externalcredential/​screens/​scanocr/​ExternalCredentialScanOcrFragment.kt Configures full-resolution capture detail.
feature/​external-credential/​build.gradle.kts Adds the barcode scanning dependency.

Review effort: Balanced

@BurningAXE
BurningAXE force-pushed the feature/fayda-barcode-and-native-res-ocr branch from b3a1548 to 2896e03 Compare October 20, 2026 11:14
@BurningAXE
BurningAXE requested a balanced review from Copilot October 20, 2026 11:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

Static review found no blocking issues in the opt-in changes; regression tests were added but not executed during review.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@BurningAXE
BurningAXE removed this pull request from stack #1873 October 20, 2026 11:19
@BurningAXE
BurningAXE added this pull request to stack #1874 October 20, 2026 11:22
@BurningAXE
BurningAXE marked this pull request as ready for review October 20, 2026 11:23
@BurningAXE
BurningAXE requested review from a team, TristramN, alex-vt, alexandr-simprints, luhmirin-s, meladRaouf and ybourgery and removed request for a team October 20, 2026 11:24
BurningAXE and others added 2 commits October 20, 2026 14:50
With ocrHighRes enabled, each frame is a full-quality still capture that is
then scaled down to the preview size before the scan area is cropped, which
discards the detail the capture was taken for. On a Galaxy J6 the Fayda FAN
ended up 7-9px tall, below what ML Kit reads reliably.

The new experimental flag (default false, no behaviour change) skips the
downscale so FrameCropToTargetUseCase crops the scan area from the
native-resolution capture. In testing this made the FAN ~40-60px tall and
OCR matched 6/7 frames instead of 3/8, at the cost of slower OCR per frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fayda cards carry the FAN in a Code 128 barcode below the printed
number. Barcode decoding is checksummed, so unlike OCR it does not
misread digits, and it works at distances where the printed FAN is too
small for OCR.

When the new experimental flag is enabled (default false, no behaviour
change), Fayda scans try the barcode first and only fall back to OCR
when no barcode with a valid FAN is found or barcode detection fails.
When any capture came from a barcode, the most frequent barcode value is
used as the final FAN instead of per-digit voting, so OCR misreads
cannot outvote it and differing barcode reads cannot be merged into a
value that was never decoded. NHIS and Ghana ID scans are not affected.
In testing on a Galaxy J6 this brought a full capture down to ~10-20s
with no misread FANs (from ~48s with one misread).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BurningAXE
BurningAXE force-pushed the feature/fayda-barcode-and-native-res-ocr branch from 2896e03 to 3d0503f Compare October 20, 2026 11:51
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants