-
Notifications
You must be signed in to change notification settings - Fork 180
[SELF-772] feat: consolidate qr / mrz logic into a folder #1134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
[SELF-772] feat: consolidate qr / mrz logic into a folder #1134
Conversation
WalkthroughAdds a new Android library module "android-mrz-qr-scanner", integrates it into the app, registers a new React Native package/module and view managers, introduces camera/ML Kit processing, MRZ/OCR/QR utilities and UI, and removes the legacy QRCodeScanner native module and package. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor JS as React JS
participant RN as MRZQRScannerModule
participant PKG as MRZQRScannerPackage
participant VM as ViewManager (OCR/QR)
participant UI as Fragment (CameraMLKit / QrCodeScannerFragment)
participant Cam as Camera (Fotoapparat/CameraX)
participant Proc as VisionProcessorBase / OcrMrzDetectorProcessor
participant ML as ML Kit TextRecognizer
participant Util as OcrUtils / MRZUtil
JS->>RN: request scan / mount view
RN->>PKG: register module & view managers
JS->>VM: mount OCR or QR view
VM->>UI: create/start fragment
UI->>Cam: start preview
Cam-->>UI: frames (ByteBuffer/Image)
UI->>Proc: process frame (InputImage / metadata)
Proc->>ML: detect text
ML-->>Proc: text result
Proc->>Util: processOcr(text)
Util-->>UI: MRZInfo or failure
UI-->>JS: emit events/callbacks (MRZ found / not found)
sequenceDiagram
autonumber
participant Old as Legacy QRCodeScannerModule
participant New as MRZQRScannerModule
note over Old: Activity-based scanning + photo-picker handling\n(removed)
note over New: Fragment + CameraX/Fotoapparat + ML Kit pipeline\n(new)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.kt (1)
85-90: Keep the camera subscription pipeline alive after view recreationCalling
dispose()on the sharedCompositeDisposablepermanently terminates it, so every subsequentdisposable.add(...)after the fragment view is recreated (rotation, back stack return, etc.) instantly disposes the work. The QR decoding pipeline stops firing after the first teardown. Clearing instead of disposing keeps the container reusable while releasing the accumulated subscriptions.- if (!disposable.isDisposed) { - disposable.dispose(); - } + disposable.clear()app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.kt (1)
99-101: Fix Kotlin call toisDisposed.Line 99 currently calls
disposable.isDisposed(); in Kotlin, RxJava’sisDisposed()accessor is exposed as the propertyisDisposed. Invoking it like a function fails to compile, so the module can’t even build. Switch to property access before merging.- if (!disposable.isDisposed()) { + if (!disposable.isDisposed) { disposable.dispose(); }
🧹 Nitpick comments (1)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt (1)
114-141: Consider deferring original bitmap creation until after successful detection to cut hot‑path CPU/GC.Most frames won’t yield results; decoding/rotating on the critical path can drop FPS.
Option: pass
nullhere and, insideonSuccess, lazily compute the bitmap only when the listener actually needs it. This keeps the critical path lightweight.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
app/android/android-mrz-qr-scanner/build.gradle(1 hunks)app/android/android-mrz-qr-scanner/src/main/AndroidManifest.xml(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.java(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.java(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/fragments/CameraFragment.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/FrameMetadata.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/GraphicOverlay.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/OcrMrzDetectorProcessor.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionImageProcessor.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.kt(2 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.kt(2 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/MRZUtil.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/OcrUtils.kt(1 hunks)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/QrCodeDetectorProcessor.kt(2 hunks)app/android/android-mrz-qr-scanner/src/main/res/layout/fragment_camera_mrz.xml(1 hunks)app/android/android-mrz-qr-scanner/src/main/res/values/colors.xml(1 hunks)app/android/android-mrz-qr-scanner/src/main/res/values/strings.xml(1 hunks)app/android/app/build.gradle(1 hunks)app/android/app/src/main/java/com/proofofpassportapp/CameraActivityPackage.java(1 hunks)app/android/app/src/main/java/com/proofofpassportapp/MainApplication.kt(2 hunks)app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java(0 hunks)app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerPackage.java(0 hunks)app/android/settings.gradle(1 hunks)
💤 Files with no reviewable changes (2)
- app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerModule.java
- app/android/app/src/main/java/com/proofofpassportapp/QRCodeScannerPackage.java
🧰 Additional context used
📓 Path-based instructions (2)
app/android/**/*
⚙️ CodeRabbit configuration file
app/android/**/*: Review Android-specific code for:
- Platform-specific implementations
- Performance considerations
- Security best practices for mobile
Files:
app/android/android-mrz-qr-scanner/src/main/res/values/strings.xmlapp/android/android-mrz-qr-scanner/src/main/AndroidManifest.xmlapp/android/settings.gradleapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/FrameMetadata.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.ktapp/android/app/build.gradleapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/fragments/CameraFragment.ktapp/android/android-mrz-qr-scanner/src/main/res/values/colors.xmlapp/android/app/src/main/java/com/proofofpassportapp/MainApplication.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/GraphicOverlay.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionImageProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/OcrUtils.ktapp/android/android-mrz-qr-scanner/src/main/res/layout/fragment_camera_mrz.xmlapp/android/app/src/main/java/com/proofofpassportapp/CameraActivityPackage.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/QrCodeDetectorProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/MRZUtil.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/OcrMrzDetectorProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.ktapp/android/android-mrz-qr-scanner/build.gradle
app/android/**/*.{kt,java}
📄 CodeRabbit inference engine (app/AGENTS.md)
Document complex native Android module changes in the PR
Files:
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/FrameMetadata.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/fragments/CameraFragment.ktapp/android/app/src/main/java/com/proofofpassportapp/MainApplication.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/GraphicOverlay.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionImageProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/OcrUtils.ktapp/android/app/src/main/java/com/proofofpassportapp/CameraActivityPackage.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/QrCodeDetectorProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/MRZUtil.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/OcrMrzDetectorProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.kt
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Applies to packages/mobile-sdk-alpha/src/processing/** : Place MRZ processing helpers in packages/mobile-sdk-alpha/src/processing/
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Verify extractMRZInfo() using published sample MRZ strings (e.g., ICAO examples)
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-09-22T11:10:57.879Z
Learning: Applies to app/android/**/*.{kt,java} : Document complex native Android module changes in the PR
📚 Learning: 2025-09-22T11:10:57.879Z
Learnt from: CR
PR: selfxyz/self#0
File: app/AGENTS.md:0-0
Timestamp: 2025-09-22T11:10:57.879Z
Learning: Applies to app/android/**/*.{kt,java} : Document complex native Android module changes in the PR
Applied to files:
app/android/android-mrz-qr-scanner/src/main/AndroidManifest.xmlapp/android/settings.gradleapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.ktapp/android/app/build.gradleapp/android/app/src/main/java/com/proofofpassportapp/MainApplication.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.ktapp/android/android-mrz-qr-scanner/build.gradle
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Applies to packages/mobile-sdk-alpha/src/processing/** : Place MRZ processing helpers in packages/mobile-sdk-alpha/src/processing/
Applied to files:
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.ktapp/android/app/src/main/java/com/proofofpassportapp/MainApplication.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/OcrUtils.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/QrCodeDetectorProcessor.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.javaapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.ktapp/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.java
📚 Learning: 2025-08-24T21:22:29.459Z
Learnt from: transphorm
PR: selfxyz/self#943
File: app/android/app/src/main/java/com/proofofpassportapp/MainApplication.kt:17-17
Timestamp: 2025-08-24T21:22:29.459Z
Learning: OpenSourceMergedSoMapping from com.facebook.react.soloader.OpenSourceMergedSoMapping is available and functional in React Native 0.75.x. It can be safely imported and used for SoLoader initialization in MainApplication.kt without causing build failures.
Applied to files:
app/android/app/src/main/java/com/proofofpassportapp/MainApplication.kt
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Verify extractMRZInfo() using published sample MRZ strings (e.g., ICAO examples)
Applied to files:
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.java
🧬 Code graph analysis (7)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/fragments/CameraFragment.kt (2)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.kt (2)
onRequestPermissionsResult(191-192)onRequestPermissionsResult(317-327)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.kt (2)
onRequestPermissionsResult(165-166)onRequestPermissionsResult(241-251)
app/android/app/src/main/java/com/proofofpassportapp/MainApplication.kt (1)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.java (1)
MRZQRScannerPackage(13-28)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/GraphicOverlay.kt (1)
packages/mobile-sdk-alpha/android/src/main/java/com/selfxyz/selfSDK/mlkit/GraphicOverlay.kt (1)
postInvalidate(112-114)
app/android/app/src/main/java/com/proofofpassportapp/CameraActivityPackage.java (1)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.kt (1)
reactContext(20-163)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerModule.java (2)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.kt (2)
reactContext(20-163)getName(27-27)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.kt (2)
reactContext(18-161)getName(25-25)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt (4)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionImageProcessor.kt (6)
process(25-48)process(28-28)process(31-31)process(34-34)process(37-37)process(40-40)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/CameraMLKitFragment.kt (1)
process(132-162)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QrCodeScannerFragment.kt (1)
process(108-136)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/OcrMrzDetectorProcessor.kt (1)
detectInImage(51-53)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/MRZQRScannerPackage.java (2)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/PassportOCRViewManager.kt (1)
reactContext(20-163)app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/ui/QRCodeScannerViewManager.kt (1)
reactContext(18-161)
🪛 detekt (1.23.8)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/MRZUtil.kt
[warning] 33-34: Empty catch block detected. If the exception can be safely ignored, name the exception according to one of the exemptions as per the configuration of this rule.
(detekt.empty-blocks.EmptyCatchBlock)
[warning] 33-33: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt
[warning] 270-270: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: android-build-test
- GitHub Check: e2e-ios
- GitHub Check: analyze-ios
- GitHub Check: analyze-android
- GitHub Check: build-deps
🔇 Additional comments (1)
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt (1)
14-24: Please document the native module changes and integration steps in the PR description.Add a brief design/migration note (module wiring, RN bridge surface, threading model, and any breaking changes).
As per coding guidelines.
| // React Native dependencies | ||
| implementation 'com.facebook.react:react-native:+' | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pin the React Native artifact version
com.facebook.react:react-native:+ lets Gradle pick an arbitrary version at build time. That breaks reproducibility, risks silently pulling insecure releases, and can desynchronize this library from the app’s pinned React Native runtime. Please align this dependency with the exact version the app already ships with.
- implementation 'com.facebook.react:react-native:+'
+ implementation "com.facebook.react:react-native:${rootProject.ext.get(\"reactNativeAndroidVersion\")}"(Replace the property with whatever constant the app module already uses for the pinned React Native coordinate.)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // React Native dependencies | |
| implementation 'com.facebook.react:react-native:+' | |
| } | |
| // React Native dependencies | |
| implementation "com.facebook.react:react-native:${rootProject.ext.get(\"reactNativeAndroidVersion\")}" | |
| } |
🤖 Prompt for AI Agents
In app/android/android-mrz-qr-scanner/build.gradle around lines 58 to 60, the
dependency uses a floating version 'com.facebook.react:react-native:+', which
must be replaced with the app's pinned React Native coordinate; locate the
constant/property the main app module already uses for the pinned React Native
version (e.g. a project ext property or dependency constant), replace the '+'
with that exact coordinate or property reference so the library and app use the
same explicit version, then sync/clean the Gradle build to verify resolution.
| rotation = getRotation(context!!, initialLensPosition) | ||
| buildCamera(cameraPreview!!, initialLensPosition) | ||
|
|
||
| hasCameraPermission = hasCameraPermission() | ||
| if (hasCameraPermission) { | ||
| checkPermissions(requestedPermissions) | ||
| } else { | ||
| fotoapparat?.start() | ||
| configureZoom() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inverted permission flag handling
hasCameraPermission() currently returns true when the camera permission is missing (!= PERMISSION_GRANTED), yet we set hasCameraPermission = true in the grant path and expect subclasses to treat the flag as “permission available”. After the next lifecycle pass, hasCameraPermission() resets the flag to false, so any subclass relying on this protected field will believe the camera is still blocked and can short-circuit MRZ/QR flows or show the wrong UI. Please flip the boolean logic so the helper returns true when access is granted, and update the onResume/onPause branches accordingly to avoid re-request loops and inconsistent state exposure.
@@
- hasCameraPermission = hasCameraPermission()
- if (hasCameraPermission) {
- checkPermissions(requestedPermissions)
- } else {
- fotoapparat?.start()
- configureZoom()
- }
+ hasCameraPermission = hasCameraPermission()
+ if (!hasCameraPermission) {
+ checkPermissions(requestedPermissions)
+ } else {
+ fotoapparat?.start()
+ configureZoom()
+ }
@@
- hasCameraPermission = hasCameraPermission()
- if (!hasCameraPermission) {
- fotoapparat?.stop()
- }
+ hasCameraPermission = hasCameraPermission()
+ if (hasCameraPermission) {
+ fotoapparat?.stop()
+ }
@@
- protected fun hasCameraPermission(): Boolean {
- return ContextCompat.checkSelfPermission(context!!, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
- }
+ protected fun hasCameraPermission(): Boolean {
+ return ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
+ }Also applies to: 248-296
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/fragments/CameraFragment.kt
around lines 146-156 (and similarly update 248-296), the permission check logic
is inverted: change hasCameraPermission() to return true when
ContextCompat.checkSelfPermission(...) == PERMISSION_GRANTED, flip assignments
so hasCameraPermission = hasCameraPermission() reflects granted state, and
update the branches so when permission is granted you start/configure the camera
(fotoapparat?.start(), configureZoom(), buildCamera/rotation) and when missing
you call checkPermissions(requestedPermissions) to request them; also adjust
onResume/onPause flows to not re-request or reset the protected flag incorrectly
after lifecycle transitions so subclasses see a consistent permission-available
boolean.
| var originalBitmap:Bitmap?=null | ||
| if(isOriginalImageReturned){ | ||
| try { | ||
| originalBitmap = inputImage.bitmapInternal | ||
| if (originalBitmap == null) { | ||
| val wrap = ByteBuffer.wrap(frame.image) | ||
| originalBitmap = ImageUtil.rotateBitmap(ImageUtil.getBitmap(wrap, frameMetadata)!!, frameMetadata.rotation.toFloat()) | ||
| } | ||
| }catch (e:Exception){ | ||
| e.printStackTrace() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix double-rotation of original bitmap in Frame path.
ImageUtil.getBitmap(...) already applies rotation; rotating again skews orientation.
Apply this diff:
- originalBitmap = inputImage.bitmapInternal
- if (originalBitmap == null) {
- val wrap = ByteBuffer.wrap(frame.image)
- originalBitmap = ImageUtil.rotateBitmap(ImageUtil.getBitmap(wrap, frameMetadata)!!, frameMetadata.rotation.toFloat())
- }
+ originalBitmap = inputImage.bitmapInternal
+ if (originalBitmap == null) {
+ val wrap = ByteBuffer.wrap(frame.image)
+ originalBitmap = ImageUtil.getBitmap(wrap, frameMetadata)
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var originalBitmap:Bitmap?=null | |
| if(isOriginalImageReturned){ | |
| try { | |
| originalBitmap = inputImage.bitmapInternal | |
| if (originalBitmap == null) { | |
| val wrap = ByteBuffer.wrap(frame.image) | |
| originalBitmap = ImageUtil.rotateBitmap(ImageUtil.getBitmap(wrap, frameMetadata)!!, frameMetadata.rotation.toFloat()) | |
| } | |
| }catch (e:Exception){ | |
| e.printStackTrace() | |
| } | |
| } | |
| var originalBitmap: Bitmap? = null | |
| if (isOriginalImageReturned) { | |
| try { | |
| originalBitmap = inputImage.bitmapInternal | |
| if (originalBitmap == null) { | |
| val wrap = ByteBuffer.wrap(frame.image) | |
| originalBitmap = ImageUtil.getBitmap(wrap, frameMetadata) | |
| } | |
| } catch (e: Exception) { | |
| e.printStackTrace() | |
| } | |
| } |
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/mlkit/VisionProcessorBase.kt
around lines 126 to 137, the code double-rotates the original bitmap when
falling back to ByteBuffer: ImageUtil.getBitmap(...) already returns a rotated
bitmap so calling ImageUtil.rotateBitmap(...) again skews orientation; change
the fallback to assign the bitmap directly from ImageUtil.getBitmap(wrap,
frameMetadata)!! (keeping the null-safety checks and try/catch) instead of
rotating it a second time.
| import org.jmrtd.lds.ImageInfo.WSQ_MIME_TYPE | ||
| import kotlin.experimental.and | ||
|
|
||
| object ImageUtil { | ||
|
|
||
| private val TAG = ImageUtil::class.java.simpleName | ||
|
|
||
| var JPEG_MIME_TYPE = "image/jpeg" | ||
| var JPEG2000_MIME_TYPE = "image/jp2" // Not decoded specially in this module | ||
| var JPEG2000_ALT_MIME_TYPE = "image/jpeg2000" // Not decoded specially in this module | ||
| var WSQ_MIME_TYPE = "image/x-wsq" | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocking: WSQ_MIME_TYPE redeclared; compile error risk.
You import org.jmrtd.lds.ImageInfo.WSQ_MIME_TYPE and also declare WSQ_MIME_TYPE locally; Kotlin will flag a redeclaration/conflicting import. Make one source of truth and make constants immutable.
Apply this diff:
-import org.jmrtd.lds.ImageInfo.WSQ_MIME_TYPE
+// import removed: avoid name clash with local constant
- var JPEG_MIME_TYPE = "image/jpeg"
- var JPEG2000_MIME_TYPE = "image/jp2" // Not decoded specially in this module
- var JPEG2000_ALT_MIME_TYPE = "image/jpeg2000" // Not decoded specially in this module
- var WSQ_MIME_TYPE = "image/x-wsq"
+ const val JPEG_MIME_TYPE = "image/jpeg"
+ const val JPEG2000_MIME_TYPE = "image/jp2" // Not decoded specially in this module
+ const val JPEG2000_ALT_MIME_TYPE = "image/jpeg2000" // Not decoded specially in this module
+ const val WSQ_MIME_TYPE = "image/x-wsq"Also applies to: 96-101
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.kt
around lines 25-36 (and similarly lines 96-101), you have a conflicting import
of org.jmrtd.lds.ImageInfo.WSQ_MIME_TYPE and a local WSQ_MIME_TYPE declaration;
remove the duplicate by either deleting the local WSQ_MIME_TYPE or removing the
import and rename the local constant, and make all MIME constants immutable (use
val) so there's a single source of truth and no redeclaration compile error.
| if (image.format == ImageFormat.JPEG) { | ||
| val planes = image.planes | ||
| val buffer = planes[0].buffer | ||
| data = ByteArray(buffer.capacity()) | ||
| buffer.get(data) | ||
| return data | ||
| } else if (image.format == ImageFormat.YUV_420_888) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JPEG branch may over-read; use remaining() instead of capacity().
buffer.capacity() isn’t the readable length; use remaining() to avoid truncation or garbage bytes.
Apply this diff:
- val buffer = planes[0].buffer
- data = ByteArray(buffer.capacity())
- buffer.get(data)
+ val buffer = planes[0].buffer
+ data = ByteArray(buffer.remaining())
+ buffer.get(data)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (image.format == ImageFormat.JPEG) { | |
| val planes = image.planes | |
| val buffer = planes[0].buffer | |
| data = ByteArray(buffer.capacity()) | |
| buffer.get(data) | |
| return data | |
| } else if (image.format == ImageFormat.YUV_420_888) { | |
| if (image.format == ImageFormat.JPEG) { | |
| val planes = image.planes | |
| val buffer = planes[0].buffer | |
| data = ByteArray(buffer.remaining()) | |
| buffer.get(data) | |
| return data | |
| } else if (image.format == ImageFormat.YUV_420_888) { | |
| // … | |
| } |
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.kt
around lines 39 to 45, the JPEG branch uses buffer.capacity() to size the byte
array which can cause over-read or include invalid bytes; change allocation and
read to use buffer.remaining() (the number of readable bytes) so you allocate
ByteArray(buffer.remaining()) and then buffer.get(data) to safely read only the
available bytes.
| fun YUV_420_888toNV21(image: Image): ByteArray { | ||
| val nv21: ByteArray | ||
| val yBuffer = image.planes[0].buffer | ||
| val uBuffer = image.planes[1].buffer | ||
| val vBuffer = image.planes[2].buffer | ||
|
|
||
| val ySize = yBuffer.remaining() | ||
| val uSize = uBuffer.remaining() | ||
| val vSize = vBuffer.remaining() | ||
|
|
||
| nv21 = ByteArray(ySize + uSize + vSize) | ||
|
|
||
| //U and V are swapped | ||
| yBuffer.get(nv21, 0, ySize) | ||
| vBuffer.get(nv21, ySize, vSize) | ||
| uBuffer.get(nv21, ySize + vSize, uSize) | ||
|
|
||
| return nv21 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NV21 conversion is incorrect (strides/pixel strides ignored); produces corrupted frames on many devices.
Current code concatenates planes and mis-sizes the buffer; you must respect rowStride/pixelStride and interleave VU for NV21.
Replace the function with a stride-aware implementation:
- fun YUV_420_888toNV21(image: Image): ByteArray {
- val nv21: ByteArray
- val yBuffer = image.planes[0].buffer
- val uBuffer = image.planes[1].buffer
- val vBuffer = image.planes[2].buffer
-
- val ySize = yBuffer.remaining()
- val uSize = uBuffer.remaining()
- val vSize = vBuffer.remaining()
-
- nv21 = ByteArray(ySize + uSize + vSize)
-
- //U and V are swapped
- yBuffer.get(nv21, 0, ySize)
- vBuffer.get(nv21, ySize, vSize)
- uBuffer.get(nv21, ySize + vSize, uSize)
-
- return nv21
- }
+ fun YUV_420_888toNV21(image: Image): ByteArray {
+ val width = image.width
+ val height = image.height
+ val ySize = width * height
+ val uvSize = ySize / 2
+ val nv21 = ByteArray(ySize + uvSize)
+
+ val yPlane = image.planes[0]
+ val uPlane = image.planes[1]
+ val vPlane = image.planes[2]
+
+ // Copy Y respecting row/pixel stride
+ val yBuffer = yPlane.buffer
+ val yRowStride = yPlane.rowStride
+ val yPixelStride = yPlane.pixelStride
+ val yBytes = ByteArray(yBuffer.remaining())
+ yBuffer.get(yBytes)
+ var pos = 0
+ var yOff = 0
+ for (row in 0 until height) {
+ var col = 0
+ while (col < width) {
+ nv21[pos++] = yBytes[yOff + col * yPixelStride]
+ col++
+ }
+ yOff += yRowStride
+ }
+
+ // Interleave V then U (NV21) respecting strides
+ val uBuffer = uPlane.buffer
+ val vBuffer = vPlane.buffer
+ val uRowStride = uPlane.rowStride
+ val vRowStride = vPlane.rowStride
+ val uPixelStride = uPlane.pixelStride
+ val vPixelStride = vPlane.pixelStride
+ val uBytes = ByteArray(uBuffer.remaining()).also { uBuffer.get(it) }
+ val vBytes = ByteArray(vBuffer.remaining()).also { vBuffer.get(it) }
+
+ val chromaHeight = height / 2
+ val chromaWidth = width / 2
+ for (row in 0 until chromaHeight) {
+ var uRowOff = row * uRowStride
+ var vRowOff = row * vRowStride
+ var col = 0
+ while (col < chromaWidth) {
+ nv21[pos++] = vBytes[vRowOff + col * vPixelStride] // V
+ nv21[pos++] = uBytes[uRowOff + col * uPixelStride] // U
+ col++
+ }
+ }
+ return nv21
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fun YUV_420_888toNV21(image: Image): ByteArray { | |
| val nv21: ByteArray | |
| val yBuffer = image.planes[0].buffer | |
| val uBuffer = image.planes[1].buffer | |
| val vBuffer = image.planes[2].buffer | |
| val ySize = yBuffer.remaining() | |
| val uSize = uBuffer.remaining() | |
| val vSize = vBuffer.remaining() | |
| nv21 = ByteArray(ySize + uSize + vSize) | |
| //U and V are swapped | |
| yBuffer.get(nv21, 0, ySize) | |
| vBuffer.get(nv21, ySize, vSize) | |
| uBuffer.get(nv21, ySize + vSize, uSize) | |
| return nv21 | |
| } | |
| fun YUV_420_888toNV21(image: Image): ByteArray { | |
| val width = image.width | |
| val height = image.height | |
| val ySize = width * height | |
| val uvSize = ySize / 2 | |
| val nv21 = ByteArray(ySize + uvSize) | |
| val yPlane = image.planes[0] | |
| val uPlane = image.planes[1] | |
| val vPlane = image.planes[2] | |
| // Copy Y respecting row/pixel stride | |
| val yBuffer = yPlane.buffer | |
| val yRowStride = yPlane.rowStride | |
| val yPixelStride = yPlane.pixelStride | |
| val yBytes = ByteArray(yBuffer.remaining()) | |
| yBuffer.get(yBytes) | |
| var pos = 0 | |
| var yOff = 0 | |
| for (row in 0 until height) { | |
| var col = 0 | |
| while (col < width) { | |
| nv21[pos++] = yBytes[yOff + col * yPixelStride] | |
| col++ | |
| } | |
| yOff += yRowStride | |
| } | |
| // Interleave V then U (NV21) respecting strides | |
| val uBuffer = uPlane.buffer | |
| val vBuffer = vPlane.buffer | |
| val uRowStride = uPlane.rowStride | |
| val vRowStride = vPlane.rowStride | |
| val uPixelStride = uPlane.pixelStride | |
| val vPixelStride = vPlane.pixelStride | |
| val uBytes = ByteArray(uBuffer.remaining()).also { uBuffer.get(it) } | |
| val vBytes = ByteArray(vBuffer.remaining()).also { vBuffer.get(it) } | |
| val chromaHeight = height / 2 | |
| val chromaWidth = width / 2 | |
| for (row in 0 until chromaHeight) { | |
| var uRowOff = row * uRowStride | |
| var vRowOff = row * vRowStride | |
| var col = 0 | |
| while (col < chromaWidth) { | |
| nv21[pos++] = vBytes[vRowOff + col * vPixelStride] // V | |
| nv21[pos++] = uBytes[uRowOff + col * uPixelStride] // U | |
| col++ | |
| } | |
| } | |
| return nv21 | |
| } |
| var inputStream = inputStream | ||
| /* DEBUG */ | ||
| synchronized(inputStream) { | ||
| val dataIn = DataInputStream(inputStream) | ||
| val bytes = ByteArray(imageLength) | ||
| dataIn.readFully(bytes) | ||
| inputStream = ByteArrayInputStream(bytes) | ||
| } | ||
| /* END DEBUG */ | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unbounded, duplicate buffering of InputStream; potential OOM/DoS and wrong-length reads. Also decodeStream may return null.
- Remove the DEBUG full read and avoid reading the stream twice.
- For WSQ, read exactly
imageLengthwith a sane upper bound. - Guard
BitmapFactory.decodeStreamwithrequireNotNull.
Apply this diff:
- var inputStream = inputStream
- /* DEBUG */
- synchronized(inputStream) {
- val dataIn = DataInputStream(inputStream)
- val bytes = ByteArray(imageLength)
- dataIn.readFully(bytes)
- inputStream = ByteArrayInputStream(bytes)
- }
- /* END DEBUG */
+ val stream = inputStream
@@
- val wsqDecoder = WsqDecoder()
- val bitmap = wsqDecoder.decode(inputStream.readBytes())
+ val wsqDecoder = WsqDecoder()
+ require(imageLength in 1..(16 * 1024 * 1024)) { "imageLength too large: $imageLength" }
+ val wsqBytes = ByteArray(imageLength)
+ DataInputStream(stream).readFully(wsqBytes)
+ val bitmap = wsqDecoder.decode(wsqBytes)
@@
- return BitmapFactory.decodeStream(inputStream)
+ return requireNotNull(BitmapFactory.decodeStream(stream)) {
+ "Unsupported or corrupt image format (mimeType=$mimeType)"
+ }Also applies to: 98-101, 110-111
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/ImageUtil.kt
around lines 86-95 (also apply same fixes to 98-101 and 110-111): remove the
DEBUG block that reads the entire InputStream into a byte array while
synchronizing (this duplicates buffering and can OOM/DoS and mis-handle
lengths); instead consume the incoming InputStream once and, for WSQ images,
read exactly imageLength bytes with a sane upper bound/cap (validate imageLength
before allocating and use a bounded read loop or a LimitedInputStream wrapper to
prevent over-reads); stop creating duplicate ByteArrayInputStream copies of the
same data; and guard BitmapFactory.decodeStream by wrapping its result with
requireNotNull (throw with a clear message) so null decode results fail fast.
| val lines = mrz.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | ||
| if (lines.size > 2) { | ||
| return cleanLine1(lines[0]) + "\n" + cleanLine2(lines[1]) | ||
| } | ||
| throw IllegalArgumentException("Not enough lines") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix MRZ line-count check.
Standard MRZ payloads are exactly two lines long, but cleanString only accepts inputs where lines.size > 2. That means every valid two-line MRZ string now throws IllegalArgumentException("Not enough lines"), breaking the scanner path completely. Please accept two-line inputs by relaxing the guard.
- if (lines.size > 2) {
+ if (lines.size >= 2) {
return cleanLine1(lines[0]) + "\n" + cleanLine2(lines[1])
}
throw IllegalArgumentException("Not enough lines")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val lines = mrz.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | |
| if (lines.size > 2) { | |
| return cleanLine1(lines[0]) + "\n" + cleanLine2(lines[1]) | |
| } | |
| throw IllegalArgumentException("Not enough lines") | |
| } | |
| val lines = mrz.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | |
| if (lines.size >= 2) { | |
| return cleanLine1(lines[0]) + "\n" + cleanLine2(lines[1]) | |
| } | |
| throw IllegalArgumentException("Not enough lines") | |
| } |
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/MRZUtil.kt
around lines 44 to 49, the method currently rejects valid two-line MRZs by
checking `lines.size > 2`; change the guard to accept two-line inputs (e.g.,
`lines.size >= 2` or `lines.size == 2`) so the function returns cleaned line1 +
"\n" + cleaned line2 for standard MRZ payloads instead of throwing
IllegalArgumentException("Not enough lines"); keep the existing
cleanLine1/cleanLine2 calls and error path for fewer than two lines.
| private fun createDummyMrz( | ||
| documentType: String, | ||
| issuingState: String = "ESP", | ||
| documentNumber: String, | ||
| dateOfBirthDay: String, | ||
| expirationDate: String, | ||
| nationality: String = "ESP" | ||
| ): MRZInfo { | ||
| return MRZInfo( | ||
| documentType, | ||
| issuingState, | ||
| "DUMMY", | ||
| "DUMMY", | ||
| documentNumber, | ||
| "ESP", | ||
| dateOfBirthDay, | ||
| Gender.MALE, | ||
| expirationDate, | ||
| "" | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix hard-coded MRZ nationality/gender
createDummyMrz always reports "ESP" and Gender.MALE, ignoring both the parsed country code and the actual gender we already parsed above. Any non-Spanish document will therefore surface with the wrong nationality (and often the wrong gender), which breaks downstream compliance flows that rely on this metadata. Please pass through the real nationality/gender instead of hard-coding them.
- private fun createDummyMrz(
- documentType: String,
- issuingState: String = "ESP",
- documentNumber: String,
- dateOfBirthDay: String,
- expirationDate: String,
- nationality: String = "ESP"
- ): MRZInfo {
- return MRZInfo(
- documentType,
- issuingState,
- "DUMMY",
- "DUMMY",
- documentNumber,
- "ESP",
- dateOfBirthDay,
- Gender.MALE,
- expirationDate,
- ""
- )
- }
+ private fun createDummyMrz(
+ documentType: String,
+ issuingState: String = "ESP",
+ documentNumber: String,
+ dateOfBirthDay: String,
+ expirationDate: String,
+ nationality: String = issuingState,
+ gender: Gender = Gender.UNSPECIFIED
+ ): MRZInfo {
+ return MRZInfo(
+ documentType,
+ issuingState,
+ "DUMMY",
+ "DUMMY",
+ documentNumber,
+ nationality,
+ dateOfBirthDay,
+ gender,
+ expirationDate,
+ ""
+ )
+ }Remember to thread the parsed nationality/gender into these parameters at the call sites so the MRZInfo stays faithful to the document.
🤖 Prompt for AI Agents
In
app/android/android-mrz-qr-scanner/src/main/java/com/selfxyz/mrzqrscanner/utils/OcrUtils.kt
around lines 249 to 268, createDummyMrz currently hard-codes nationality as
"ESP" and gender as Gender.MALE; change the MRZInfo construction to use the
function parameters (pass nationality and gender) instead of hard-coded values,
update the function signature to accept a nationality:String and gender:Gender
if not already present, and then update every call site to forward the parsed
nationality and parsed gender so the returned MRZInfo reflects the actual
document data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/android/app/build.gradle(1 hunks)app/android/settings.gradle(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/android/app/build.gradle
🧰 Additional context used
📓 Path-based instructions (1)
app/android/**/*
⚙️ CodeRabbit configuration file
app/android/**/*: Review Android-specific code for:
- Platform-specific implementations
- Performance considerations
- Security best practices for mobile
Files:
app/android/settings.gradle
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: e2e-ios
- GitHub Check: android-build-test
- GitHub Check: build-deps
- GitHub Check: analyze-android
- GitHub Check: analyze-ios
🔇 Additional comments (1)
app/android/settings.gradle (1)
13-14: LGTM: New scanner module added correctly.The android-mrz-qr-scanner module is properly declared and follows the existing project structure conventions.
| project(':passportreader').projectDir = new File(rootProject.projectDir, './android-passport-reader/app') | ||
| include ':android-mrz-qr-scanner' | ||
| project(':android-mrz-qr-scanner').projectDir = new File(rootProject.projectDir, './android-mrz-qr-scanner') | ||
| project(':passportreader').projectDir = new File(rootProject.projectDir, './android-passport-nfc-reader/app') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Duplicate ':passportreader' project configuration will break the build.
Lines 12 and 15 both declare the same project identifier ':passportreader' with different directory paths:
- Line 12:
./android-passport-reader/app - Line 15:
./android-passport-nfc-reader/app
Gradle will either fail the build or the second declaration will silently override the first, leading to unexpected behavior. Each project must have a unique identifier.
Verify which module declaration is correct and either:
- Remove the duplicate line, or
- Rename one of the projects (e.g., ':passportreader' vs ':passport-nfc-reader')
#!/bin/bash
# Verify which directories actually exist and contain build.gradle files
echo "Checking for android-passport-reader module:"
fd --type f --max-depth 3 "build.gradle" app/android/android-passport-reader
echo -e "\nChecking for android-passport-nfc-reader module:"
fd --type f --max-depth 3 "build.gradle" app/android/android-passport-nfc-reader🤖 Prompt for AI Agents
In app/android/settings.gradle around lines 12 to 15 there are duplicate
declarations for project(':passportreader') pointing at two different folders
which will break or silently override the build; resolve by verifying which
module is correct (check that each target folder exists and contains a
build.gradle), then either remove the incorrect duplicate line or rename one
declaration to a unique identifier (e.g., ':passport-nfc-reader'), update its
include statement accordingly, and ensure each project(...) call uses the
correct projectDir path so no two entries share the same project id.
|
@seshanthS since you're working on new native module logic, can we close this pull request? |
note: copies files from the mobile sdk but does not remove them
Summary by CodeRabbit