SensorManager handles SensorDataSet.

Part of #1424.
This commit is contained in:
Dennis Guse
2023-05-27 10:02:56 +02:00
parent 6c852091ce
commit d046ca1cd8
6 changed files with 98 additions and 96 deletions
@@ -57,7 +57,6 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter; import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.sensors.AltitudeSumManager; import de.dennisguse.opentracks.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
@@ -165,8 +164,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("2020-02-02T02:02:18Z"); trackPointCreator.setClock("2020-02-02T02:02:18Z");
BluetoothRemoteSensorManager mockRemoteSensorManager = Mockito.mock(BluetoothRemoteSensorManager.class); trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet();
trackPointCreator.getSensorManager().setBluetoothSensorManager(mockRemoteSensorManager);
service.endCurrentTrack(); service.endCurrentTrack();
trackPointCreator.setClock("2020-02-02T02:03:20Z"); trackPointCreator.setClock("2020-02-02T02:03:20Z");
@@ -179,7 +177,6 @@ public class ExportImportTest {
sendLocation(trackPointCreator, "2020-02-02T02:03:23Z", 3, 16.001, 10, 27, 15, 10, 0); sendLocation(trackPointCreator, "2020-02-02T02:03:23Z", 3, 16.001, 10, 27, 15, 10, 0);
trackPointCreator.setClock("2020-02-02T02:03:24Z"); trackPointCreator.setClock("2020-02-02T02:03:24Z");
trackPointCreator.getSensorManager().setBluetoothSensorManager(mockRemoteSensorManager);
service.endCurrentTrack(); service.endCurrentTrack();
Track track = contentProviderUtils.getTrack(trackId); Track track = contentProviderUtils.getTrack(trackId);
@@ -495,9 +492,6 @@ public class ExportImportTest {
} }
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power) { private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power) {
BluetoothRemoteSensorManager remoteSensorManager = Mockito.mock(BluetoothRemoteSensorManager.class);
Mockito.when(remoteSensorManager.fill(Mockito.any())).thenAnswer(invocation -> {
TrackPoint trackPoint = invocation.getArgument(0);
SensorDataSet sensorDataSet = new SensorDataSet(); SensorDataSet sensorDataSet = new SensorDataSet();
sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power))); sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power)));
@@ -508,21 +502,20 @@ public class ExportImportTest {
Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence)); Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence));
sensorDataSet.set(cyclingCadence); sensorDataSet.set(cyclingCadence);
if (distance != null && speed != null) { if (distance != null && speed != null) {
SensorDataCyclingDistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCyclingDistanceSpeed.Data.class); SensorDataCyclingDistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCyclingDistanceSpeed.Data.class);
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance); Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed)); Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
SensorDataCyclingDistanceSpeed distanceSpeed = Mockito.mock(SensorDataCyclingDistanceSpeed.class); SensorDataCyclingDistanceSpeed distanceSpeed = Mockito.mock(SensorDataCyclingDistanceSpeed.class);
Mockito.when(distanceSpeed.hasValue()).thenReturn(true); Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData); Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
sensorDataSet.set(distanceSpeed); sensorDataSet.set(distanceSpeed);
} }
sensorDataSet.fillTrackPoint(trackPoint); trackPointCreator.getSensorManager().sensorDataSet = sensorDataSet;
return sensorDataSet; trackPointCreator.onChange(sensorDataSet);
});
trackPointCreator.getSensorManager().setBluetoothSensorManager(remoteSensorManager); //TODO Might require: getSensorManager().sensorDataSet = new SensorDataSet()
trackPointCreator.onChange(new SensorDataSet());
} }
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
@@ -545,6 +538,6 @@ public class ExportImportTest {
mockAltitudeChange(trackPointCreator, altitudeGain); mockAltitudeChange(trackPointCreator, altitudeGain);
trackPointCreator.setClock(time); trackPointCreator.setClock(time);
trackPointCreator.getGpsHandler().onLocationChanged(location); trackPointCreator.onChange(location);
} }
} }
@@ -189,6 +189,7 @@ public abstract class AbstractBluetoothConnectionManager<DataType> {
*/ */
protected abstract SensorData<DataType> parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, @NonNull BluetoothGattCharacteristic characteristic); protected abstract SensorData<DataType> parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, @NonNull BluetoothGattCharacteristic characteristic);
@Deprecated //TODO REMOVE
interface SensorDataObserver { interface SensorDataObserver {
void onChanged(SensorData<?> sensorData); void onChanged(SensorData<?> sensorData);
@@ -24,17 +24,12 @@ import android.os.Handler;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.time.Duration; import java.time.Duration;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.sensors.sensorData.SensorData;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.PermissionRequester; import de.dennisguse.opentracks.util.PermissionRequester;
@@ -61,20 +56,15 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
private final BluetoothAdapter bluetoothAdapter; private final BluetoothAdapter bluetoothAdapter;
private final Context context; private final Context context;
private final Handler handler; private final Handler handler;
private final SensorManager.SensorDataChangedObserver observer;
private boolean started = false; private boolean started = false;
private Distance preferenceWheelCircumference;
private final BluetoothConnectionManagerHeartRate heartRate = new BluetoothConnectionManagerHeartRate(this); private final BluetoothConnectionManagerHeartRate heartRate = new BluetoothConnectionManagerHeartRate(this);
private final BluetoothConnectionManagerCyclingCadence cyclingCadence = new BluetoothConnectionManagerCyclingCadence(this); private final BluetoothConnectionManagerCyclingCadence cyclingCadence = new BluetoothConnectionManagerCyclingCadence(this);
private final BluetoothConnectionManagerCyclingDistanceSpeed cyclingSpeed = new BluetoothConnectionManagerCyclingDistanceSpeed(this); private final BluetoothConnectionManagerCyclingDistanceSpeed cyclingSpeed = new BluetoothConnectionManagerCyclingDistanceSpeed(this);
private final BluetoothConnectionManagerCyclingPower cyclingPower = new BluetoothConnectionManagerCyclingPower(this); private final BluetoothConnectionManagerCyclingPower cyclingPower = new BluetoothConnectionManagerCyclingPower(this);
private final BluetoothConnectionRunningSpeedAndCadence runningSpeedAndCadence = new BluetoothConnectionRunningSpeedAndCadence(this); private final BluetoothConnectionRunningSpeedAndCadence runningSpeedAndCadence = new BluetoothConnectionRunningSpeedAndCadence(this);
private final SensorDataSet sensorDataSet = new SensorDataSet();
private final SensorManager.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) {
@@ -95,9 +85,6 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
connect(cyclingSpeed, address); connect(cyclingSpeed, address);
} }
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key, key)) {
preferenceWheelCircumference = PreferencesUtils.getWheelCircumference();
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) { if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(); String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress();
@@ -114,7 +101,7 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
} }
}; };
public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @NonNull SensorManager.SensorDataSetChangeObserver observer) { public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) {
this.context = context; this.context = context;
this.handler = handler; this.handler = handler;
this.observer = observer; this.observer = observer;
@@ -137,8 +124,6 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
cyclingPower.disconnect(); cyclingPower.disconnect();
runningSpeedAndCadence.disconnect(); runningSpeedAndCadence.disconnect();
sensorDataSet.clear();
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
started = false; started = false;
} }
@@ -178,53 +163,14 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
} }
} }
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
sensorDataSet.fillTrackPoint(trackPoint);
return new SensorDataSet(sensorDataSet);
}
public void reset() {
sensorDataSet.reset();
}
@Override @Override
public synchronized void onChanged(SensorData<?> sensorData) { public synchronized void onChanged(SensorData<?> sensorData) {
if (sensorData instanceof SensorDataCyclingCadence) { observer.onChange(sensorData);
SensorDataCyclingCadence previous = sensorDataSet.getCyclingCadence();
Log.d(TAG, "Previous: " + previous + "; current: " + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cadence data repeated.");
return;
}
((SensorDataCyclingCadence) sensorData).compute(previous);
}
if (sensorData instanceof SensorDataCyclingDistanceSpeed) {
SensorDataCyclingDistanceSpeed previous = sensorDataSet.getCyclingDistanceSpeed();
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cycling speed data repeated.");
return;
}
((SensorDataCyclingDistanceSpeed) sensorData).compute(previous, preferenceWheelCircumference);
}
if (sensorData instanceof SensorDataRunning) {
SensorDataRunning previous = sensorDataSet.getRunningDistanceSpeedCadence();
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: running speed data repeated.");
return;
}
((SensorDataRunning) sensorData).compute(previous);
}
sensorDataSet.set(sensorData);
observer.onChange(new SensorDataSet(sensorDataSet));
} }
@Override @Override
public void onDisconnecting(SensorData<?> sensorData) { public void onDisconnecting(SensorData<?> sensorData) {
sensorDataSet.remove(sensorData); observer.onDisconnect(sensorData);
} }
@NonNull @NonNull
@@ -14,12 +14,34 @@ public class SensorManager {
private static final String TAG = SensorManager.class.getSimpleName(); private static final String TAG = SensorManager.class.getSimpleName();
//TODO Should be final and not be visible for testing
@VisibleForTesting
public SensorDataSet sensorDataSet = new SensorDataSet();
private final SensorManager.SensorDataSetChangeObserver observer;
private final SensorDataChangedObserver listener = new SensorDataChangedObserver() {
@Override
public void onChange(SensorData<?> sensorData) {
sensorDataSet.set(sensorData);
observer.onChange(new SensorDataSet(sensorDataSet));
}
@Override
public void onDisconnect(SensorData<?> sensorData) {
sensorDataSet.remove(sensorData);
observer.onChange(new SensorDataSet(sensorDataSet));
}
};
private BluetoothRemoteSensorManager bluetoothSensorManager; private BluetoothRemoteSensorManager bluetoothSensorManager;
private AltitudeSumManager altitudeSumManager; private AltitudeSumManager altitudeSumManager;
public SensorManager(Context context, Handler handler, SensorDataSetChangeObserver observer) { public SensorManager(Context context, Handler handler, SensorDataSetChangeObserver observer) {
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, observer); this.observer = observer;
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener);
altitudeSumManager = new AltitudeSumManager(); altitudeSumManager = new AltitudeSumManager();
} }
@@ -38,11 +60,14 @@ public class SensorManager {
altitudeSumManager.stop(context); altitudeSumManager.stop(context);
altitudeSumManager = null; altitudeSumManager = null;
} }
sensorDataSet.clear();
} }
public SensorDataSet fill(TrackPoint trackPoint) { public SensorDataSet fill(TrackPoint trackPoint) {
altitudeSumManager.fill(trackPoint); altitudeSumManager.fill(trackPoint);
return bluetoothSensorManager.fill(trackPoint); sensorDataSet.fillTrackPoint(trackPoint);
return new SensorDataSet(sensorDataSet);
} }
public void reset() { public void reset() {
@@ -50,7 +75,7 @@ public class SensorManager {
Log.d(TAG, "No recording running and no reset necessary."); Log.d(TAG, "No recording running and no reset necessary.");
return; return;
} }
bluetoothSensorManager.reset(); sensorDataSet.reset();
altitudeSumManager.reset(); altitudeSumManager.reset();
} }
@@ -60,12 +85,6 @@ public class SensorManager {
return bluetoothSensorManager; return bluetoothSensorManager;
} }
@Deprecated
@VisibleForTesting
public void setBluetoothSensorManager(BluetoothRemoteSensorManager remoteSensorManager) {
this.bluetoothSensorManager = remoteSensorManager;
}
@Deprecated @Deprecated
@VisibleForTesting @VisibleForTesting
public AltitudeSumManager getAltitudeSumManager() { public AltitudeSumManager getAltitudeSumManager() {
@@ -78,6 +97,12 @@ public class SensorManager {
this.altitudeSumManager = altitudeSumManager; this.altitudeSumManager = altitudeSumManager;
} }
public interface SensorDataChangedObserver {
void onChange(SensorData<?> sensorData);
void onDisconnect(SensorData<?> sensorData);
}
@Deprecated @Deprecated
public interface SensorDataSetChangeObserver { public interface SensorDataSetChangeObserver {
void onChange(SensorDataSet sensorDataSet); void onChange(SensorDataSet sensorDataSet);
@@ -1,16 +1,21 @@
package de.dennisguse.opentracks.sensors.sensorData; package de.dennisguse.opentracks.sensors.sensorData;
import android.util.Log;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.PreferencesUtils;
public final class SensorDataSet { public final class SensorDataSet {
private static final String TAG = SensorDataSet.class.getSimpleName();
private SensorDataHeartRate heartRate; private SensorDataHeartRate heartRate;
private SensorDataCyclingCadence cyclingCadence; private SensorDataCyclingCadence cyclingCadence;
@@ -140,28 +145,55 @@ public final class SensorDataSet {
+ (runningDistanceSpeedCadence != null ? " " + runningDistanceSpeedCadence : ""); + (runningDistanceSpeedCadence != null ? " " + runningDistanceSpeedCadence : "");
} }
private void set(@NonNull SensorData<?> type, SensorData<?> data) { private void set(@NonNull SensorData<?> type, SensorData<?> sensorData) {
if (type instanceof SensorDataHeartRate) { if (type instanceof SensorDataHeartRate) {
this.heartRate = (SensorDataHeartRate) data; this.heartRate = (SensorDataHeartRate) sensorData;
return; return;
} }
if (type instanceof SensorDataCyclingCadence) { if (type instanceof SensorDataCyclingCadence) {
this.cyclingCadence = (SensorDataCyclingCadence) data; SensorDataCyclingCadence previous = getCyclingCadence();
Log.d(TAG, "Previous: " + previous + "; current: " + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cadence data repeated.");
return;
}
this.cyclingCadence = (SensorDataCyclingCadence) sensorData;
this.cyclingCadence.compute(previous);
return; return;
} }
if (type instanceof SensorDataCyclingDistanceSpeed) { if (type instanceof SensorDataCyclingDistanceSpeed) {
this.cyclingDistanceSpeed = (SensorDataCyclingDistanceSpeed) data; SensorDataCyclingDistanceSpeed previous = getCyclingDistanceSpeed();
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: cycling speed data repeated.");
return;
}
Distance preferenceWheelCircumference = PreferencesUtils.getWheelCircumference(); //TODO Fetch once and then listen for changes.
this.cyclingDistanceSpeed = (SensorDataCyclingDistanceSpeed) sensorData;
this.cyclingDistanceSpeed.compute(previous, preferenceWheelCircumference);
return; return;
} }
if (type instanceof SensorDataCyclingPower) { if (type instanceof SensorDataCyclingPower) {
this.cyclingPower = (SensorDataCyclingPower) data; this.cyclingPower = (SensorDataCyclingPower) sensorData;
return; return;
} }
if (type instanceof SensorDataRunning) { if (type instanceof SensorDataRunning) {
this.runningDistanceSpeedCadence = (SensorDataRunning) data; SensorDataRunning previous = getRunningDistanceSpeedCadence();
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
if (sensorData.equals(previous)) {
Log.d(TAG, "onChanged: running speed data repeated.");
return;
}
this.runningDistanceSpeedCadence = (SensorDataRunning) sensorData;
this.runningDistanceSpeedCadence.compute(previous);
return; return;
} }
@@ -142,6 +142,11 @@ public class TrackPointCreator implements SensorManager.SensorDataSetChangeObser
return sensorManager; return sensorManager;
} }
@VisibleForTesting
public void setSensorManager(SensorManager sensorManager) {
this.sensorManager = sensorManager;
}
@VisibleForTesting @VisibleForTesting
public void setClock(@NonNull String time) { public void setClock(@NonNull String time) {
this.clock = Clock.fixed(Instant.parse(time), ZoneId.of("CET")); this.clock = Clock.fixed(Instant.parse(time), ZoneId.of("CET"));