From 16ccdee731664706dfe986da4d4692ccecb8b97e Mon Sep 17 00:00:00 2001 From: alpita-masurkar Date: Sun, 29 Mar 2020 17:01:06 +0200 Subject: [PATCH 1/2] Spanish translation update_Miquel (#272) * Update index.js * Create notification.json * Update overlap.json --- app/locales/es/index.js | 14 ++++++++------ app/locales/es/notification.json | 8 ++++++++ app/locales/es/overlap.json | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 app/locales/es/notification.json diff --git a/app/locales/es/index.js b/app/locales/es/index.js index 4cba49d83d..8e4028faaf 100644 --- a/app/locales/es/index.js +++ b/app/locales/es/index.js @@ -4,12 +4,14 @@ import importFile from './import.json'; import exportFile from './exportscreen.json'; import licensesFile from './licensesscreen.json'; import overlapFile from './overlap.json'; +import notificationFile from './notification.json'; export default { - ...intro, - ...locationTracking, - ...importFile, - ...exportFile, - ...overlapFile, - ...licensesFile, + ...intro, + ...locationTracking, + ...importFile, + ...exportFile, + ...overlapFile, + ...licensesFile, + ...notificationFile, }; diff --git a/app/locales/es/notification.json b/app/locales/es/notification.json new file mode 100644 index 0000000000..692df5ed9a --- /dev/null +++ b/app/locales/es/notification.json @@ -0,0 +1,8 @@ +{ + "notification_main_text": "Comprueba tus posibles puntos de encuentro a diario", + "notification_title": "Analizar tus puntos de encuentro", + "notification_data_not_available": "\n\nNo tienes información pública de posibles puntos de encuentro descargada!\n\n", + "notification_warning_text": "Pues hacer click en el siguiente botón para generar una simulación de puntos de encuentro. \nAVISO: Estos puntos de encuentro no son casos reales, sino simulaciones", + "notification_random_data_button": "Haz click en este botón para generar una simulación", + "notifications":"Notificaciones" +} diff --git a/app/locales/es/overlap.json b/app/locales/es/overlap.json index 2bd53e9903..25daba5cb7 100644 --- a/app/locales/es/overlap.json +++ b/app/locales/es/overlap.json @@ -1,7 +1,7 @@ { "overlap_title": "Comprobar posibles puntos de encuentro", - "overlap_para_1": "Los círculos verdes indican las ubicaciones en las que te has registrado más veces. Amplia el mapa para ver los marcadores rojos, que indican tus ubicaciones exactas guardadas en cada momento. \n\nHaz click en el botón para descargar la información pública sobre casos confirmados, que se muestra con los círculos de color púrpura claro.", - "show_overlap": "Incorporar información pública", + "overlap_para_1": "El registro de color verde representa tu historial de localizaciones\n\nLos círculos de color púrpura claro representan la información pública actual", + "show_overlap": "Haz click para ver la información pública disponible", "loading_public_data": "cargando datos...", "overlap_no_results_button_label": "Información pública incorporada", "overlap_found_button_label": "Información pública incorporada", From e5fcb63916fe9a546952a05a4e95d8b5bdad1381 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sun, 29 Mar 2020 12:04:27 -0400 Subject: [PATCH 2/2] Version 0.5.10 (#251) * Running build on develop. * Keeping action to Master * Starting Bluetooth Beacon Broadcasting. * Other ID was too big. * Only runs Bluetooth on Android * Changing Package version to 0.0.4 to pass tests on Phones without Bluetooth adapters. * 0.5.7 * 0.5.8 * Migrating Bluetooth to 0.0.5 * Removing the tag for just build number increments on new versions. * 0.5.9 * 0.5.10 * Saving contacts and Requesting permissions to turn bluetooth on --- android/app/build.gradle | 4 +- app/services/BroadcastingService.js | 256 +++++++++++++++++++++------- ios/PrivateKit/Info.plist | 4 +- ios/PrivateKitTests/Info.plist | 4 +- package-lock.json | 2 +- package.json | 8 +- 6 files changed, 209 insertions(+), 69 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 845ac5a0af..d2f8af42e3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -132,8 +132,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled true - versionCode 14 - versionName "0.5.9" + versionCode 15 + versionName "0.5.10" } splits { abi { diff --git a/app/services/BroadcastingService.js b/app/services/BroadcastingService.js index 5cc6758340..61b9c974ad 100644 --- a/app/services/BroadcastingService.js +++ b/app/services/BroadcastingService.js @@ -1,127 +1,265 @@ import { GetStoreData, SetStoreData } from '../helpers/General'; - +import { Alert, Platform } from 'react-native'; import BackgroundTimer from 'react-native-background-timer'; import UUIDGenerator from 'react-native-uuid-generator'; import Moment from 'moment'; import AndroidBLEAdvertiserModule from 'react-native-ble-advertiser'; +import { NativeEventEmitter, NativeModules } from 'react-native'; var currentUUID = null; +var onDeviceFound = null; +var onBTStatusChange = null; +var lastSeen = {}; -function saveContact(contact) { - // Persist this contact data in our local storage of time/lat/lon values +const c5_MINS = 1000 * 60 * 5; +const c28_DAYS = 1000 * 60 * 60 * 24 * 28; +const c1_HOUR = 1000 * 60; - GetStoreData('CONTACT_DATA').then(contactArrayString => { - var contactArray; - if (contactArrayString !== null) { - contactArray = JSON.parse(contactArrayString); - } else { - contactArray = []; +const MANUFACTURER_ID = 0xff; +const MANUFACTURER_DATA = [12, 23, 56]; + +function nowStr() { + return Moment(new Date()).format('H:mm') +} + +/* + * Check if the contact is new in the last 5 mins. + */ +function isNewContact(contact) { + var nowLocal = new Date().getTime(); + if (lastSeen[contact['uuid']] && lastSeen[contact['uuid']] > nowLocal - c5_MINS) { + //console.log('[Bluetooth]', nowStr(), currentUUID, 'Ignoring UUID for 5 mins:', contact['uuid']); + return false; // needs a space of 5 mins to log again. + } + + lastSeen[contact['uuid']] = nowLocal; + return true; +} + +/* + * Select only the last 28 days of data. + */ +function filterAfter(arrayIncludingTime, time) { + let curated = []; + for (let i = 0; i < arrayIncludingTime.length; i++) { + if (arrayIncludingTime[i]['time'] > time) { + curated.push(arrayIncludingTime[i]); + } } + return curated; +} - // Always work in UTC, not the local time in the contactData - var nowUTC = new Date().toISOString(); - var unixtimeUTC = Date.parse(nowUTC); - var unixtimeUTC_28daysAgo = unixtimeUTC - 60 * 60 * 24 * 1000 * 28; - - // Save the contact using the current lat-lon and the - // calculated UTC time (maybe a few milliseconds off from - // when the GPS data was collected, but that's unimportant - // for what we are doing.) - console.log('[GPS] Saving point:', contactArray.length); - var lat_lon_time = { - uuid: contact['uuid'], - time: unixtimeUTC, - }; - contactArray.push(lat_lon_time); +function saveContact(contact) { + // Persist this contact data in our local storage of time/uuid values + //console.log('[Bluetooth]', nowStr(), currentUUID, 'New Device Found', contact['uuid']); + if (isNewContact(contact)) { + GetStoreData('CONTACT_DATA', false).then(contactArray => { + if (!contactArray) { + contactArray = []; + } - SetStoreData('CONTACT_DATA', contactArray); - }); + // Always work in UTC, not the local time in the contactData + var nowUTC = new Date().toISOString(); + var unixtimeUTC = Date.parse(nowUTC); + + // Curate the list of contacts, only keep the last 28 days + let curated = filterAfter(contactArray, unixtimeUTC - c28_DAYS); + + var uuid_time = { + uuid: contact['uuid'], + time: unixtimeUTC, + }; + curated.push(uuid_time); + console.log('[Bluetooth]', nowStr(), currentUUID, + 'Saving contact:', contact['uuid'], curated.length); + + SetStoreData('CONTACT_DATA', curated); + }); + } } function saveMyUUID(me) { // Persist this contact data in our local storage of time/lat/lon values - GetStoreData('MY_UUIDs').then(myUUIDArrayString => { - var myUUIDArray; - if (myUUIDArrayString !== null) { - myUUIDArray = JSON.parse(myUUIDArrayString); - } else { + GetStoreData('MY_UUIDs', false).then(myUUIDArray => { + if (!myUUIDArray) { myUUIDArray = []; } // Always work in UTC, not the local time in the contactData var nowUTC = new Date().toISOString(); var unixtimeUTC = Date.parse(nowUTC); - var unixtimeUTC_28daysAgo = unixtimeUTC - 60 * 60 * 24 * 1000 * 28; + + // Curate the list of points, only keep the last 28 days + let curated = filterAfter(myUUIDArray, unixtimeUTC - c28_DAYS); var uuid_time = { uuid: me['uuid'], time: unixtimeUTC, }; + console.log( - '[GPS] Saving myUUID:', - Moment(unixtimeUTC).format('MMM Do, H:mma'), - me['uuid'], - myUUIDArray.length, + '[Bluetooth]', nowStr(), me['uuid'], + 'Saving myUUID:', me['uuid'], curated.length, ); - myUUIDArray.push(uuid_time); + curated.push(uuid_time); - SetStoreData('MY_UUIDs', myUUIDArray); + SetStoreData('MY_UUIDs', curated); }); } function loadLastUUIDAndBroadcast() { - GetStoreData('MY_UUIDs').then(myUUIDArrayString => { - var myUUIDArray; - if (myUUIDArrayString !== null) { - myUUIDArray = JSON.parse(myUUIDArrayString); + GetStoreData('MY_UUIDs', false).then(myUUIDArray => { + if (!myUUIDArray) { console.log( - 'Loading last uuid ', + '[Bluetooth]', nowStr(), myUUIDArray[myUUIDArray.length - 1].uuid, + 'Loading last uuid' ); - currentUUID = myUUIDArray[myUUIDArray.length - 1].uuid; - broadcast(); + var lastUUID = myUUIDArray[myUUIDArray.length - 1].uuid; + broadcast(lastUUID); } else { generateNewUUIDAndBroadcast(); } }); } -function broadcast() { +function broadcast(currentUUID) { + if (!currentUUID) return; // does not allow to start without UUID + // Do not run on iOS for now. if (Platform.OS === 'android') { - console.log('Broadcasting: ', currentUUID); - AndroidBLEAdvertiserModule.setCompanyId(0xff); - AndroidBLEAdvertiserModule.broadcast(currentUUID, [12, 23, 56]) - .then(sucess => { - console.log('Broadcasting Sucessful', sucess); - }) - .catch(error => console.log('Broadcasting Error', error)); + //console.log('[Bluetooth]', nowStr(), currentUUID, 'Broadcasting'); + AndroidBLEAdvertiserModule.setCompanyId(MANUFACTURER_ID); + AndroidBLEAdvertiserModule.broadcast(currentUUID, MANUFACTURER_DATA) + .then(success => console.log('[Bluetooth]', nowStr(), currentUUID, 'Broadcasting Sucessful', success)) + .catch(error => console.log('[Bluetooth]', nowStr(), currentUUID, 'Broadcasting Error', error)); + + //console.log('[Bluetooth]', nowStr(), currentUUID, "Starting Scanner"); + AndroidBLEAdvertiserModule.scan(MANUFACTURER_DATA, {}) + .then(success => console.log('[Bluetooth]', nowStr(), currentUUID, "Scan Successful", success)) + .catch(error => console.log('[Bluetooth]', nowStr(), currentUUID, "Scan Error", error)); + } +} + +function stopBroadcast(currentUUID) { + if (!currentUUID) return; // does not allow to start without UUID + + // Do not run on iOS for now. + if (Platform.OS === 'android') { + //console.log('[Bluetooth]', nowStr(), currentUUID, 'Stopping Broadcast'); + AndroidBLEAdvertiserModule.stopBroadcast() + .then(success => console.log('[Bluetooth]', nowStr(), currentUUID, "Stop Broadcast Successful", success)) + .catch(error => console.log('[Bluetooth]', nowStr(), currentUUID, "Stop Broadcast Error", error)); + + //console.log('[Bluetooth]', nowStr(), currentUUID, "Stopping Scanning"); + AndroidBLEAdvertiserModule.stopScan() + .then(success => console.log('[Bluetooth]', nowStr(), currentUUID, "Stop Scan Successful", success)) + .catch(error => console.log('[Bluetooth]', nowStr(), currentUUID, "Stop Scan Error", error)); } } function generateNewUUIDAndBroadcast() { UUIDGenerator.getRandomUUID(uuid => { + console.log('[Bluetooth]', nowStr(), currentUUID, 'Renewing this UUID'); + stopBroadcast(currentUUID); + currentUUID = uuid; saveMyUUID({ uuid: uuid }); - broadcast(); + + broadcast(currentUUID); }); } export default class BroadcastingServices { + static isBTActive() { + AndroidBLEAdvertiserModule.getAdapterState().then(result => { + console.log('[Bluetooth]', nowStr(), currentUUID, 'Bluetooth State', result); + if (result != 12) { + setTimeout(() => + Alert.alert( + 'Private Kit requires bluetooth to be enabled', + 'Would you like to enable Bluetooth?', + [ + { + text: 'Yes', + onPress: () => AndroidBLEAdvertiserModule.enableAdapter(), + }, + { + text: 'No', + onPress: () => console.log('No Pressed'), + style: 'cancel', + }, + ], + ), + 1000); + return false; + } else { + return true; + } + }).catch(error => { + return false; + console.log('[Bluetooth]', nowStr(), currentUUID, "BT Not Enabled") + }); + } + static start() { + const eventEmitter = new NativeEventEmitter(NativeModules.AndroidBLEAdvertiserModule); + onBTStatusChange = eventEmitter.addListener('onBTStatusChange', (status) => { + if (status.enabled) + BroadcastingServices.startAndSetCallbacks(); + else + BroadcastingServices.stopAndClearCallbacks(); + }); + + if (!BroadcastingServices.isBTActive()) return; + + BroadcastingServices.startAndSetCallbacks(); + } + + static stop() { + if (onBTStatusChange) { + onBTStatusChange.remove(); + onBTStatusChange = null; + } + + if (!BroadcastingServices.isBTActive()) return; + + BroadcastingServices.stopAndClearCallbacks(); + } + + static startAndSetCallbacks() { + // if it was already active + if (onDeviceFound) { + BroadcastingServices.stopAndClearCallbacks(); + } + + // listening event. + const eventEmitter = new NativeEventEmitter(NativeModules.AndroidBLEAdvertiserModule); + onDeviceFound = eventEmitter.addListener('onDeviceFound', (event) => { + //console.log('[Bluetooth]', nowStr(), currentUUID, 'New Device', event); + if (event.serviceUuids && event.serviceUuids.length > 0) + saveContact({ uuid: event.serviceUuids[0]}); + }); + + // Get a Valid UUID and start broadcasting and scanning. loadLastUUIDAndBroadcast(); BackgroundTimer.runBackgroundTimer(() => { generateNewUUIDAndBroadcast(); - }, 1000 * 60 * 60); // Every hour, change UUID - - console.log('Starting Bluetooth'); + }, c1_HOUR); // Every hour, change UUID } - static stop(nav) { - console.log('Stopping Bluetooth'); + static stopAndClearCallbacks() { + //console.log('[Bluetooth]', nowStr(), currentUUID, 'Stopping Bluetooth'); + stopBroadcast(currentUUID); + + if (onDeviceFound) { + onDeviceFound.remove(); + onDeviceFound = null; + } + BackgroundTimer.stopBackgroundTimer(); } } diff --git a/ios/PrivateKit/Info.plist b/ios/PrivateKit/Info.plist index 9100f0d3e8..aff1738a08 100644 --- a/ios/PrivateKit/Info.plist +++ b/ios/PrivateKit/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.5.9 + 0.5.10 CFBundleSignature ???? CFBundleVersion - 14 + 15 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/ios/PrivateKitTests/Info.plist b/ios/PrivateKitTests/Info.plist index df5a366899..06fd4cccd2 100644 --- a/ios/PrivateKitTests/Info.plist +++ b/ios/PrivateKitTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.5.9 + 0.5.10 CFBundleSignature ???? CFBundleVersion - 14 + 15 diff --git a/package-lock.json b/package-lock.json index 34d7709677..0668e15b78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "privatekit", - "version": "0.5.9", + "version": "0.5.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 991bbcf7e2..460c086c8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "privatekit", - "version": "0.5.9", + "version": "0.5.10", "private": true, "scripts": { "install:pod": "cd ios && pod install", @@ -45,7 +45,7 @@ "react-native": "0.61.5", "react-native-app-intro-slider": "^3.0.0", "react-native-background-timer": "^2.2.0", - "react-native-ble-advertiser": "0.0.5", + "react-native-ble-advertiser": "0.0.9", "react-native-extended-stylesheet": "^0.12.0", "react-native-fs": "^2.16.6", "react-native-gesture-handler": "~1.5.0", @@ -80,6 +80,8 @@ }, "jest": { "preset": "react-native", - "setupFiles": ["./jestSetupFile.js"] + "setupFiles": [ + "./jestSetupFile.js" + ] } }