improve NFC reading UX on android #130

This commit is contained in:
BernalHQ
2024-08-07 01:04:53 -06:00
parent 0c3d115553
commit 0fbed199e1
3 changed files with 55 additions and 6 deletions

View File

@@ -114,6 +114,15 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
import com.facebook.react.bridge.LifecycleEventListener
import com.facebook.react.bridge.Callback
object Messages {
const val SCANNING = "Scanning....."
const val STOP_MOVING = "Stop moving....."
const val AUTH = "Auth....."
const val COMPARING = "Comparing....."
const val COMPLETED = "Scanning completed"
const val RESET = ""
}
class Response(json: String) : JSONObject(json) {
val type: String? = this.optString("type")
val data = this.optJSONArray("data")
@@ -171,6 +180,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
@ReactMethod
fun scan(opts: ReadableMap, promise: Promise) {
eventMessageEmitter(Messages.SCANNING)
val mNfcAdapter = NfcAdapter.getDefaultAdapter(reactApplicationContext)
// val mNfcAdapter = NfcAdapter.getDefaultAdapter(this.reactContext)
if (mNfcAdapter == null) {
@@ -261,6 +271,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
override fun doInBackground(vararg params: Void?): Exception? {
try {
eventMessageEmitter(Messages.STOP_MOVING)
isoDep.timeout = 10000
Log.e("MY_LOGS", "This should obvsly log")
val cardService = CardService.getInstance(isoDep)
@@ -349,7 +360,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// e.printStackTrace()
// }
// Log.d(TAG, "============LET'S VERIFY THE SIGNATURE=============")
eventMessageEmitter(Messages.AUTH)
doChipAuth(service)
doPassiveAuth()
@@ -372,6 +383,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
}
} catch (e: Exception) {
eventMessageEmitter(Messages.RESET)
return e
}
return null
@@ -409,8 +421,11 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val dataHashes = sodFile.dataGroupHashes
eventMessageEmitter("Reading DG14.....")
val dg14Hash = if (chipAuthSucceeded) digest.digest(dg14Encoded) else ByteArray(0)
eventMessageEmitter("Reading DG1.....")
val dg1Hash = digest.digest(dg1File.encoded)
eventMessageEmitter("Reading DG2.....")
val dg2Hash = digest.digest(dg2File.encoded)
// val gson = Gson()
@@ -432,7 +447,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// Log.d(TAG, "dg2HashjoinToString " + gson.toJson(dg2Hash.joinToString("") { "%02x".format(it) }))
Log.d(TAG, "Comparing data group hashes...")
eventMessageEmitter(Messages.COMPARING)
if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
&& (!chipAuthSucceeded || Arrays.equals(dg14Hash, dataHashes[14]))) {
@@ -498,6 +513,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
Log.d(TAG, "Passive authentication success: $passiveAuthSuccess")
}
} catch (e: Exception) {
eventMessageEmitter(Messages.RESET)
Log.w(TAG, "Exception in passive authentication", e)
}
}
@@ -538,6 +554,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val certificateBytes = certificate.encoded
val certificateBase64 = Base64.encodeToString(certificateBytes, Base64.DEFAULT)
Log.d(TAG, "certificateBase64: ${certificateBase64}")
passport.putString("documentSigningCertificate", certificateBase64)
@@ -609,7 +626,9 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
passport.putMap("photo", photo)
// passport.putString("dg2File", gson.toJson(dg2File))
eventMessageEmitter(Messages.COMPLETED)
scanPromise?.resolve(passport)
eventMessageEmitter(Messages.RESET)
resetState()
}
}
@@ -626,6 +645,16 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
}
}
private fun eventMessageEmitter(message: String) {
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit("NativeEvent", message)
} else {
Log.d(TAG, "Error")
}
}
companion object {
private val TAG = RNPassportReaderModule::class.java.simpleName
private const val PARAM_DOC_NUM = "documentNumber";

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3 } from 'tamagui'
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3, View } from 'tamagui'
import { HelpCircle, IterationCw, VenetianMask, Cog, CheckCircle2, ChevronLeft, Share, Eraser } from '@tamagui/lucide-icons';
import X from '../images/x.png'
import Telegram from '../images/telegram.png'
@@ -8,7 +8,7 @@ import Internet from "../images/internet.png"
import ProveScreen from './ProveScreen';
import { Steps } from '../utils/utils';
import AppScreen from './AppScreen';
import { Linking, Modal, Platform, Pressable } from 'react-native';
import { NativeEventEmitter, NativeModules, Linking, Modal, Platform, Pressable } from 'react-native';
import NFC_IMAGE from '../images/nfc.png'
import { bgColor, blueColorLight, borderColor, componentBgColor, textColor1, textColor2 } from '../utils/colors';
import SendProofScreen from './SendProofScreen';
@@ -26,9 +26,12 @@ import Dialog from "react-native-dialog";
import { contribute } from '../utils/contribute';
import RegisterScreen from './RegisterScreen';
const { nativeModule } = NativeModules;
const emitter = new NativeEventEmitter(nativeModule);
const MainScreen: React.FC = () => {
const [NFCScanIsOpen, setNFCScanIsOpen] = useState(false);
const [scanningMessage, setScanningMessage] = useState('');
const [displayOtherOptions, setDisplayOtherOptions] = useState(false);
const [SettingsIsOpen, setSettingsIsOpen] = useState(false);
const [DialogContributeIsOpen, setDialogContributeIsOpen] = useState(false);
@@ -123,6 +126,18 @@ const MainScreen: React.FC = () => {
setDialogDeleteSecretIsOpen(false);
}
useEffect(() => {
const handleNativeEvent = (event: string) => {
setScanningMessage(event);
};
const subscription = emitter.addListener('NativeEvent', handleNativeEvent);
return () => {
subscription.remove();
};
}, []);
useEffect(() => {
if (passportNumber?.length === 9 && (dateOfBirth?.length === 6 && dateOfExpiry?.length === 6)) {
setStep(Steps.MRZ_SCAN_COMPLETED);
@@ -207,8 +222,13 @@ const MainScreen: React.FC = () => {
<Sheet open={NFCScanIsOpen} onOpenChange={setNFCScanIsOpen} dismissOnSnapToBottom modal dismissOnOverlayPress={false} disableDrag animation="medium" snapPoints={[35]}>
<Sheet.Overlay />
<Sheet.Frame>
<YStack gap="$5" f={1} pt="$3">
<H2 textAlign='center'>Ready to scan</H2>
<View>
<H2 textAlign='center'>Ready to scan</H2>
<Text textAlign='center'>{scanningMessage}</Text>
</View>
{step >= Steps.NEXT_SCREEN ?
<CheckCircle2
size="$8"

View File

@@ -213,7 +213,7 @@ const handleResponseAndroid = async (
encapContent,
documentSigningCertificate
} = response;
amplitude.track('Sig alg before conversion: ' + signatureAlgorithm);
const pem = "-----BEGIN CERTIFICATE-----" + documentSigningCertificate + "-----END CERTIFICATE-----"