Cleanup: SensorDataAggregator inlined into SensorManager.

Preparation for refactoring.
This commit is contained in:
Dennis Guse
2026-01-26 20:13:11 +01:00
parent 744853ee91
commit 1a14fed287
5 changed files with 250 additions and 262 deletions
@@ -67,6 +67,7 @@ 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.BluetoothHandlerCyclingPower; import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower;
import de.dennisguse.opentracks.sensors.SensorManager;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
@@ -75,7 +76,6 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataAggregator;
import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
@@ -197,7 +197,7 @@ public class ExportImportTest {
)); ));
trackPointCreator.setClock("2020-02-02T02:02:18Z"); trackPointCreator.setClock("2020-02-02T02:02:18Z");
trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); trackPointCreator.getSensorManager().clear();
service.endCurrentTrack(); service.endCurrentTrack();
trackPointCreator.setClock("2020-02-02T02:03:20Z"); trackPointCreator.setClock("2020-02-02T02:03:20Z");
@@ -212,7 +212,7 @@ public class ExportImportTest {
sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3.1234567, 16.001, 10, 27, 15, 999.123, 0f); sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3.1234567, 16.001, 10, 27, 15, 999.123, 0f);
trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); trackPointCreator.getSensorManager().clear();
trackPointCreator.setClock("2020-02-02T02:04:00Z"); trackPointCreator.setClock("2020-02-02T02:04:00Z");
service.endCurrentTrack(); service.endCurrentTrack();
@@ -661,16 +661,16 @@ public class ExportImportTest {
} }
private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain, float temperature) { private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain, float temperature) {
SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; SensorManager sensorManager = trackPointCreator.getSensorManager();
AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", "");
cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null))); cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null)));
sensorDataAggregator.add(cyclingPower); sensorManager.add(cyclingPower);
AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", "");
avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate))); avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate)));
sensorDataAggregator.add(avgHeartRate); sensorManager.add(avgHeartRate);
AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") { AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") {
@NonNull @NonNull
@@ -684,7 +684,7 @@ public class ExportImportTest {
return true; return true;
} }
}; };
sensorDataAggregator.add(cyclingCadence); sensorManager.add(cyclingCadence);
if (distance != null && speed != null) { if (distance != null && speed != null) {
AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") { AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") {
@@ -699,14 +699,14 @@ public class ExportImportTest {
return true; return true;
} }
}; };
sensorDataAggregator.add(aggregatorCyclingDistanceSpeed); sensorManager.add(aggregatorCyclingDistanceSpeed);
} else { } else {
sensorDataAggregator.add(new AggregatorCyclingDistanceSpeed("", "")); sensorManager.add(new AggregatorCyclingDistanceSpeed("", ""));
} }
mockAltitudeChange(trackPointCreator, altitudeGain); mockAltitudeChange(trackPointCreator, altitudeGain);
sensorDataAggregator.add(new AggregatorTemperature("", "'") { sensorManager.add(new AggregatorTemperature("", "'") {
@NonNull @NonNull
@Override @Override
public Temperature getAggregatedValue(Instant now) { public Temperature getAggregatedValue(Instant now) {
@@ -723,10 +723,11 @@ public class ExportImportTest {
} }
private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) {
SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; SensorManager sensorManager = trackPointCreator.getSensorManager();
sensorManager.reset();
if (altitudeGain == null) { if (altitudeGain == null) {
sensorDataAggregator.add(new AggregatorBarometer("test", null)); sensorManager.add(new AggregatorBarometer("test", null));
return; return;
} }
@@ -742,7 +743,7 @@ public class ExportImportTest {
return true; return true;
} }
}; };
sensorDataAggregator.add(aggregatorBarometer); sensorManager.add(aggregatorBarometer);
} }
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) {
@@ -339,7 +339,7 @@ public class TrackRecordingServiceRecordingTest {
mockAltitudeChange(trackPointCreator, 0); mockAltitudeChange(trackPointCreator, 0);
SensorManager sensorManager = trackPointCreator.getSensorManager(); SensorManager sensorManager = trackPointCreator.getSensorManager();
sensorManager.sensorDataAggregator.add(new AggregatorHeartRate("", "")); sensorManager.add(new AggregatorHeartRate("", ""));
// when // when
String sensor1 = "2020-02-02T02:02:03Z"; String sensor1 = "2020-02-02T02:02:03Z";
trackPointCreator.setClock(sensor1); trackPointCreator.setClock(sensor1);
@@ -809,8 +809,8 @@ public class TrackRecordingServiceRecordingTest {
Track.Id trackId = service.startNewTrack(); Track.Id trackId = service.startNewTrack();
SensorManager sensorManager = trackPointCreator.getSensorManager(); SensorManager sensorManager = trackPointCreator.getSensorManager();
sensorManager.sensorDataAggregator.add(new AggregatorRunning("", "")); sensorManager.add(new AggregatorRunning("", ""));
sensorManager.sensorDataAggregator.barometer = null; sensorManager.barometer = null;
// when // when
String sensor1 = "2020-02-02T02:02:03Z"; String sensor1 = "2020-02-02T02:02:03Z";
@@ -962,7 +962,7 @@ public class TrackRecordingServiceRecordingTest {
} }
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
trackPointCreator.getSensorManager().sensorDataAggregator.barometer = new AggregatorBarometer("", "") { trackPointCreator.getSensorManager().barometer = new AggregatorBarometer("", "") {
@Override @Override
public boolean hasReceivedData() { public boolean hasReceivedData() {
return true; return true;
@@ -6,26 +6,39 @@ import android.os.Handler;
import android.os.PowerManager; import android.os.PowerManager;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.time.Instant; import java.time.Instant;
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
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.Position;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataAggregator; import de.dennisguse.opentracks.sensors.sensorData.SensorData;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.SystemUtils; import de.dennisguse.opentracks.util.SystemUtils;
public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener {
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 SensorDataAggregator sensorDataAggregator;
private PowerManager.WakeLock wakeLock; private PowerManager.WakeLock wakeLock;
private final TrackPointCreator observer; private final TrackPointCreator observer;
@@ -34,23 +47,23 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
@Override @Override
public void onConnect(Aggregator<?, ?> aggregator) { public void onConnect(Aggregator<?, ?> aggregator) {
sensorDataAggregator.add(aggregator); add(aggregator);
} }
@Override @Override
public void onChange(Raw<?> data) { public void onChange(Raw<?> data) {
sensorDataAggregator.update(data); update(data);
observer.onChange(); observer.onChange();
} }
@Override @Override
public void onDisconnect(Aggregator<?, ?> aggregator) { public void onDisconnect(Aggregator<?, ?> aggregator) {
sensorDataAggregator.add(aggregator); add(aggregator);
} }
@Override @Override
public void onRemove(Aggregator<?, ?> aggregator) { public void onRemove(Aggregator<?, ?> aggregator) {
sensorDataAggregator.remove(aggregator); remove(aggregator);
} }
@Override @Override
@@ -67,7 +80,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
public SensorManager(TrackPointCreator observer) { public SensorManager(TrackPointCreator observer) {
this.observer = observer; this.observer = observer;
this.sensorDataAggregator = new SensorDataAggregator();
} }
public void start(Context context, Handler handler) { public void start(Context context, Handler handler) {
@@ -100,11 +112,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
gpsManager.stop(); gpsManager.stop();
gpsManager = null; gpsManager = null;
sensorDataAggregator.clear(); clear();
}
public SensorDataSet getSensorDataSet(Instant now) {
return sensorDataAggregator.getSensorData(now);
} }
public void reset() { public void reset() {
@@ -112,7 +120,17 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
Log.d(TAG, "No recording running and no reset necessary."); Log.d(TAG, "No recording running and no reset necessary.");
return; return;
} }
sensorDataAggregator.reset();
Log.i(TAG, "Resetting data");
if (heartRate != null) heartRate.resetAggregated();
if (temperature != null) temperature.resetAggregated();
if (cyclingCadence != null) cyclingCadence.resetAggregated();
if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated();
if (cyclingPower != null) cyclingPower.resetAggregated();
if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated();
if (barometer != null) barometer.resetAggregated();
if (gps != null) gps.resetAggregated();
} }
@VisibleForTesting @VisibleForTesting
@@ -155,4 +173,197 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
Instant getNow(); Instant getNow();
} }
//TODO Inline from SensorDataAggregator; Aggregators will be moved into Drivers.
@VisibleForTesting
public AggregatorHeartRate heartRate;
@VisibleForTesting
public AggregatorTemperature temperature;
@VisibleForTesting
public AggregatorCyclingCadence cyclingCadence;
@VisibleForTesting
public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed;
@VisibleForTesting
public AggregatorCyclingPower cyclingPower;
@VisibleForTesting
public AggregatorRunning runningDistanceSpeedCadence;
@VisibleForTesting
public AggregatorBarometer barometer;
public AggregatorGPS gps;
@VisibleForTesting
public SensorData<HeartRate> getHeartRate(Instant now) {
if (heartRate != null) {
SensorData<HeartRate> value = heartRate.getAggregatedValueWithSensorName(now);
if (value.data().isValid()) return value;
}
return null;
}
private SensorData<Cadence> getCadence(Instant now) {
if (cyclingCadence != null) {
return cyclingCadence.getAggregatedValueWithSensorName(now);
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).cadence() != null) {
return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue().cadence(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
private SensorData<Distance> getDistance(Instant now) {
if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData()) {
return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeed.getSensorNameOrAddress());
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) {
return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue(now).distance(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
//TOOD simplify?
private SensorData<Speed> getSpeed(Instant now) {
if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData() && cyclingDistanceSpeed.getAggregatedValue(now).speed() != null) {
return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).speed(), cyclingDistanceSpeed.getSensorNameOrAddress());
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) {
return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue().speed(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
public void add(@NonNull Aggregator<?, ?> data) {
set(data, data);
}
//TODO Refactor generic "fun" here: go explicit.
public void update(@NonNull Raw<?> data) {
Object value = data.value();
if (value instanceof HeartRate) {
this.heartRate.add((Raw<HeartRate>) data);
return;
}
if (value instanceof Temperature) {
this.temperature.add((Raw<Temperature>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingCadence.CrankData) {
this.cyclingCadence.add((Raw<BluetoothHandlerCyclingCadence.CrankData>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) {
this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes.
this.cyclingDistanceSpeed.add((Raw<BluetoothHandlerCyclingDistanceSpeed.WheelData>) data);
return;
}
if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) {
this.runningDistanceSpeedCadence.add((Raw<BluetoothHandlerRunningSpeedAndCadence.Data>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingPower.Data) {
this.cyclingPower.add((Raw<BluetoothHandlerCyclingPower.Data>) data);
return;
}
if (value instanceof AtmosphericPressure) {
this.barometer.add((Raw<AtmosphericPressure>) data);
return;
}
if (value instanceof Position) {
this.gps.add((Raw<Position>) data);
return;
}
throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName());
}
public void remove(@NonNull Aggregator<?, ?> type) {
set(type, null);
}
// TODO inline with stop()?
@VisibleForTesting
public void clear() {
Log.i(TAG, "Removing all aggregators");
this.heartRate = null;
this.temperature = null;
this.cyclingCadence = null;
this.cyclingDistanceSpeed = null;
this.cyclingPower = null;
this.runningDistanceSpeedCadence = null;
this.barometer = null;
this.gps = null;
}
public SensorDataSet getSensorDataSet(Instant now) {
return new SensorDataSet(
gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""),
getSpeed(now),
getDistance(now),
getHeartRate(now),
temperature != null && temperature.hasReceivedData() ? temperature.getAggregatedValueWithSensorName(now) : null,
getCadence(now),
cyclingPower != null && cyclingPower.hasReceivedData() ? cyclingPower.getAggregatedValueWithSensorName(now) : null,
barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null
);
}
//TODO Refactor generic "fun" here: go explicit.
private void set(@NonNull Aggregator<?, ?> type, @Nullable Aggregator<?, ?> sensorData) {
Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData);
if (type instanceof AggregatorHeartRate) {
heartRate = (AggregatorHeartRate) sensorData;
return;
}
if (type instanceof AggregatorTemperature) {
temperature = (AggregatorTemperature) sensorData;
return;
}
if (type instanceof AggregatorCyclingCadence) {
cyclingCadence = (AggregatorCyclingCadence) sensorData;
return;
}
if (type instanceof AggregatorCyclingDistanceSpeed) {
cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData;
return;
}
if (type instanceof AggregatorCyclingPower) {
cyclingPower = (AggregatorCyclingPower) sensorData;
return;
}
if (type instanceof AggregatorRunning) {
runningDistanceSpeedCadence = (AggregatorRunning) sensorData;
return;
}
if (type instanceof AggregatorBarometer) {
barometer = (AggregatorBarometer) sensorData;
return;
}
if (type instanceof AggregatorGPS) {
gps = (AggregatorGPS) sensorData;
return;
}
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
} }
@@ -48,6 +48,11 @@ public abstract class Aggregator<Input, Output> {
@NonNull @NonNull
protected abstract Output getNoneValue(); protected abstract Output getNoneValue();
@Deprecated //TODO Removed; just implemented for refactoring. This code is bypassing core functionality of this class.
public Output getAggregatedValue() {
return aggregatedValue;
}
@NonNull @NonNull
public Output getAggregatedValue(Instant now) { public Output getAggregatedValue(Instant now) {
if (!hasReceivedData()) { if (!hasReceivedData()) {
@@ -1,229 +0,0 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.time.Instant;
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
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.Position;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower;
import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence;
import de.dennisguse.opentracks.settings.PreferencesUtils;
public class SensorDataAggregator {
private static final String TAG = SensorDataAggregator.class.getSimpleName();
@VisibleForTesting
public AggregatorHeartRate heartRate;
@VisibleForTesting
public AggregatorTemperature temperature;
@VisibleForTesting
public AggregatorCyclingCadence cyclingCadence;
@VisibleForTesting
public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed;
@VisibleForTesting
public AggregatorCyclingPower cyclingPower;
@VisibleForTesting
public AggregatorRunning runningDistanceSpeedCadence;
@VisibleForTesting
public AggregatorBarometer barometer;
public AggregatorGPS gps;
@VisibleForTesting
public SensorData<HeartRate> getHeartRate(Instant now) {
if (heartRate != null) {
SensorData<HeartRate> value = heartRate.getAggregatedValueWithSensorName(now);
if (value.data().isValid()) return value;
}
return null;
}
private SensorData<Cadence> getCadence(Instant now) {
if (cyclingCadence != null) {
return cyclingCadence.getAggregatedValueWithSensorName(now);
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).cadence() != null) {
return new SensorData<>(runningDistanceSpeedCadence.aggregatedValue.cadence(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
private SensorData<Distance> getDistance(Instant now) {
if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData()) {
return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeed.getSensorNameOrAddress());
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) {
return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue(now).distance(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
//TOOD simplify?
private SensorData<Speed> getSpeed(Instant now) {
if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData() && cyclingDistanceSpeed.getAggregatedValue(now).speed() != null) {
return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).speed(), cyclingDistanceSpeed.getSensorNameOrAddress());
}
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) {
return new SensorData<>(runningDistanceSpeedCadence.aggregatedValue.speed(), runningDistanceSpeedCadence.getSensorNameOrAddress());
}
return null;
}
public void add(@NonNull Aggregator<?, ?> data) {
set(data, data);
}
//TODO Refactor generic "fun" here: go explicit.
public void update(@NonNull Raw<?> data) {
Object value = data.value();
if (value instanceof HeartRate) {
this.heartRate.add((Raw<HeartRate>) data);
return;
}
if (value instanceof Temperature) {
this.temperature.add((Raw<Temperature>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingCadence.CrankData) {
this.cyclingCadence.add((Raw<BluetoothHandlerCyclingCadence.CrankData>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) {
this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes.
this.cyclingDistanceSpeed.add((Raw<BluetoothHandlerCyclingDistanceSpeed.WheelData>) data);
return;
}
if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) {
this.runningDistanceSpeedCadence.add((Raw<BluetoothHandlerRunningSpeedAndCadence.Data>) data);
return;
}
if (value instanceof BluetoothHandlerCyclingPower.Data) {
this.cyclingPower.add((Raw<BluetoothHandlerCyclingPower.Data>) data);
return;
}
if (value instanceof AtmosphericPressure) {
this.barometer.add((Raw<AtmosphericPressure>) data);
return;
}
if (value instanceof Position) {
this.gps.add((Raw<Position>) data);
return;
}
throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName());
}
public void remove(@NonNull Aggregator<?, ?> type) {
set(type, null);
}
public void clear() {
Log.i(TAG, "Removing all aggregators");
this.heartRate = null;
this.temperature = null;
this.cyclingCadence = null;
this.cyclingDistanceSpeed = null;
this.cyclingPower = null;
this.runningDistanceSpeedCadence = null;
this.barometer = null;
this.gps = null;
}
public SensorDataSet getSensorData(Instant now) {
return new SensorDataSet(
gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""),
getSpeed(now),
getDistance(now),
getHeartRate(now),
temperature != null && temperature.hasReceivedData() ? temperature.getAggregatedValueWithSensorName(now) : null,
getCadence(now),
cyclingPower != null && cyclingPower.hasReceivedData() ? cyclingPower.getAggregatedValueWithSensorName(now) : null,
barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null
);
}
public void reset() {
Log.i(TAG, "Resetting data");
if (heartRate != null) heartRate.resetAggregated();
if (temperature != null) temperature.resetAggregated();
if (cyclingCadence != null) cyclingCadence.resetAggregated();
if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated();
if (cyclingPower != null) cyclingPower.resetAggregated();
if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated();
if (barometer != null) barometer.resetAggregated();
if (gps != null) gps.resetAggregated();
}
//TODO Refactor generic "fun" here: go explicit.
private void set(@NonNull Aggregator<?, ?> type, @Nullable Aggregator<?, ?> sensorData) {
Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData);
if (type instanceof AggregatorHeartRate) {
heartRate = (AggregatorHeartRate) sensorData;
return;
}
if (type instanceof AggregatorTemperature) {
temperature = (AggregatorTemperature) sensorData;
return;
}
if (type instanceof AggregatorCyclingCadence) {
cyclingCadence = (AggregatorCyclingCadence) sensorData;
return;
}
if (type instanceof AggregatorCyclingDistanceSpeed) {
cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData;
return;
}
if (type instanceof AggregatorCyclingPower) {
cyclingPower = (AggregatorCyclingPower) sensorData;
return;
}
if (type instanceof AggregatorRunning) {
runningDistanceSpeedCadence = (AggregatorRunning) sensorData;
return;
}
if (type instanceof AggregatorBarometer) {
barometer = (AggregatorBarometer) sensorData;
return;
}
if (type instanceof AggregatorGPS) {
gps = (AggregatorGPS) sensorData;
return;
}
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
}