diff --git a/.env.example b/.env.example index 2db4b3b..cf3e1e9 100644 --- a/.env.example +++ b/.env.example @@ -72,4 +72,6 @@ APPCENTER_BUILD_ID=1 ENFServerUrl= # Google's SafetynetKey for Device Attestation API -SafetynetKey= \ No newline at end of file +SafetynetKey= + +ENFCheckInterval= \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e07f371..28b2817 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -276,7 +276,7 @@ PODS: - react-native-config/App (= 1.3.3) - react-native-config/App (1.3.3): - React - - react-native-exposure-notification-service (1.1.44): + - react-native-exposure-notification-service (1.2.6): - Alamofire (~> 5.2) - KeychainSwift (~> 19.0) - React @@ -450,7 +450,7 @@ DEPENDENCIES: - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: - https://cdn.cocoapods.org/: + trunk: - Alamofire - AppCenter - AppCenterReactNativeShared @@ -620,7 +620,7 @@ SPEC CHECKSUMS: React-jsinspector: b14e62ebe7a66e9231e9581279909f2fc3db6606 react-native-camera: 35854c4f764a4a6cf61c1c3525888b92f0fe4b31 react-native-config: 9a061347e0136fdb32d43a34d60999297d672361 - react-native-exposure-notification-service: 32ca3fa42976b518bf0a8e2b0bf16810d75e41b9 + react-native-exposure-notification-service: bc9fe5ece6048ac6eca17f5649367014a6bfbfc2 react-native-netinfo: 250dc0ca126512f618a8a2ca6a936577e1f66586 react-native-safe-area-context: 955ecfce672683b495d9294d2f154a9ad1d9796b react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 @@ -657,4 +657,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9a46cbeb408836d3fa898d9ed314381af73a92d1 -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.1 diff --git a/package.json b/package.json index ceb98ee..e571695 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "react-native-config": "^1.3.3", "react-native-country-picker-modal": "^2.0.0", "react-native-device-info": "^6.0.2", - "react-native-exposure-notification-service": "^1.1.44", + "react-native-exposure-notification-service": "1.2.6", "react-native-gesture-handler": "^1.8.0", "react-native-google-safetynet": "^1.0.0", "react-native-haptic-feedback": "^1.11.0", diff --git a/scripts/setenv.sh b/scripts/setenv.sh index ed9cfb9..447442b 100755 --- a/scripts/setenv.sh +++ b/scripts/setenv.sh @@ -25,6 +25,7 @@ echo "APP_VERSION=${APP_VERSION}" >>.env echo "APPCENTER_BUILD_ID=${APPCENTER_BUILD_ID}" >>.env echo "ENFServerUrl=${ENFServerUrl}" >>.env echo "SafetynetKey=${SafetynetKey}" >>.env +echo "ENFCheckInterval=${ENFCheckInterval}" >>.env printf "\n.env created with contents:\n" diff --git a/src/__snapshots__/config.spec.ts.snap b/src/__snapshots__/config.spec.ts.snap index 3c05c75..771e9d4 100644 --- a/src/__snapshots__/config.spec.ts.snap +++ b/src/__snapshots__/config.spec.ts.snap @@ -18,6 +18,7 @@ Object { "ContactAlertsUrl": "https://www.health.govt.nz/nz-covid-tracer-contact-alerts", "ContactUsPageUrl": "https://www.health.govt.nz/our-work/diseases-and-conditions/covid-19-novel-coronavirus/covid-19-resources-and-tools/nz-covid-tracer-app/contact-nz-covid-tracer", "DbEncryptionKey": "", + "ENFCheckInterval": 180, "ENFServerUrl": "", "ExposureEventsBaseUrl": "https://exposure-events.", "Features": Set {}, diff --git a/src/config.ts b/src/config.ts index 582c030..0211939 100644 --- a/src/config.ts +++ b/src/config.ts @@ -32,6 +32,7 @@ export interface AppConfigRaw { ANDROID_VERSION_CODE_OFFSET?: string; ENFServerUrl?: string; SafetynetKey?: string; + ENFCheckInterval?: string; } export interface AppConfig { @@ -65,6 +66,7 @@ export interface AppConfig { APPCENTER_BUILD_ID: string; ENFServerUrl: string; SafetynetKey: string; + ENFCheckInterval: number; } export let disableAnimations = false; @@ -119,6 +121,16 @@ export const getBuildId = (offset?: string, buildId?: string) => { export { buildUrl as _buildUrl }; +const getENFCheckInterval = () => { + if (raw.ENFCheckInterval) { + const parsed = parseInt(raw.ENFCheckInterval); + if (!isNaN(parsed)) { + return Math.max(15, parsed); + } + } + return 180; +}; + const config: AppConfig = { APIServiceAddress: raw.APIServiceAddress || "", AppAddress: raw.AppAddress || "", @@ -169,6 +181,7 @@ const config: AppConfig = { ), ENFServerUrl: raw.ENFServerUrl || "", SafetynetKey: raw.SafetynetKey || "", + ENFCheckInterval: getENFCheckInterval(), }; export default config; diff --git a/src/features/debugging/commands/enfCheckExposure.ts b/src/features/debugging/commands/enfCheckExposure.ts index 0a177c7..f36bbbd 100644 --- a/src/features/debugging/commands/enfCheckExposure.ts +++ b/src/features/debugging/commands/enfCheckExposure.ts @@ -9,7 +9,7 @@ export const enfCheckExposure = ( title: "Check Exposure", async run() { const { checkExposure } = exposure; - checkExposure(true, false); + checkExposure(false); Alert.alert("checkExposure", "Done"); }, }); diff --git a/src/features/debugging/commands/enfContacts.ts b/src/features/debugging/commands/enfContacts.ts index ddb69e6..a51c8e8 100644 --- a/src/features/debugging/commands/enfContacts.ts +++ b/src/features/debugging/commands/enfContacts.ts @@ -11,7 +11,7 @@ export const enfContacts = (exposure: ExposureContextValue): TestCommand => ({ const contacts = await getCloseContacts(); const latestExposureDate = contacts?.reduce((max, contact) => { - const exposureDate = moment(parseInt(contact.exposureAlertDate, 10)) + const exposureDate = moment(contact.exposureAlertDate) .subtract(contact.daysSinceLastExposure, "days") .valueOf(); return max > exposureDate ? max : exposureDate; @@ -21,12 +21,12 @@ export const enfContacts = (exposure: ExposureContextValue): TestCommand => ({ (acc, contact, ix, array) => acc .concat( - `Alert date: ${moment( - parseInt(contact.exposureAlertDate, 10), - ).format("DD MMM HH:mm")}`, + `Alert date: ${moment(contact.exposureAlertDate).format( + "DD MMM HH:mm", + )}`, ) .concat( - `\nExposure date: ${moment(parseInt(contact.exposureAlertDate, 10)) + `\nExposure date: ${moment(contact.exposureAlertDate) .subtract(contact.daysSinceLastExposure, "days") .format("DD MMM HH:mm")}`, ) diff --git a/src/features/debugging/commands/enfSimulateExposure.ts b/src/features/debugging/commands/enfSimulateExposure.ts index b34151a..d7bde94 100644 --- a/src/features/debugging/commands/enfSimulateExposure.ts +++ b/src/features/debugging/commands/enfSimulateExposure.ts @@ -18,6 +18,6 @@ export const enfSimulateExposure = ( return; } } - exposure.simulateExposure(0); + exposure.simulateExposure(0, 0); }, }); diff --git a/src/features/enf/components/ExposureProvider.tsx b/src/features/enf/components/ExposureProvider.tsx index 9f9e4d7..6739c43 100644 --- a/src/features/enf/components/ExposureProvider.tsx +++ b/src/features/enf/components/ExposureProvider.tsx @@ -27,7 +27,7 @@ export function ExposureProvider(props: ExposureProviderProps) { keyServerUrl: config.ENFServerUrl, keyServerType: KeyServerType.nearform, traceConfiguration: { - exposureCheckInterval: 180, + exposureCheckInterval: config.ENFCheckInterval, storeExposuresFor: 14, fileLimit: 1, fileLimitiOS: 3, diff --git a/src/features/enfExposure/analytics.ts b/src/features/enfExposure/analytics.ts index c6dcbf9..6480909 100644 --- a/src/features/enfExposure/analytics.ts +++ b/src/features/enfExposure/analytics.ts @@ -16,9 +16,7 @@ export const recordDismissENFAlert = (enfAlert: ENFAlertData) => { export const recordDisplayENFAlert = (match: CloseContact) => { recordAnalyticEvent(ENFEvent.ENFBannerDisplayed, { attributes: { - alertDate: moment(parseInt(match.exposureAlertDate, 10)).format( - "DD MMM YYYY", - ), + alertDate: moment(match.exposureAlertDate).format("DD MMM YYYY"), }, metrics: { riskScore: match.maxRiskScore, diff --git a/src/features/enfExposure/sagas/updateENFAlert.spec.ts b/src/features/enfExposure/sagas/updateENFAlert.spec.ts index a650513..3f26ac6 100644 --- a/src/features/enfExposure/sagas/updateENFAlert.spec.ts +++ b/src/features/enfExposure/sagas/updateENFAlert.spec.ts @@ -13,29 +13,33 @@ import { import updateENFAlert from "./updateENFAlert"; const CONTACT1: CloseContact = { - exposureAlertDate: moment("2020-11-10T00:00:00.000Z").valueOf().toString(), + exposureAlertDate: moment("2020-11-10T00:00:00.000Z").valueOf(), daysSinceLastExposure: 2, attenuationDurations: [], matchedKeyCount: 1, maxRiskScore: 10, - summationRiskScore: 10, + riskScoreSumFullRange: 10, + maxRiskScoreFullRange: 10, + exposureDate: moment("2020-11-10T00:00:00.000Z").valueOf(), }; // the most recent exposure date, alert date is between contact1 and 3 -const CONTACT2 = { +const CONTACT2: CloseContact = { maxRiskScore: 120, - exposureAlertDate: moment("2020-11-15T00:00:00.000Z").valueOf().toString(), + exposureAlertDate: moment("2020-11-15T00:00:00.000Z").valueOf(), daysSinceLastExposure: 2, attenuationDurations: [], matchedKeyCount: 1, - summationRiskScore: 120, + riskScoreSumFullRange: 120, + maxRiskScoreFullRange: 120, + exposureDate: moment("2020-11-15T00:00:00.000Z").valueOf(), }; // this one has the most recent alert date, but not recent exposure date -const CONTACT3 = { +const CONTACT3: CloseContact = { ...CONTACT1, maxRiskScore: 10, - exposureAlertDate: moment("2020-11-20T00:00:00.000Z").valueOf().toString(), + exposureAlertDate: moment("2020-11-20T00:00:00.000Z").valueOf(), daysSinceLastExposure: 10, matchedKeyCount: 2, }; @@ -47,8 +51,8 @@ const RESULT_FROM_CONTACT1_BUCKET0: ENFAlertData = { alertTitle: enfConfig[0].alertTitle, alertMessage: enfConfig[0].alertMessage, linkUrl: enfConfig[0].linkUrl, - alertDate: parseInt(CONTACT1.exposureAlertDate, 10), - exposureDate: moment(parseInt(CONTACT1.exposureAlertDate, 10)) + alertDate: CONTACT1.exposureAlertDate, + exposureDate: moment(CONTACT1.exposureAlertDate) .subtract(CONTACT1.daysSinceLastExposure, "days") .valueOf(), exposureCount: 1, @@ -58,8 +62,8 @@ const RESULT_FROM_CONTACT2_BUCKET2: ENFAlertData = { alertTitle: enfConfig[2].alertTitle, alertMessage: enfConfig[2].alertMessage, linkUrl: enfConfig[2].linkUrl, - alertDate: parseInt(CONTACT2.exposureAlertDate, 10), - exposureDate: moment(parseInt(CONTACT2.exposureAlertDate, 10)) + alertDate: CONTACT2.exposureAlertDate, + exposureDate: moment(CONTACT2.exposureAlertDate) .subtract(CONTACT2.daysSinceLastExposure, "days") .valueOf(), exposureCount: 1, @@ -69,8 +73,8 @@ const RESULT_FROM_CONTACT2_BUCKET2_1: ENFAlertData = { alertTitle: enfConfig[2].alertTitle, alertMessage: enfConfig[2].alertMessage, linkUrl: enfConfig[2].linkUrl, - alertDate: parseInt(CONTACT2.exposureAlertDate, 10), - exposureDate: moment(parseInt(CONTACT2.exposureAlertDate, 10)) + alertDate: CONTACT2.exposureAlertDate, + exposureDate: moment(CONTACT2.exposureAlertDate) .subtract(CONTACT2.daysSinceLastExposure, "days") .valueOf(), exposureCount: 3, diff --git a/src/features/enfExposure/sagas/updateENFAlert.ts b/src/features/enfExposure/sagas/updateENFAlert.ts index d0ba28e..d5147c0 100644 --- a/src/features/enfExposure/sagas/updateENFAlert.ts +++ b/src/features/enfExposure/sagas/updateENFAlert.ts @@ -43,12 +43,12 @@ export default function* updateENFAlert( const match = contacts.reduce( (current, contact) => { const currentExposureDate = current - ? moment(parseInt(contact.exposureAlertDate, 10)) + ? moment(contact.exposureAlertDate) .subtract(contact.daysSinceLastExposure, "days") .valueOf() : 0; - const exposureDate = moment(parseInt(contact.exposureAlertDate, 10)) + const exposureDate = moment(contact.exposureAlertDate) .subtract(contact.daysSinceLastExposure, "days") .valueOf(); @@ -87,7 +87,7 @@ export default function* updateENFAlert( return; } - const alertDate = parseInt(match.exposureAlertDate, 10); + const alertDate = match.exposureAlertDate; const result: ENFAlertData = { exposureCount, diff --git a/src/features/scan/views/Scan.tsx b/src/features/scan/views/Scan.tsx index 3a3a119..6837e55 100644 --- a/src/features/scan/views/Scan.tsx +++ b/src/features/scan/views/Scan.tsx @@ -371,28 +371,23 @@ export function Scan(props: Props) { [canScanBarcode, currentUserId, isFocused, saveEntryAsync, showError, t], ); + const appState = useAppState(); + const showCamera = useMemo( - () => isCameraMounted && cameraPermission === "granted", - [isCameraMounted, cameraPermission], + () => + appState !== "background" && + isCameraMounted && + cameraPermission === "granted", + [isCameraMounted, cameraPermission, appState], ); - const appState = useAppState(); - useEffect(() => { - if (cameraRef.current == null) { - return; - } - switch (appState) { - case "background": - logInfo("pause preview"); - cameraRef.current.pausePreview(); - break; - case "active": - logInfo("resume preview"); - cameraRef.current.resumePreview(); - break; + if (showCamera) { + logInfo("show camera"); + } else { + logInfo("hide camera"); } - }, [appState]); + }, [showCamera]); useAccessibleTitle(); diff --git a/yarn.lock b/yarn.lock index e6e1577..104992d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9387,10 +9387,10 @@ react-native-device-info@^6.0.2: resolved "https://registry.yarnpkg.com/react-native-device-info/-/react-native-device-info-6.2.1.tgz#6b63faeef833d8959d636c0413ccd5066eada2bf" integrity sha512-+9Li07jD+7IiSIn9VVmb1YWYfJtgERVMsgO/hG+aUzsFD6uFklpM2TOEBlfKPWP/8J6s8MZgpGfA/Dl1WZrn2g== -react-native-exposure-notification-service@^1.1.44: - version "1.1.44" - resolved "https://registry.yarnpkg.com/react-native-exposure-notification-service/-/react-native-exposure-notification-service-1.1.44.tgz#bf02c63efa98f61cff4c01b0a7eb150c094d6640" - integrity sha512-sL4+NnVcWSjh9l8S2oLHMJh5YPEJGGg0jKAqERoKlwS2lA51uWJGS7/DcHDQSTiiwp5y4EEvPF4ZJ4y5YjM4sA== +react-native-exposure-notification-service@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/react-native-exposure-notification-service/-/react-native-exposure-notification-service-1.2.6.tgz#e0ba0b80352d243b7843ee01edd669a372198abd" + integrity sha512-BJwgj1G0iN+5vvJgCgN3z6tdEVz3xXzrKPqoTk6Z0BTl9bQ47VEhHsILvygc5aN5HKJM78eBsQezccgLNDrLpg== react-native-flipper@^0.34.0: version "0.34.0"