Files
thijooree/docs/thijooree/25-qr-scanner.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.2 KiB

QR Scanner

Full-screen camera-based QR scanner. Returns the decoded string to the caller via activity result.


Activity — QrScannerActivity

File: ui/home/QrScannerActivity.kt. Hosts a CameraX preview + analysis pipeline backed by de.markusfisch.android.zxingcpp.ZxingCpp.

Reader Options

ZxingCpp.ReaderOptions(
    tryHarder = true,
    tryRotate = true,
    tryInvert = true,
    tryDownscale = true,
    maxNumberOfSymbols = 1,
    textMode = ZxingCpp.TextMode.PLAIN,
)

Camera Pipeline

startCamera() (QrScannerActivity.kt:186-240):

  1. ProcessCameraProvider.getInstance()
  2. Builds Preview and ImageAnalysis with HIGHEST_AVAILABLE_STRATEGY + RATIO_16_9_FALLBACK_AUTO_STRATEGY
  3. Analyser receives STRATEGY_KEEP_ONLY_LATEST frames; reads the Y-plane via ZxingCpp.readYBuffer(...) with the image rotation applied
  4. On first hit, deliverResult(text) sets Activity.RESULT_OK with EXTRA_QR_CONTENT and finishes

Lock Guard

onCreate (QrScannerActivity.kt:101-106) checks CredentialStore.loadSecurityHash() and app.isUnlocked; if a lock exists and the app is locked, it forwards to LockActivity and finishes — direct intent launches cannot bypass the lock screen.


UI Controls

Control Behaviour
Flashlight (btnFlashlight) Toggles camera.cameraControl.enableTorch(); icon swaps between ic_flashlight_to_on / ic_flashlight_to_off with an Animatable transition
Zoom slider (zoomSlider) Linear zoom via setLinearZoom(); updated live from the camera's zoomState observer
Pinch-to-zoom ScaleGestureDetector on the preview view, mapped through cameraControl.setZoomRatio() clamped to the device's [minZoomRatio, maxZoomRatio]
Pick image (btnPickImage) GetContent("image/*"); decodes the picked bitmap with the same reader options

Image Decoder Fallback

Bitmap.decodeQr() (QrScannerActivity.kt:243-249) mirrors BinaryEye: tries Binarizer.LOCAL_AVERAGE first, then falls back to GLOBAL_HISTOGRAM for tricky lighting.


Callers

Each caller registers an ActivityResultContracts.StartActivityForResult launcher and reads EXTRA_QR_CONTENT from the result intent.

Caller Result handling
TransferFragment Routes PayMV / BML URL via PaymvQrParser + extractBmlGatewayUrl
PayMvQrFragment Generation only — does not call the scanner directly
CredentialsFragment (login) OtpauthParser.parse(raw) → fills etOtpSeed or shows a chooser for multi-entry QRs
DashboardFragment BML URL → BML QR pay; PayMV → pre-fill Transfer; otherwise toast
CardsFragment Same routing as Dashboard, scoped to the active BML card

Share-to-Scan Fast Path

When another app shares an image directly to the activity-alias .ScanToPayActivity, MainActivity decodes the QR from the image before routing (it holds the URI permission only at that point). The decoded string is then forwarded as the share_qr_text extra. This bypasses the camera entirely.


 


← Notifications     Next → Circular Nav