Bluetooth sensors: event-driven TrackPoint creation.

Part of #500.
This commit is contained in:
Dennis Guse
2022-01-01 21:15:46 +01:00
parent 1fb8fc6a09
commit c4b8082efc
9 changed files with 40 additions and 27 deletions
@@ -147,7 +147,7 @@ public class ExportImportTest {
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null); service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET"))); trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET")));
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context)); trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator));
service.pauseCurrentTrack(); service.pauseCurrentTrack();
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET"))); trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET")));
@@ -165,7 +165,7 @@ public class ExportImportTest {
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0); sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0);
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:24Z"), ZoneId.of("CET"))); trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:24Z"), ZoneId.of("CET")));
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context)); trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator));
service.endCurrentTrack(); service.endCurrentTrack();
Track track = contentProviderUtils.getTrack(trackId); Track track = contentProviderUtils.getTrack(trackId);
@@ -412,7 +412,7 @@ public class ExportImportTest {
} }
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, Float heartRate, Float cyclingCadence, Float power) { private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, Float heartRate, Float cyclingCadence, Float power) {
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) { trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator) {
@Override @Override
public SensorDataSet fill(@NonNull TrackPoint trackPoint) { public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
SensorDataSet sensorDataSet = new SensorDataSet(); SensorDataSet sensorDataSet = new SensorDataSet();
@@ -280,7 +280,7 @@ public class TrackRecordingServiceTest {
trackPointCreator.stopGPS(); trackPointCreator.stopGPS();
trackPointCreator.setAltitudeSumManager(altitudeSumManager); trackPointCreator.setAltitudeSumManager(altitudeSumManager);
trackPointCreator.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z")), Distance.of(50)); trackPointCreator.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z")));
// then // then
assertTrue(service.isRecording()); assertTrue(service.isRecording());
@@ -404,7 +404,7 @@ public class TrackRecordingServiceTest {
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:03Z")) new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:03Z"))
.setLatitude(10) .setLatitude(10)
.setLongitude(10) .setLongitude(10)
, Distance.of(50)); );
// when // when
Marker.Id markerId = service.insertMarker(null, null, null, null); Marker.Id markerId = service.insertMarker(null, null, null, null);
@@ -452,7 +452,7 @@ public class TrackRecordingServiceTest {
.setSpeed(Speed.of(speed)) .setSpeed(Speed.of(speed))
.setBearing(3.0f); .setBearing(3.0f);
trackRecordingService.getTrackPointCreator().onNewTrackPoint(trackPoint, Distance.of(50)); trackRecordingService.getTrackPointCreator().onNewTrackPoint(trackPoint);
} }
//TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests. //TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests.
@@ -325,7 +325,7 @@ public class TrackRecordingServiceTestLocation {
Track.Id trackId = service.startNewTrack(); Track.Id trackId = service.startNewTrack();
service.stopUpdateRecordingData(); service.stopUpdateRecordingData();
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager); service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context) { service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context, service.getTrackPointCreator()) {
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
@@ -386,7 +386,7 @@ public class TrackRecordingServiceTestLocation {
@MediumTest @MediumTest
@Test @Test
public void testOnLocationChangedAsync_idle_withSensorDistance() { public void testOnLocationChangedAsync_idle_withSensorDistance() {
BluetoothRemoteSensorManager remoteSensorManager = new BluetoothRemoteSensorManager(context) { BluetoothRemoteSensorManager remoteSensorManager = new BluetoothRemoteSensorManager(context, service.getTrackPointCreator()) {
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
@@ -62,7 +62,7 @@ public class GPSHandlerTest {
locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis())); locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis()));
// then // then
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class)); verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class));
} }
/** /**
@@ -78,7 +78,7 @@ public class GPSHandlerTest {
locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis())); locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis()));
// then // then
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class)); verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class));
} }
/** /**
@@ -94,7 +94,7 @@ public class GPSHandlerTest {
// then // then
// no newTrackPoint called // no newTrackPoint called
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class)); verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class));
} }
@Test @Test
@@ -107,7 +107,7 @@ public class GPSHandlerTest {
locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
// then // then
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class)); verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class));
} }
/** /**
@@ -48,7 +48,7 @@ public class TrackPointCreatorTest {
Distance horizontalAccuracyThreshold = Distance.of(50); Distance horizontalAccuracyThreshold = Distance.of(50);
// when // when
subject.onNewTrackPoint(trackPoint, horizontalAccuracyThreshold); subject.onNewTrackPoint(trackPoint);
// then // then
Thread.sleep(10); // Wait for executor service Thread.sleep(10); // Wait for executor service
@@ -88,7 +88,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
@Override @Override
public void run() { public void run() {
updateRecordingDataWhileRecording(); updateRecordingDataWhileRecording();
trackPointCreator.onNewTrackPointWithoutGPS(); //TODO Should not be called every second, right? + with do some duplicate computation with updateRecordingDataWhileRecording().
Handler localHandler = TrackRecordingService.this.handler; Handler localHandler = TrackRecordingService.this.handler;
if (localHandler == null) { if (localHandler == null) {
@@ -121,7 +121,7 @@ public class GPSHandler implements LocationListener, GpsStatus.GpsStatusListener
} }
lastTrackPoint = trackPoint; lastTrackPoint = trackPoint;
trackPointCreator.onNewTrackPoint(trackPoint, thresholdHorizontalAccuracy); trackPointCreator.onNewTrackPoint(trackPoint);
} }
@Override @Override
@@ -20,7 +20,7 @@ import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
/** /**
* Creates TrackPoints while recording by fusing data from different sensors (e.g., GNSS, barometer, BLE sensors). * Creates TrackPoints while recording by fusing data from different sensors (e.g., GNSS, barometer, BLE sensors).
*/ */
public class TrackPointCreator { public class TrackPointCreator implements BluetoothRemoteSensorManager.SensorDataSetChangeObserver {
private static final String TAG = TrackPointCreator.class.getSimpleName(); private static final String TAG = TrackPointCreator.class.getSimpleName();
@@ -51,10 +51,10 @@ public class TrackPointCreator {
gpsHandler.onStart(context); gpsHandler.onStart(context);
remoteSensorManager = new BluetoothRemoteSensorManager(context); remoteSensorManager = new BluetoothRemoteSensorManager(context, this);
remoteSensorManager.start();
altitudeSumManager = new AltitudeSumManager(); altitudeSumManager = new AltitudeSumManager();
remoteSensorManager.start();
altitudeSumManager.start(context); altitudeSumManager.start(context);
} }
@@ -109,19 +109,25 @@ public class TrackPointCreator {
gpsHandler.onSharedPreferenceChanged(key); gpsHandler.onSharedPreferenceChanged(key);
} }
public synchronized void onNewTrackPoint(@NonNull TrackPoint trackPoint, @NonNull Distance thresholdHorizontalAccuracy) { /**
* Got a new TrackPoint from Bluetooth only; contains no GPS location.
*
* @param sensorDataSet
*/
@Override
public void onChange(SensorDataSet sensorDataSet) {
onNewTrackPoint(new TrackPoint(TrackPoint.Type.SENSORPOINT, createNow()));
}
public synchronized void onNewTrackPoint(@NonNull TrackPoint trackPoint) {
fill(trackPoint); fill(trackPoint);
boolean stored = service.newTrackPoint(trackPoint, thresholdHorizontalAccuracy); boolean stored = service.newTrackPoint(trackPoint, gpsHandler.getThresholdHorizontalAccuracy());
if (stored) { if (stored) {
resetSensorData(); resetSensorData();
} }
} }
public void onNewTrackPointWithoutGPS() {
onNewTrackPoint(new TrackPoint(TrackPoint.Type.SENSORPOINT, createNow()), gpsHandler.getThresholdHorizontalAccuracy());
}
public TrackPoint createSegmentStartManual() { public TrackPoint createSegmentStartManual() {
return TrackPoint.createSegmentStartManualWithTime(createNow()); return TrackPoint.createSegmentStartManualWithTime(createNow());
} }
@@ -33,8 +33,8 @@ import de.dennisguse.opentracks.content.sensor.SensorData;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling; import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataRunning; import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
import de.dennisguse.opentracks.content.sensor.SensorDataSet; import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.util.BluetoothUtils;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.BluetoothUtils;
/** /**
* Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors. * Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors.
@@ -71,6 +71,8 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
private final SensorDataSet sensorDataSet = new SensorDataSet(); private final SensorDataSet sensorDataSet = new SensorDataSet();
private final SensorDataSetChangeObserver observer;
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
@@ -110,8 +112,9 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
} }
}; };
public BluetoothRemoteSensorManager(Context context) { public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull SensorDataSetChangeObserver observer) {
this.context = context; this.context = context;
this.observer = observer;
bluetoothAdapter = BluetoothUtils.getAdapter(context); bluetoothAdapter = BluetoothUtils.getAdapter(context);
} }
@@ -208,10 +211,15 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
} }
sensorDataSet.set(sensorData); sensorDataSet.set(sensorData);
observer.onChange(new SensorDataSet(sensorDataSet));
} }
@Override @Override
public void onDisconnecting(SensorData<?> sensorData) { public void onDisconnecting(SensorData<?> sensorData) {
sensorDataSet.remove(sensorData); sensorDataSet.remove(sensorData);
} }
public interface SensorDataSetChangeObserver {
void onChange(SensorDataSet sensorDataSet);
}
} }