Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔵🦷 Initial, proof of concept, alpha version of the bluetooth integration #226

Merged
merged 38 commits into from
Apr 26, 2024

Conversation

shankari
Copy link
Contributor

Includes:

  • basic monitoring and ranging on iOS
  • geofence-triggered ranging on android
  • FSM changes to, in the fleet version, only read location in proximity to BLE
  • prompting for bluetooth permissions
  • wrapper class for bluetooth
  • a javascript function to mock BLE objects and aid in testing

Related usercache change:
e-mission/cordova-usercache#51

Related UI changes:
e-mission/e-mission-phone#1144

louisg1337 and others added 30 commits March 25, 2024 13:08
…ng if it has detected a beacon in the region. Also started setting up adding a new state in the FSM.
- Added `kScanningForBLEState` state
- Added transitions `[CFCTransitionScanBLE, CFCTransitionBLEFound, CFCTransitionBLENotFound]`
- `kScanningForBLEState` is between `kWaitingForTripStartState` and `kOngoingTripState`
…before starting a trip. Only works in the foreground right now.
TODO:
- Run tests to confirm these changes perform correctly
- Add second phase of beacon ranging after intial region
monitoring
And make sure that they can be sent from the UI
…luetoothMonitoringService for future constant monitoring, and added in some permission checks
…permissions so we ask for bluetooth permissions when the app opens for the time being.
- This current iteration should only track when a BLE Beacon is within range
- TODO:
  - Address varios TODO comments within code
  - Case on the Dynamic Config, such that only FLEET deployments use BLE
  - Store BLE sensor data
…etooth code

The data format is very similar to the beacon object in iOS.

We consciously patterned the object to be similar to `CLBeacon` since the
alt-beacon library for android is an effort to be compatible with iOS to the
extent possible.

Our only changes are to change the fields in iOS to be more easily serializable
e-mission/e-mission-docs#1062 (comment)
e-mission/e-mission-docs#1062 (comment)

Testing done:
After adding a hack to read/write messages on every ble_found transition,
e-mission/e-mission-phone#1144 (comment)
was able to verify that both read and write worked properly

Android:

```
sqlite> select * from userCache where type == "sensor-data";
1713026512.887||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026512887E9}
```

```
04-13 09:45:21.365 18332 18332 I TripDiaryStateMachineRcvr: TripDiaryStateMachineReciever onReceive(android.app.ReceiverRestrictedContext@9e3bd75, Intent { act=local.transition.ble_beacon_found flg=0x10 pkg=edu.berkeley.eecs.emission cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineReceiver }) called
04-13 09:45:21.385 18332 18332 I TripDiaryStateMachineService: Service created. Initializing one-time variables!
04-13 09:45:21.396 18332 18332 D TripDiaryStateMachineService: service started with flags = 0 startId = 1 action = local.transition.ble_beacon_found
04-13 09:45:21.404 18332 18332 D TripDiaryStateMachineService: after reading from the prefs, the current state is local.state.waiting_for_trip_start
04-13 09:45:21.424 18332 18332 D BuiltinUserCache: Added value for key statemachine/transition at time 1.713026721405E9
04-13 09:45:21.432 18332 18332 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.ble_beacon_found) called
04-13 09:45:21.448 18332 18332 D BuiltinUserCache: Added value for key background/battery at time 1.713026721433E9
04-13 09:45:21.464 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.713026721449E9
04-13 09:45:21.479 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.713026721465E9
04-13 09:45:21.493 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.71302672148E9
04-13 09:45:21.520 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.713026721493E9
04-13 09:45:21.532 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.71302672152E9
04-13 09:45:21.546 18332 18332 D BuiltinUserCache: Added value for key background/bluetooth_ble at time 1.713026721533E9
04-13 09:45:21.548 18332 18332 I System.out: [BLE native] Found 5 entries
04-13 09:45:21.548 18332 18332 I System.out: [BLE native] First entry is edu.berkeley.eecs.emission.cordova.tracker.wrapper.BluetoothBLE@afc8f12 last entry is edu.berkeley.eecs.emission.cordova.tracker.wrapper.BluetoothBLE@b0c96e3
04-13 09:45:21.548 18332 18332 I System.out: [BLE native] while handling transition local.transition.ble_beacon_found
```

```
sqlite> select * from userCache where type == "sensor-data";
1713026512.887||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026512887E9}
1713026710.433||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026710432E9}
1713026712.809||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026712808E9}
1713026721.433||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026721433E9}
1713026721.449||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"REGION_ENTER","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"0e27c613-ff78-486c-b523-950776777d16"}
1713026721.465||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"RANGE_UPDATE","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"d8635e19-4133-493c-b2fd-c04fdd920c6a"}
1713026721.48||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"RANGE_UPDATE","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"5efe9e8b-ce30-4417-80e3-79ce9ff53ca9"}
1713026721.493||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"RANGE_UPDATE","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"d9283862-2926-4a0c-b377-0e80718e6525"}
1713026721.52||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"RANGE_UPDATE","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"cef2f3df-30c5-49d5-8707-2f234530ef18"}
1713026721.533||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"accuracy":100.0,"eventType":"RANGE_UPDATE","major":4538,"minor":1256,"proximity":"ProximityNear","rssi":10,"ts":1.713026721E9,"uuid":"326876e5-9869-407d-976c-2de438bec330"}
1713026800.123||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026800121E9}
1713026800.788||America/Los_Angeles|sensor-data|background/battery||{"android_health":"GOOD","android_plugged":"UNKNOWN","android_technology":"Li-ion","android_temperature":250,"android_voltage":250,"battery_level_pct":100.0,"battery_status":4,"ts":1.713026800788E9}
```

iOS

```
$ sqlite3 /Users/kshankar/Library/Developer/CoreSimulator/Devices/42B6F8A1-A925-4CAD-A48A-4835D69595ED/data/Containers/Data/Application/13D8F42C-921C-4754-9420-89C4350CE63F/Library/LocalDatabase/userCacheDB
SQLite version 3.39.5 2022-10-14 20:58:05
Enter ".help" for usage hints.
sqlite> select * from userCache where type == "sensor-data";
sqlite>
```

```
2024-04-13 09:34:56.566596-0700 emission[17352:9891606] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-13 09:34:56.566796-0700 emission[17352:9891606] DEBUG: In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-13 09:34:56.568786-0700 emission[17352:9891606] data has 92 bytes, str has size 92
2024-04-13 09:34:56.570995-0700 emission[17352:9891606] data has 69 bytes, str has size 69
2024-04-13 09:35:12.781616-0700 emission[17352:9891606] data has 177 bytes, str has size 177
2024-04-13 09:35:12.784409-0700 emission[17352:9891606] data has 176 bytes, str has size 176
2024-04-13 09:35:12.786659-0700 emission[17352:9891606] data has 177 bytes, str has size 177
2024-04-13 09:35:12.789160-0700 emission[17352:9891606] data has 177 bytes, str has size 177
2024-04-13 09:35:12.791407-0700 emission[17352:9891606] data has 176 bytes, str has size 176
2024-04-13 09:35:12.793945-0700 emission[17352:9891606] data has 177 bytes, str has size 177
2024-04-13 09:35:17.900501-0700 emission[17352:9891606] [BLE native] Found 5 entries
2024-04-13 09:35:17.900666-0700 emission[17352:9891606] [BLE native] First entry is <BluetoothBLE: 0x6000010b8c80>, last entry is <BluetoothBLE: 0x6000010ba3f0>
2024-04-13 09:35:17.900773-0700 emission[17352:9891606] [BLE native] while handling transition T_BLE_BEACON_FOUND
2024-04-13 09:35:20.434450-0700 emission[17352:9891606] Got unexpected transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP, ignoring
```

```
sqlite> select * from userCache where type == "sensor-data";
1713026112.78185||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"REGION_ENTER","ts":1713026111.2200561,"uuid":"35355A74-E587-4F09-B114-D6718E925DC0","proximity":"ProximityNear","accuracy":100}
1713026112.78457||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"RANGE_UPDATE","ts":1713026112.784344,"uuid":"3448C47C-BE3B-40B8-A11F-4BD3CC1C2F63","proximity":"ProximityNear","accuracy":100}
1713026112.78698||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"RANGE_UPDATE","ts":1713026112.7865958,"uuid":"A2778875-CDF8-4AA8-A2E1-0639C9B4B159","proximity":"ProximityNear","accuracy":100}
1713026112.78947||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"RANGE_UPDATE","ts":1713026112.7891002,"uuid":"EE5129DA-6D64-4B25-BA68-3FB3D0FE6BD6","proximity":"ProximityNear","accuracy":100}
1713026112.79173||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"RANGE_UPDATE","ts":1713026112.791352,"uuid":"5B6A86F3-BE4D-498E-A3FD-0CAB6039914E","proximity":"ProximityNear","accuracy":100}
1713026112.7941||America/Los_Angeles|sensor-data|background/bluetooth_ble||{"major":4538,"minor":1256,"rssi":10,"eventType":"RANGE_UPDATE","ts":1713026112.7938981,"uuid":"71E73F8E-4138-4346-8E5F-D05E045A6D69","proximity":"ProximityNear","accuracy":100}
```
…plugin

We created a testing hack to test the previous read/write native changes.
e-mission/e-mission-phone#1144 (comment)

We now move that hack to the plugin interface and make it accessible externally.
That makes it easier to call from the UI for better mocking.
Concretely, we can modify
e-mission/e-mission-phone@7cb3882
to call the interface, which will write sensor data using native code.
This allows us to simulate the actual working of the system (writing native
code) through the UI

Summary of changes:
- Create a new `mockBLEObjects` method in the interface
- Implement it on both android and iOS
- Change the fake object implementaton in the BluetoothBLE wrapper to take more
  arguments to that they can be passed in from the UI

Testing done:
e-mission/e-mission-phone@463c2a5
🗃️ Plumb through BLE support
Conflict was due to the newly added transitions
Per e-mission/e-mission-docs#1062 (comment)
resolved conflict by removing transitions from this PR, and changing
`beacon_found` to `ble_beacon_found`
Consistent with
e-mission/e-mission-docs#1062 (comment)
- removed the newly added transitions
- made them consistent with the plumbed through values
- simplified the tracking logic in `TripDiaryStateMachineService`
- minor refactoring to pull the isFleet check into an instance variable that we
  can reuse without having to read it every time

Testing done:

Non-fleet case

- Start sending location
    - Not seeing any locations
- Manually exit geofence
```
04-13 22:51:45.962 23297 23297 I TripDiaryStateMachineRcvr: TripDiaryStateMachineReciever onReceive(android.app.ReceiverRestrictedContext@a7c085e, Intent { act=local.transition.exited_geofence flg=0x10 pkg=edu.berkeley.eecs.emission cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineReceiver }) called
04-13 22:51:46.118 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.exited_geofence) called
04-13 22:51:46.160 23297 23297 D TripDiaryStateMachineService: Geofence exit in non-fleet mode, starting location tracking
```

- Stop sending locations
- Manually end trip
```
04-13 22:54:41.792 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.ongoing_trip, local.transition.stopped_moving) completed, waiting for async operations to complete
```

Fleet case

- Start sending location
    - Not seeing any locations
```
$ grep LocationChangeIntentService /tmp/logcat.log | tail
04-13 22:54:32.555 23297 32018 D LocationChangeIntentService: FINALLY! Got location update, intent is Intent { cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.LocationChangeIntentService (has extras) }
```

- Manually exit geofence
```
04-13 23:07:58.760 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.exited_geofence) called
04-13 23:07:58.798 23297 23297 D TripDiaryStateMachineService: Geofence exit in fleet mode, checking for beacons before starting location tracking
04-13 23:07:58.807 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.exited_geofence) completed, waiting for async operations to complete

$ grep LocationChangeIntentService /tmp/logcat.log | tail
04-13 22:54:32.555 23297 32018 D LocationChangeIntentService: FINALLY! Got location update, intent is Intent { cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.LocationChangeIntentService (has extras) }
```

- Generate BLE event
```
04-13 23:11:26.244 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.ble_beacon_found) called
04-13 23:11:26.293 23297 23297 D TripDiaryStateMachineService: TripDiaryStateMachineReceiver handleTripStart(local.transition.ble_beacon_found) called
04-13 23:11:26.319 23297 23297 D TripDiaryStateMachineService: Found beacon in fleet mode, starting location tracking
04-13 23:11:26.387 23297 23297 D ActivityRecognitionActions: Starting activity recognition with interval = 30000
04-13 23:11:26.490 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.waiting_for_trip_start, local.transition.ble_beacon_found) completed, waiting for async operations to complete
04-13 23:11:26.568 23297 23297 D TripDiaryStateMachineService: newState after handling action is local.state.ongoing_trip

$ grep LocationChangeIntentService /tmp/logcat.log | tail
04-13 23:20:58.573 23297 14437 D LocationChangeIntentService: FINALLY! Got location update, intent is Intent { cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.LocationChangeIntentService (has extras) }

$ grep LocationChangeIntentService /tmp/logcat.log | tail
04-13 23:22:28.651 23297 15241 D LocationChangeIntentService: FINALLY! Got location update, intent is Intent { cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.LocationChangeIntentService (has extras) }
```

- Stop sending locations

- Manually end trip
```
04-13 23:23:24.649 23297 23297 D TripDiaryStateMachineService: handleAction(local.state.ongoing_trip, local.transition.stopped_moving) called
04-13 23:23:24.921 23297 23297 D TripDiaryStateMachineService: newState after handling action is local.state.waiting_for_trip_start
04-13 23:23:24.958 23297 23297 D TripDiaryStateMachineService: newState saved in prefManager is local.state.waiting_for_trip_start

04-13 23:22:54.173 23297 23297 D LocationChangeIntentService: onDestroy called
04-13 23:22:54.173 23297 23297 D LocationChangeIntentService: onDestroy called
04-13 23:22:54.173 23297 23297 D LocationChangeIntentService: onDestroy called
```
This will allow us to know *which* beacons we were seeing during the trip, and
thus, to match up the car with the trip.

Testing done: compiled

```
BUILD SUCCESSFUL in 7s
52 actionable tasks: 2 executed, 50 up-to-date
```

I am not able to test it since I don't currently have a BLE beacon, but should
be able to push it to staging so that we can test it.

Also bump up the plugin version to reflect the change
…d non-fleet cases

The previous code had the non-fleet versions commented out.
However, when we push this to production, we need to support both fleet and
non-fleet versions. Making sure we keep the original functionality for the
fleet case.

Also, consistent with
e-mission/e-mission-docs#1062 (comment)
and
e-mission/e-mission-docs#1062 (comment)

used the standard transitions from the data model instead

NOTE: that the `isFleet` is currently hardcoded, we need to read it properly
from the dynamic config

Testing done:

2024-04-14 14:47:18.722084-0700 emission[53427:11554764] In TripDiaryStateMachine, received transition T_EXITED_GEOFENCE in state STATE_WAITING_FOR_TRIP_START
2024-04-14 14:47:18.728881-0700 emission[53427:11554764] Got transition T_EXITED_GEOFENCE in state STATE_WAITING_FOR_TRIP_START with fleet mode, checking for beacons before starting location tracking

2024-04-14 14:50:45.818623-0700 emission[53427:11554764] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_WAITING_FOR_TRIP_START
2024-04-14 14:50:45.823268-0700 emission[53427:11554764] Got transition T_BLE_BEACON_FOUND in state STATE_WAITING_FOR_TRIP_START with fleet mode, starting location tracking

2024-04-14 14:51:53.498788-0700 emission[53427:11554764] DEBUG: In TripDiaryStateMachine, received transition T_BLE_BEACON_LOST in state STATE_ONGOING_TRIP

START 2024-04-14 14:51:53.685614 POST /usercache/put
START 2024-04-14 14:51:53.723916 POST /usercache/get
END 2024-04-14 14:51:53.779754 POST /usercache/get 4c152d72-a66d-4472-93f4-62b07c9e110f 0.055525779724121094
END 2024-04-14 14:51:54.061900 POST /usercache/put 4c152d72-a66d-4472-93f4-62b07c9e110f 0.3760108947753906

```
2024-04-14 14:57:32.309087-0700 emission[53427:11554764] DEBUG: In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_WAITING_FOR_TRIP_START
2024-04-14 14:57:32.313790-0700 emission[53427:11554764] Got transition T_BLE_BEACON_FOUND in state STATE_WAITING_FOR_TRIP_START with fleet mode, starting location tracking
2024-04-14 14:57:32.314013-0700 emission[53427:11554764] started fine location tracking with accuracy = -1 and distanceFilter = 1

2024-04-14 14:57:32.316945-0700 emission[53427:11554764] In TripDiaryStateMachine, received transition T_TRIP_STARTED in state STATE_WAITING_FOR_TRIP_START
2024-04-14 14:57:32.323449-0700 emission[53427:11554764] DEBUG: Moved from STATE_WAITING_FOR_TRIP_START to STATE_ONGOING_TRIP
```

```
2024-04-14 15:21:38.026872-0700 emission[53427:11554764] Got transition T_BLE_BEACON_FOUND in state STATE_WAITING_FOR_TRIP_START with fleet mode, starting location tracking

2024-04-14 15:28:31.763608-0700 emission[53427:11554764] Got transition T_TRIP_END_DETECTED in state STATE_ONGOING_TRIP with fleet mode, still seeing beacon but no location updates, ignoring

2024-04-14 15:29:27.951348-0700 emission[53427:11554764] DEBUG: In TripDiaryStateMachine, received transition T_BLE_BEACON_LOST in state STATE_ONGOING_TRIP
2024-04-14 15:29:27.977814-0700 emission[53427:11554764] In TripDiaryStateMachine, received transition T_END_TRIP_TRACKING in state STATE_ONGOING_TRIP

2024-04-14 15:29:27.986602-0700 emission[53427:11554764] In TripDiaryStateMachine, received transition T_TRIP_ENDED in state STATE_ONGOING_TRIP
2024-04-14 15:29:28.033050-0700 emission[53427:11554764] DEBUG: Moved from STATE_ONGOING_TRIP to STATE_WAITING_FOR_TRIP_START
```

```
2024-04-14 15:40:45.930239-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_EXITED_GEOFENCE in state STATE_WAITING_FOR_TRIP_START
2024-04-14 15:40:45.938188-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_STARTED in state STATE_WAITING_FOR_TRIP_START
2024-04-14 15:40:45.968094-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_STARTED in state STATE_ONGOING_TRIP
2024-04-14 15:40:45.978604-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_RESTARTED in state STATE_ONGOING_TRIP
2024-04-14 15:40:45.987830-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_RESTARTED in state STATE_ONGOING_TRIP
2024-04-14 15:41:12.876066-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-14 15:41:22.486777-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-14 15:41:24.861993-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-14 15:41:27.220213-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_FOUND in state STATE_ONGOING_TRIP
2024-04-14 15:41:31.110132-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_LOST in state STATE_ONGOING_TRIP
2024-04-14 15:41:37.788507-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_LOST in state STATE_ONGOING_TRIP
2024-04-14 15:41:37.796704-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_BLE_BEACON_LOST in state STATE_ONGOING_TRIP
2024-04-14 15:41:53.319772-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_END_DETECTED in state STATE_ONGOING_TRIP
2024-04-14 15:41:53.871614-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition (null) in state STATE_ONGOING_TRIP
2024-04-14 15:41:55.577755-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_END_TRIP_TRACKING in state STATE_ONGOING_TRIP
2024-04-14 15:41:55.583780-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_TRIP_ENDED in state STATE_ONGOING_TRIP
2024-04-14 15:41:56.022684-0700 emission[65361:11644200] In TripDiaryStateMachine, received transition T_DATA_PUSHED in state STATE_WAITING_FOR_TRIP_START
```
In a46fad8
we hardcoded the fleet / non-fleet flag to make it easier to test
This commit reads the flag correctly from the dynamic config.

Before making this change, I was concerned that we may be calling the `init`
function before the user has put in their opcode and we have donwloaded the
dynamic config.

however, it looks, through testing, that fortunately, we have done the right thing.
we wait to initialize the FSM until the user has entered the opcode

Testing done:
#220 (comment)

- Uninstalled and reinstalled
- TripDiaryStateMachine was not initialized
- Put in opcode
- TripDiaryStateMachine was initialized with this stacktrace

```

```

On restart (after install), the backtrace is

```
```
Consistent with
e-mission/e-mission-docs#1062 (comment)
store the BLE scan results so that we can use them while matching the mapping

While storing the changes, I realized that the region enter and exit calls
returned a CLBeaconRegion object and the range scans returned a CLRegion
object.
#220 (comment)

This needed us to change the wrapper class as well:
- Add a new initFromCLBeaconRegion that only copies non-range values and sets
  default values for the range values (proximity, accuracy and rssi)
- Change the existing initFromCLBeacon to not need an event type, since it is
  only called for the scans, and the event type is always `RANGE_UPDATE` in
  that case.

Testing done:
- Compiled
- Launched the app
- Note that we cannot test this code without a physical beacon, but it is very
  straightforward and compiles. The only reason why it may fail is if values
  are not filled out in unexpected ways.
For the fleet version of OpenPATH, we need to install the app on work phones.
While this works for most users, users who BYOD might have a separate work
profile on their personal phone. The work profile may have different settings
than the personal profile.

We had a report from a GSA user that their "Pause app activity if unused"
setting was grayed out, so they could not enable it and could not proceed in the app.
Our speculation is that this is because the app has a system exemption from
hibernation, which generates an error while querying, which causes us to return false.
https://developer.android.com/topic/performance/app-hibernation#system-exemption

I am still not sure why it doesn't return `FEATURE_NOT_AVAILABLE` or `DISABLED`
instead of `ERROR`. Both of those and in particular `DISABLED` appear to be
more meaningful and would return `true` in our case.

```
        case UnusedAppRestrictionsConstants.FEATURE_NOT_AVAILABLE: return true;
        case UnusedAppRestrictionsConstants.DISABLED: return true;
```

> Any available Unused App Restrictions on the device are disabled for this
> app. In other words, this app is exempt from having its permissions
> automatically removed or being hibernated.

- Due to lack of time, we are not able to test this; just flipping this to see if it works.
- Ignoring all errors is bad, and we should clean this up to check for work
  profiles properly if this is indeed the issue. We may also have a file an
  issue against google to fix their implementation.
💩 Hack to enable installing the app in a work profile
Should compare strings with equals instead of ==
…on android

As far as we can tell, iOS does not need any additional permissions to use the
iBeacon API since we already have "always" location permissions.
However, android requires the BLUETOOTH_SCAN permission
https://developer.android.com/develop/connectivity/bluetooth/bt-permissions#declare-android12-or-higher

This change includes:
- removing the hack popup that shows up when the app is launched
- adding check and checkAndFix methods in the javascript -> plugin -> foreground checker
- adding a new check method to the list of checks
- invoking the method from the background checker so that we can prompt people
  to provide it if they don't already do so
- ensure that the background checker method is only run for fleet configs

Testing done:
- See screenshots in the related UI PR
- Without the fleet check, simulated trip start/end on a non-fleet config and
  got a notification saying that permissions were incorrect
- With the fleet check, retried, and did not get the notification
The current implementation on android starts ranging for beacons after a
geofence exit and gives up after 4 retries. This is known to work when the
beacon is available at the start of the trip - e.g. walking to work with a
beacon tracks, walking to work without a beacon does not.

But this may not work when the beacon is not at the start location. For
example, if the geofence triggers as soon as a user leaves their work building,
and then they have to walk several minutes to get to their car, the ranging
will timeout and the trip will be missed. This is a bit less likely because our
geofence radius is set to ~ half a block, but we still don't want to miss
trips.

We should really handle this with monitoring versus ranging, but for now, we
will at least bump up the duration for which the ranging happens.

The range callback is roughly once a minute
https://github.com/AltBeacon/android-beacon-library/blob/7af8419c404329ac7dc6001917b5962d2cd53a11/lib/src/main/java/org/altbeacon/beacon/RangeNotifier.java#L39

```
    /**
     * Called once per second to give an estimate of the mDistance to visible beacons
     * @param beacons a collection of <code>Beacon<code> objects that have been seen in the past second
     * @param region the <code>Region</code> object that defines the criteria for the ranged beacons
     */
    public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region);
```

So let's scan 5 * 60 times (roughly 5 minutes) before giving up

This is the last change for e-mission/e-mission-docs#1062
before we move to staging
shankari and others added 5 commits April 15, 2024 00:42
👷🔧 🪠 Plumb through support for requesting bluetooth scan permissions …
🔧 ⌛ Continue scanning for 5 minutes after the geofence exit
Slightly refactored process for how we range beacons
@shankari
Copy link
Contributor Author

This works, and has been deployed in the alpha version. It passes all the CI checks. However, when trying to use it with in a package that is not emission, we run into an issue where the R package is not handled properly in the hook.

$ npx cordova plugin rm cordova-plugin-em-datacollection
Uninstalling cordova-plugin-em-datacollection from android
Subproject Path: CordovaLib
Subproject Path: app
Uninstalling cordova-plugin-em-datacollection from ios
Running command: pod install --verbose
Removing "cordova-plugin-em-datacollection"
...
...platforms/android/app/src/main/java/edu/berkeley/eecs/emission/cordova/tracker/bluetooth/BluetoothMonitoringService.java:15: error: cannot find symbol
import edu.berkeley.eecs.emission.R;
                                 ^
  symbol:   class R
  location: package edu.berkeley.eecs.emission
...platforms/android/app/src/main/java/edu/berkeley/eecs/emission/cordova/tracker/location/TripDiaryStateMachineForegroundService.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error

Note that this is the only java file which is affected. We need to see why this is not handled the same way as the others.

@shankari
Copy link
Contributor Author

This is because we don't check for the import statement, we check for the usage of the package.

const R_RE = /[^\.\w]R\./;
> "import edu.berkeley.eecs.emission.R;".match(R_RE);
null
> "import edu.berkeley.eecs.emission.R;".match(/emission/);
[
  'emission',
  index: 25,
  input: 'import edu.berkeley.eecs.emission.R;',
  groups: undefined
]
> " R.string.transition_ble_beacon".match(R_RE);
[
  ' R.',
  index: 0,
  input: ' R.string.transition_ble_beacon',
  groups: undefined
]

So the problem is that we are not using the variable anywhere. Let's add a simple statement to use it...

@shankari
Copy link
Contributor Author

After adding code to save the entries

...
                    UserCacheFactory.getUserCache(BluetoothMonitoringService.this)
                        .putSensorData(R.string.key_usercache_bluetooth_ble, currWrapper);
...

we get

For file .../plugins/cordova-plugin-em-datacollection/src/android/bluetooth/BluetoothMonitoringService.java Results of match checks: R = (R. BUILDCONFIG = null MAINACT = null
file BluetoothMonitoringService.java needs to be rewritten, checking package

Additional logs:
- to indicate the result of the matching (commented out to avoid spew)
- to indicate that there was not match instead of silently ignoring
This supports:
- Saving the region enter as a REGION_ENTER message
- Ensuring that we use the `R` class so that the imports
are handled correctly
#226 (comment)
#226 (comment)
#226 (comment)

I could have also handled that by removing the import (since the class is not
used) but chose to go forward instead of back
Fix monitoring service import and hook
@shankari shankari merged commit 9263a07 into master Apr 26, 2024
shankari added a commit to shankari/e-mission-phone that referenced this pull request Apr 26, 2024
e-mission/e-mission-data-collection#226
is now merged and a new release
https://github.com/e-mission/e-mission-data-collection/releases/tag/v1.8.5
has been created

So we can now use the version number instead of a branch while adding the
plugin

With this commit, the initial implementation in
e-mission#1144
is done, and we can merge it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants