From 0e01a566cbc3b99d17142d9681e16cceffcdd2ab Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Sun, 5 Apr 2020 22:21:14 -0700 Subject: [PATCH 1/3] Ensure that UnifiedDataLoader is only local for this version Strip out the remote promise and all the dups. Only return the local promise and don't do any merging Load time on the phone is now significantly faster --- www/js/services.js | 56 ++++------------------------------------------ 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/www/js/services.js b/www/js/services.js index 33a324f7d..e30ed006e 100644 --- a/www/js/services.js +++ b/www/js/services.js @@ -179,61 +179,13 @@ angular.module('emission.services', ['emission.plugin.logger', } }) .service('UnifiedDataLoader', function($window, CommHelper, Logger) { - var combineWithDedup = function(list1, list2) { - var combinedList = list1.concat(list2); - return combinedList.filter(function(value, i, array) { - var firstIndexOfValue = array.findIndex(function(element, index, array) { - return element.metadata.write_ts == value.metadata.write_ts; - }); - return firstIndexOfValue == i; - }); - }; - // TODO: generalize to iterable of promises var combinedPromise = function(localPromise, remotePromise, combiner) { - return new Promise(function(resolve, reject) { - var localResult = []; - var localError = null; - - var remoteResult = []; - var remoteError = null; - - var localPromiseDone = false; - var remotePromiseDone = false; - - var checkAndResolve = function() { - if (localPromiseDone && remotePromiseDone) { - // time to return from this promise - if (localError && remoteError) { - reject([localError, remoteError]); - } else { - Logger.log("About to dedup localResult = "+localResult.length - +"remoteResult = "+remoteResult.length); - var dedupedList = combiner(localResult, remoteResult); - Logger.log("Deduped list = "+dedupedList.length); - resolve(dedupedList); - } - } - }; + return localPromise; + } - localPromise.then(function(currentLocalResult) { - localResult = currentLocalResult; - localPromiseDone = true; - }, function(error) { - localResult = []; - localError = error; - localPromiseDone = true; - }).then(checkAndResolve); - - remotePromise.then(function(currentRemoteResult) { - remoteResult = currentRemoteResult; - remotePromiseDone = true; - }, function(error) { - remoteResult = []; - remoteError = error; - remotePromiseDone = true; - }).then(checkAndResolve); - }) + var combineWithDedup = function(list1, list2) { + return list1; } // TODO: Generalize this to work for both sensor data and messages From ac547d77e9fb10d8aa8808cb92ef2f88dcdd8f3f Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Sun, 5 Apr 2020 22:26:15 -0700 Subject: [PATCH 2/3] Re-implement the interface to make it easier to display the CENs Concretely: - Remove callbacks from the plugin which may or may not work in the long-term - Keep the CENs in plugin memory instead so we ensure that they are not missed - Add a simple `get` method to allow refresh to happen in the foreground since users need to only see the values in the foreground anyway Change both the native and javascript interfaces (yay Kotlin!) Add control buttons to the list view Fix list view formatting Please see screenshots in the associated PR --- .../src/android/ContactTracing.kt | 47 +++++------- www/js/bluetooth/list.js | 72 +++++++++++-------- www/templates/bluetooth/list.html | 12 +++- 3 files changed, 69 insertions(+), 62 deletions(-) diff --git a/resources/plugins/cordova-plugin-contacttracing/src/android/ContactTracing.kt b/resources/plugins/cordova-plugin-contacttracing/src/android/ContactTracing.kt index 57c70397b..f13610c42 100644 --- a/resources/plugins/cordova-plugin-contacttracing/src/android/ContactTracing.kt +++ b/resources/plugins/cordova-plugin-contacttracing/src/android/ContactTracing.kt @@ -10,10 +10,9 @@ import org.json.* class ContactTracing : CordovaPlugin() { - private var scanContext: CallbackContext? = null - private var adContext: CallbackContext? = null private var cenScanner: CENScanner? = null private var cenAdvertiser: CENAdvertiser? = null + private var inMemoryCache: MutableList? = mutableListOf(); @Throws(JSONException::class) override fun execute(action: String, args: JSONArray, context: CallbackContext): Boolean { @@ -43,39 +42,27 @@ class ContactTracing : CordovaPlugin() { try { when ( action ) { "startScanner" -> { - scanContext?.let{ throw Exception( "Scanner is already started" ) } - scanContext = context try { uuid = UUID.fromString( args.getString(0) ) } catch (e: Exception) { } cenScanner!!.startScanning( arrayOf( uuid ), args.getLong(1) ?: 10 ) - result.setKeepCallback( true ) - context.sendPluginResult( result ) + context.success(); } "stopScanner" -> { - scanContext ?: throw Exception( "Scanner is already stopped" ) + try { uuid = UUID.fromString( args.getString(0) ) } catch (e: Exception) { } cenScanner!!.stopScanning() - scanContext!!.sendPluginResult( result ) - scanContext = null - context.success() + context.success(); } "startAdvertiser" -> { - adContext?.let{ throw Exception( "Advertiser is already started" ) } - adContext = context try { uuid = UUID.fromString( args.getString(0) ) } catch (e: Exception) { } cenAdvertiser!!.startAdvertiser( uuid ) - result.setKeepCallback( true ) - context.sendPluginResult( result ) + context.success(); } "stopAdvertiser" -> { - adContext ?: throw Exception( "Advertiser is already stopped" ) + try { uuid = UUID.fromString( args.getString(0) ) } catch (e: Exception) { } cenAdvertiser!!.stopAdvertiser() - adContext!!.sendPluginResult( result ) - adContext = null - context.success() + context.success(); } "updateCEN" -> { - adContext ?: throw Exception( "Advertiser must be started first" ) - cenAdvertiser!!.updateCEN() - context.success() + context.success(JSONArray(inMemoryCache)); } else -> throw Exception( "Invalid Action" ) } @@ -89,23 +76,21 @@ class ContactTracing : CordovaPlugin() { inner class ScanCENHandler : CENHandler { override fun handleCEN(cen: CEN) { - scanContext ?: return val contactEvent = JSONObject() - contactEvent.put( "cen", cen.toUUID().toString() ) - val result = PluginResult(PluginResult.Status.OK, contactEvent) - result.setKeepCallback(true); - scanContext!!.sendPluginResult(result) + contactEvent.put( "number", cen.toUUID().toString() ) + contactEvent.put( "ts", System.currentTimeMillis()/1000) + contactEvent.put( "type", "scan") + inMemoryCache!!.add(contactEvent); } } inner class AdCENHandler : CENHandler { override fun handleCEN(cen: CEN) { - adContext ?: return val contactEvent = JSONObject() - contactEvent.put( "cen", cen.toUUID().toString() ) - val result = PluginResult(PluginResult.Status.OK, contactEvent) - result.setKeepCallback(true); - adContext!!.sendPluginResult(result) + contactEvent.put( "number", cen.toUUID().toString() ) + contactEvent.put( "ts", System.currentTimeMillis()/1000) + contactEvent.put("type", "advertise"); + inMemoryCache!!.add(contactEvent); } } diff --git a/www/js/bluetooth/list.js b/www/js/bluetooth/list.js index 0337e6a0d..e874b002b 100644 --- a/www/js/bluetooth/list.js +++ b/www/js/bluetooth/list.js @@ -12,45 +12,59 @@ angular zoomAnimation: true, touchZoom: false, scrollWheelZoom: false, doubleClickZoom: false, boxZoom: false } } ); - var startScanningContactEvents = _ => { - $scope.data = []; - var startScanPromise = - $window.cordova.plugins.contacttracing.startScanner( null, 10) - .then(ce => logContactEvent( ce, false )) - .catch(e => console.error( 'SCAN', e )); - var startAdvPromise = - $window.cordova.plugins.contacttracing.startAdvertiser( null ) - .then( ce => logContactEvent( ce, true )) - .catch( e => console.error( 'AD', e )); - - return Promise.all([startScanPromise, startAdvPromise]) .then(_ => { - Logger.log("successfully started scanning, launching CEN update"); - $scope.update = $window.setInterval( $window.cordova.plugins.contacttracing.updateCEN, - 60000 ); - }); + $scope.startAdvertiser = _ => { + $window.cordova.plugins.contacttracing.startAdvertiser( null ) + .catch(err => Logger.displayError("Error while starting advertise", err)); } - var stopScanningContactEvents = _ => { - var stopScanPromise = $window.cordova.plugins.contacttracing.stopScanner(); - var stopAdvPromise = $window.cordova.plugins.contacttracing.stopAdvertiser(); - return Promise.all([stopScanPromise, stopAdvPromise]).then(_ => { - Logger.log("successfully stopped scanning"); - console.log("About to clear interval" + $scope.update); - }).catch(err => { - Logger.displayError("stopping scan errored", err); - console.log("About to clear interval" + $scope.update); - }); + $scope.stopAdvertiser = _ => { + $window.cordova.plugins.contacttracing.stopAdvertiser() + .catch(err => Logger.displayError("Error while stopping advertise", err)); } - $scope.refresh = _ => { + $scope.startScan = _ => { + $window.cordova.plugins.contacttracing.startScanner( null, 10 ) + .catch(err => Logger.displayError("Error while starting scan", err)); + } + + $scope.stopScan = _ => { + $window.cordova.plugins.contacttracing.stopScanner() + .catch(err => Logger.displayError("Error while stopping scan", err)); + } + + $scope.pullRefresh = _ => { if ($ionicScrollDelegate.getScrollPosition().top < 20) { - stopScanningContactEvents().then(startScanningContactEvents()); + $scope.refresh(); + return true; } } + $scope.formatTime = (ts_in_secs) => moment(ts_in_secs * 1000).format('LT') + + $scope.refresh = _ => { + console.log("About to refresh CEN list"); + $window.cordova.plugins.contacttracing.updateCEN().then(cenList => { + Logger.log("Retrieved list of size "+cenList.length); + $scope.$apply(_ => { + $scope.data = cenList.map(cen => { + if(cen.type == "advertise") { + cen.ad = true; + } else { + cen.ad = false; + } + return cen; + });; + }); + }).catch(err => Logger.displayError("Error refreshing", err)); + } + var logContactEvent = ( ce, ad ) => $scope.data.push( { time: new Date().toLocaleTimeString(), number: ce.cen.toUpperCase(), ad } ); - // $ionicPlatform.ready().then( startScanningContactEvents() ); + $ionicPlatform.ready().then( $scope.update = $window.setInterval( + $scope.refresh(), 60000 ) ); + + $ionicPlatform.ready().then( $scope.testPeriodic = $window.setInterval( + console.log("Periodic call"), 60000 ) ); }); diff --git a/www/templates/bluetooth/list.html b/www/templates/bluetooth/list.html index 490b8b40d..72479ec62 100644 --- a/www/templates/bluetooth/list.html +++ b/www/templates/bluetooth/list.html @@ -1,6 +1,14 @@ - + + + Scan + + + + + Advertise +
@@ -9,7 +17,7 @@
-
{{ cen.time }}
+
{{ formatTime(cen.ts) }}
From 7c0dcdaa20da8eb15b817a42851e957ca3a41be9 Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Sun, 5 Apr 2020 22:53:39 -0700 Subject: [PATCH 3/3] Bump up version numbers for the new release --- config.cordovabuild.xml | 2 +- package.cordovabuild.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.cordovabuild.xml b/config.cordovabuild.xml index ce0aa856d..9059681f8 100644 --- a/config.cordovabuild.xml +++ b/config.cordovabuild.xml @@ -1,5 +1,5 @@ - + cv-19-track Travel pattern tracker for COVID-19 risk estimation. diff --git a/package.cordovabuild.json b/package.cordovabuild.json index fdbe6abb0..df6d62676 100644 --- a/package.cordovabuild.json +++ b/package.cordovabuild.json @@ -1,6 +1,6 @@ { "name": "edu.berkeley.eecs.covid19", - "version": "0.0.3", + "version": "0.0.4", "displayName": "cv-19-track", "scripts": { "setup-serve": "./bin/download_settings_controls.js",