Skip to content

Commit

Permalink
Merge pull request #221 from shankari/add_ble_plumbing
Browse files Browse the repository at this point in the history
🗃️ Plumb through BLE support
  • Loading branch information
shankari authored Apr 14, 2024
2 parents 20d1469 + 0846678 commit dc1eeb1
Show file tree
Hide file tree
Showing 11 changed files with 284 additions and 1 deletion.
7 changes: 6 additions & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
id="cordova-plugin-em-datacollection"
version="1.8.3">
version="1.8.4">

<name>DataCollection</name>
<description>Background data collection FTW! This is the part that I really
Expand Down Expand Up @@ -80,6 +80,8 @@
<action android:name="local.transition.stopped_moving"></action>
<action android:name="local.transition.stop_tracking"></action>
<action android:name="local.transition.start_tracking"></action>
<action android:name="local.transition.ble_beacon_found"></action>
<action android:name="local.transition.ble_beacon_lost"></action>
<action android:name="local.transition.tracking_error"></action>
</intent-filter>
</receiver>
Expand Down Expand Up @@ -169,6 +171,7 @@
<source-file src="src/android/wrapper/Transition.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/LocationTrackingConfig.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/Battery.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/BluetoothBLE.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/ConsentConfig.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/Timer.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
<source-file src="src/android/wrapper/StatsEvent.java" target-dir="src/edu/berkeley/eecs/emission/cordova/tracker/wrapper"/>
Expand Down Expand Up @@ -247,6 +250,7 @@
<header-file src="src/ios/Wrapper/Transition.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/LocationTrackingConfig.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/Battery.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/BluetoothBLE.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/ConsentConfig.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/Timer.h" target-dir="Wrapper"/>
<header-file src="src/ios/Wrapper/StatsEvent.h" target-dir="Wrapper"/>
Expand All @@ -269,6 +273,7 @@
<source-file src="src/ios/Wrapper/Transition.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/LocationTrackingConfig.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/Battery.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/BluetoothBLE.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/ConsentConfig.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/Timer.m" target-dir="Wrapper"/>
<source-file src="src/ios/Wrapper/StatsEvent.m" target-dir="Wrapper"/>
Expand Down
2 changes: 2 additions & 0 deletions res/android/statemachine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<string name="transition_stopped_moving">local.transition.stopped_moving</string>
<string name="transition_stop_tracking">local.transition.stop_tracking</string>
<string name="transition_start_tracking">local.transition.start_tracking</string>
<string name="transition_ble_beacon_found">local.transition.ble_beacon_found</string>
<string name="transition_ble_beacon_lost">local.transition.ble_beacon_lost</string>
<string name="transition_tracking_error">local.transition.tracking_error</string>
<!-- <string name="transition_actions_started">local.transition.actions_started</string>
<string name="transition_actions_complete">local.transition.actions_complete</string> -->
Expand Down
32 changes: 32 additions & 0 deletions src/android/DataCollectionPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
import edu.berkeley.eecs.emission.cordova.tracker.wrapper.ConsentConfig;
import edu.berkeley.eecs.emission.cordova.tracker.wrapper.LocationTrackingConfig;
import edu.berkeley.eecs.emission.cordova.tracker.wrapper.StatsEvent;
import edu.berkeley.eecs.emission.cordova.tracker.wrapper.BluetoothBLE;
import edu.berkeley.eecs.emission.cordova.tracker.verification.SensorControlForegroundDelegate;
import edu.berkeley.eecs.emission.cordova.unifiedlogger.Log;
import edu.berkeley.eecs.emission.cordova.usercache.BuiltinUserCache;
import edu.berkeley.eecs.emission.cordova.usercache.UserCacheFactory;

public class DataCollectionPlugin extends CordovaPlugin {
public static final String TAG = "DataCollectionPlugin";
Expand Down Expand Up @@ -193,6 +195,34 @@ public void run() {
}
});
return true;
} else if (action.equals("mockBLEObjects")) {
// we want to run this in a background thread because it might sometimes wait to get
// the current location
final String eventType = data.getString(0);
final String uuid = data.getString(1);
final int major = data.getInt(2);
final int minor = data.getInt(3);
final int nObjects = data.getInt(4);
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
Context ctxt = cordova.getActivity();
for (int i = 0; i < nObjects; i++) {
BluetoothBLE currWrapper = BluetoothBLE.initFake(eventType, uuid, major, minor);
UserCacheFactory.getUserCache(ctxt).putSensorData(R.string.key_usercache_bluetooth_ble,
currWrapper);
}
BluetoothBLE[] justAddedEntries = UserCacheFactory.getUserCache(ctxt).getLastSensorData(
R.string.key_usercache_bluetooth_ble, nObjects, BluetoothBLE.class);
for(BluetoothBLE currEntry : justAddedEntries) {
if (!currEntry.getEventType().equals(eventType)) {
callbackContext.error(currEntry.getEventType()+ " found in last "+nObjects+" objects, expected all "+eventType);
}
callbackContext.success(eventType);
}
}
});
return true;
} else if (action.equals("handleSilentPush")) {
throw new UnsupportedOperationException("silent push handling not supported for android");
} else if (action.equals("getAccuracyOptions")) {
Expand All @@ -214,6 +244,8 @@ private static Map<String, String> getTransitionMap(Context ctxt) {
retVal.put("STOPPED_MOVING", ctxt.getString(R.string.transition_stopped_moving));
retVal.put("STOP_TRACKING", ctxt.getString(R.string.transition_stop_tracking));
retVal.put("START_TRACKING", ctxt.getString(R.string.transition_start_tracking));
retVal.put("BLE_BEACON_FOUND", ctxt.getString(R.string.transition_ble_beacon_found));
retVal.put("BLE_BEACON_LOST", ctxt.getString(R.string.transition_ble_beacon_lost));
return retVal;
}

Expand Down
2 changes: 2 additions & 0 deletions src/android/location/TripDiaryStateMachineReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public void onReceive(Context context, Intent intent) {
context.getString(R.string.transition_stopped_moving),
context.getString(R.string.transition_stop_tracking),
context.getString(R.string.transition_start_tracking),
context.getString(R.string.transition_ble_beacon_found),
context.getString(R.string.transition_ble_beacon_lost),
context.getString(R.string.transition_tracking_error)
}));

Expand Down
97 changes: 97 additions & 0 deletions src/android/wrapper/BluetoothBLE.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package edu.berkeley.eecs.emission.cordova.tracker.wrapper;

/**
* Created by shankari on 3/30/24.
*/
public class BluetoothBLE {
public String getEventType() {
return eventType;
}

/* Not sure if we need to return the UUID, major and minor
since we will only get callbacks for the registered UUID
and we don't need to check the major or minor in native code
only that it is **our** beacon. Let's hold off on them for now.
**/

/* We do need to use proximity in the FSM to avoid spurious exits (e.g. a
* personal car parked next to a fleet car may still see a region enter,
* but we don't want to track the trip because the proximity is "far".
*/
public String getProximity() {
return proximity;
}

public double getTs() {
return ts;
}

// Similarly, we store the accuracy and the rssi for the record, but the
// underlying API already converts it to a proximity value, so we use that
// instead

private String eventType;
private String uuid;
private int major;
private int minor;
private String proximity;
private double accuracy;
private int rssi;

private double ts;
// Should we put newState in here as well?
// If so, we will need to change the location of the save

private BluetoothBLE() {}

public static BluetoothBLE initRegionEnter(String uuid, double ts) {
BluetoothBLE enterEvent = new BluetoothBLE();
enterEvent.eventType = "REGION_ENTER";
enterEvent.uuid = uuid;
enterEvent.ts = ts;
return enterEvent;
}

public static BluetoothBLE initRegionExit(String uuid, double ts) {
BluetoothBLE exitEvent = new BluetoothBLE();
exitEvent.eventType = "REGION_EXIT";
exitEvent.uuid = uuid;
exitEvent.ts = ts;
return exitEvent;
}

public static BluetoothBLE initRangeUpdate(String uuid, double ts,
int major, int minor,
String proximity, double accuracy, int rssi) {
BluetoothBLE rangeEvent = new BluetoothBLE();
rangeEvent.eventType = "RANGE_UPDATE";
rangeEvent.uuid = uuid;
rangeEvent.ts = ts;

rangeEvent.major = major;
rangeEvent.minor = minor;
rangeEvent.proximity = proximity;
rangeEvent.accuracy = accuracy;
rangeEvent.rssi = rssi;
return rangeEvent;
}

public static BluetoothBLE initFake(String eventType, String uuid, int major, int minor) {
BluetoothBLE fakeEvent = new BluetoothBLE();
fakeEvent.uuid = uuid;
fakeEvent.eventType = eventType;
fakeEvent.ts = System.currentTimeMillis() / 1000; // time is in seconds for us

// we assume that we don't have major and minor entries for the
// "monitor" responses
if (eventType == "RANGE_UPDATE") {
fakeEvent.major = major;
fakeEvent.minor = minor;
fakeEvent.proximity = "ProximityNear";
fakeEvent.accuracy = (int)(Math.random() * 100);
fakeEvent.rssi = (int)(Math.random() * 10);
}

return fakeEvent;
}
}
1 change: 1 addition & 0 deletions src/ios/BEMDataCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- (void) setConfig:(CDVInvokedUrlCommand*)command;
- (void) getState:(CDVInvokedUrlCommand*)command;
- (void) forceTransition:(CDVInvokedUrlCommand *)command;
- (void) mockBLEObjects:(CDVInvokedUrlCommand *)command;
- (void) handleSilentPush:(CDVInvokedUrlCommand *)command;
- (void)getAccuracyOptions:(CDVInvokedUrlCommand *)command;

Expand Down
51 changes: 51 additions & 0 deletions src/ios/BEMDataCollection.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "BEMDataCollection.h"
#import "LocalNotificationManager.h"
#import "Wrapper/LocationTrackingConfig.h"
#import "Wrapper/BluetoothBLE.h"
#import "BEMAppDelegate.h"
#import "ConfigManager.h"
#import "DataUtils.h"
Expand Down Expand Up @@ -301,6 +302,54 @@ - (void)forceTransition:(CDVInvokedUrlCommand *)command
messageAsString:msg];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
@catch (NSException *exception) {
NSString* msg = [NSString stringWithFormat: @"While getting settings, error %@", exception];
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_ERROR
messageAsString:msg];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
}

- (void)mockBLEObjects:(CDVInvokedUrlCommand *)command
{
NSString* callbackId = [command callbackId];

@try {
NSString* eventType = [[command arguments] objectAtIndex:0];
NSString* uuid = [[command arguments] objectAtIndex:1];
int major = [[[command arguments] objectAtIndex:2] intValue];
int minor = [[[command arguments] objectAtIndex:3] intValue];
int nObjects = [[[command arguments] objectAtIndex:4] intValue];
for (int i = 0; i < nObjects; i++) {
BluetoothBLE* currWrapper = [[BluetoothBLE new] initFake:@"RANGE_UPDATE" anduuid: uuid andmajor: major andminor: minor];
[[BuiltinUserCache database] putSensorData:@"key.usercache.bluetooth_ble" value:currWrapper];
}
NSArray* justAddedEntries = [[BuiltinUserCache database] getLastSensorData:@"key.usercache.bluetooth_ble"
nEntries:nObjects
wrapperClass:BluetoothBLE.class];
for (int i = 0; i < justAddedEntries.count; i++) {
BluetoothBLE* currEntry = [justAddedEntries objectAtIndex:i];
if (![currEntry.eventType isEqualToString:eventType]) {
NSString* msg = [NSString stringWithFormat: @"%@ found in last %d objects, expected all %@", currEntry.eventType, nObjects, eventType];
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_ERROR
messageAsString:msg];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
}
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_OK
messageAsString:eventType];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
@catch (NSException *exception) {
NSString* msg = [NSString stringWithFormat: @"While getting settings, error %@", exception];
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_ERROR
messageAsString:msg];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
}

- (void)handleSilentPush:(CDVInvokedUrlCommand *)command
Expand Down Expand Up @@ -367,6 +416,8 @@ - (NSDictionary*) getTransitionMap {
retVal[@"RECEIVED_SILENT_PUSH"] = CFCTransitionRecievedSilentPush;
retVal[@"VISIT_STARTED"] = CFCTransitionVisitStarted;
retVal[@"VISIT_ENDED"] = CFCTransitionVisitEnded;
retVal[@"BLE_BEACON_FOUND"] = CFCTransitionBeaconFound;
retVal[@"BLE_BEACON_LOST"] = CFCTransitionBeaconLost;
return retVal;
}

Expand Down
2 changes: 2 additions & 0 deletions src/ios/Location/TripDiaryStateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#define CFCTransitionStartTracking @"T_START_TRACKING"
#define CFCTransitionVisitStarted @"T_VISIT_STARTED"
#define CFCTransitionVisitEnded @"T_VISIT_ENDED"
#define CFCTransitionBeaconFound @"T_BLE_BEACON_FOUND"
#define CFCTransitionBeaconLost @"T_BLE_BEACON_LOST"
#define CFCTransitionNOP @"T_NOP"

/*
Expand Down
28 changes: 28 additions & 0 deletions src/ios/Wrapper/BluetoothBLE.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Transition.h
// CFC_Tracker
//
// Created by Kalyanaraman Shankari on 10/27/15.
// Copyright © 2015 Kalyanaraman Shankari. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

@interface BluetoothBLE : NSObject

- (instancetype)initWithCLBeacon:(CLBeacon *)beacon andEventType:(NSString *) eventType;
- (instancetype)initFake:(NSString *)eventType anduuid:(NSString*) uuid andmajor:(int) major andminor:(int) minor;

// fields from CLBeacon, modified to be easy to serialize and restore
@property NSString* uuid;
@property NSInteger major;
@property NSInteger minor;
@property NSString* proximity;
@property CLLocationAccuracy accuracy;
@property NSInteger rssi;
@property NSString* eventType;
@property double ts;

+ (NSString*) proximityToString:(CLProximity) proximityObj;
@end
54 changes: 54 additions & 0 deletions src/ios/Wrapper/BluetoothBLE.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Transition.m
// CFC_Tracker
//
// Created by Kalyanaraman Shankari on 10/27/15.
// Copyright © 2015 Kalyanaraman Shankari. All rights reserved.
//

#import "BluetoothBLE.h"
#import "DataUtils.h"
#import <stdlib.h>

@implementation BluetoothBLE

-(id) initWithCLBeacon:(CLBeacon*) beacon andEventType:(NSString*) eventType {
self = [super init];
self.uuid = beacon.UUID;
self.major = beacon.major.integerValue;
self.minor = beacon.minor.integerValue;
self.proximity = [BluetoothBLE proximityToString:beacon.proximity];
self.accuracy = beacon.accuracy;
self.rssi = beacon.rssi;

self.eventType = eventType;
self.ts = [DataUtils dateToTs:beacon.timestamp];
return self;
}

-(id) initFake:(NSString*) eventType anduuid:(NSString*) uuid andmajor:(int) major andminor:(int)minor {
self = [super init];
self.uuid = uuid;
self.eventType = eventType;
self.ts = [DataUtils dateToTs:[NSDate now]];

if ([eventType isEqualToString:@"RANGE_UPDATE"]) {
self.major = major;
self.minor = minor;
self.proximity = [BluetoothBLE proximityToString:CLProximityNear];
self.accuracy = arc4random_uniform(100);
self.rssi = arc4random_uniform(10);
}

return self;
}

+ (NSString*) proximityToString:(CLProximity) proximityObj {
if (proximityObj == CLProximityImmediate) { return @"ProximityImmediate"; };
if (proximityObj == CLProximityNear) { return @"ProximityNear"; };
if (proximityObj == CLProximityFar) { return @"ProximityFar"; };
return @"ProximityUnknown";
}


@end
Loading

0 comments on commit dc1eeb1

Please sign in to comment.