SensorHandler now interacts with Aggregator.

This commit is contained in:
Dennis Guse
2026-01-31 19:45:32 +01:00
parent b79acfb942
commit a1a363698f
10 changed files with 75 additions and 55 deletions
@@ -3,19 +3,19 @@ package de.dennisguse.opentracks.sensors;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.data.models.AtmosphericPressure;
import de.dennisguse.opentracks.sensors.driver.BarometerBluetooth; import de.dennisguse.opentracks.sensors.driver.BarometerBluetooth;
import de.dennisguse.opentracks.sensors.driver.BarometerInternal; import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.BluetoothDriver;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
/** /**
* Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer). * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer).
*/ */
//TODO Rename class //TODO Rename class
public class AltitudeChangeHandler extends SensorHandler<AtmosphericPressure> { public class AltitudeChangeHandler extends SensorHandler<AtmosphericPressure, AltitudeGainLoss> {
public AltitudeChangeHandler(SensorManager sensorManager) { public AltitudeChangeHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -44,7 +44,7 @@ public class AltitudeChangeHandler extends SensorHandler<AtmosphericPressure> {
@NonNull @NonNull
@Override @Override
public Aggregator<AtmosphericPressure, ?> createAggregator() { public AggregatorBarometer createAggregator() {
return new AggregatorBarometer("", null); return new AggregatorBarometer("", null);
} }
} }
@@ -3,13 +3,13 @@ package de.dennisguse.opentracks.sensors;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.BluetoothDriver;
import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth; import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
public class CyclingCadenceHandler extends SensorHandler<CyclingCadenceBluetooth.CrankData> { public class CyclingCadenceHandler extends SensorHandler<CyclingCadenceBluetooth.CrankData, Cadence> {
protected CyclingCadenceHandler(SensorManager sensorManager) { protected CyclingCadenceHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -27,7 +27,7 @@ public class CyclingCadenceHandler extends SensorHandler<CyclingCadenceBluetooth
@NonNull @NonNull
@Override @Override
protected Aggregator<CyclingCadenceBluetooth.CrankData, ?> createAggregator() { protected AggregatorCyclingCadence createAggregator() {
return new AggregatorCyclingCadence("", null); return new AggregatorCyclingCadence("", null);
} }
@@ -8,7 +8,7 @@ import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
public class CyclingDistanceSpeedHandler extends SensorHandler<CyclingDistanceSpeedBluetooth.WheelData> { public class CyclingDistanceSpeedHandler extends SensorHandler<CyclingDistanceSpeedBluetooth.WheelData, AggregatorCyclingDistanceSpeed.Data> {
protected CyclingDistanceSpeedHandler(SensorManager sensorManager) { protected CyclingDistanceSpeedHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -3,12 +3,13 @@ package de.dennisguse.opentracks.sensors;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.BluetoothDriver;
import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth; import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
public class CyclingPowerHandler extends SensorHandler<CyclingPowerBluetooth.Data> { public class CyclingPowerHandler extends SensorHandler<CyclingPowerBluetooth.Data, Power> {
protected CyclingPowerHandler(SensorManager sensorManager) { protected CyclingPowerHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -7,10 +7,9 @@ import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.BluetoothDriver;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.driver.HeartRateBluetooth; import de.dennisguse.opentracks.sensors.driver.HeartRateBluetooth;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
public class HeartRateHandler extends SensorHandler<HeartRate> { public class HeartRateHandler extends SensorHandler<HeartRate, HeartRate> {
protected HeartRateHandler(SensorManager sensorManager) { protected HeartRateHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -28,7 +27,7 @@ public class HeartRateHandler extends SensorHandler<HeartRate> {
@NonNull @NonNull
@Override @Override
protected Aggregator<HeartRate, ?> createAggregator() { protected AggregatorHeartRate createAggregator() {
return new AggregatorHeartRate("", null); return new AggregatorHeartRate("", null);
} }
@@ -8,7 +8,7 @@ import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth; import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning;
public class RunningSpeedCadenceDistanceHandler extends SensorHandler<RunningSpeedAndCadenceBluetooth.Data> { public class RunningSpeedCadenceDistanceHandler extends SensorHandler<RunningSpeedAndCadenceBluetooth.Data, AggregatorRunning.Data> {
protected RunningSpeedCadenceDistanceHandler(SensorManager sensorManager) { protected RunningSpeedCadenceDistanceHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -3,23 +3,27 @@ package de.dennisguse.opentracks.sensors;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.time.Instant;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.driver.DriverObserver; import de.dennisguse.opentracks.sensors.driver.DriverObserver;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
public abstract class SensorHandler<T> { public abstract class SensorHandler<AggregatorInput, AggregatorOutput> {
private final SensorManager sensorManager; private final SensorManager sensorManager;
private Driver driver; private Driver driver;
private Aggregator<T, ?> aggregator; private Aggregator<AggregatorInput, AggregatorOutput> aggregator;
protected final DriverObserver<T> driverObserver = new DriverObserver<>() { protected final DriverObserver<AggregatorInput> driverObserver = new DriverObserver<>() {
@Override @Override
public void onConnect() { public void onConnect() {
SensorHandler.this.aggregator = createAggregator(); SensorHandler.this.aggregator = createAggregator();
@@ -31,7 +35,7 @@ public abstract class SensorHandler<T> {
} }
@Override @Override
public void onData(T value) { public void onData(AggregatorInput value) {
SensorHandler.this.aggregator.add(sensorManager.getNow(), value); SensorHandler.this.aggregator.add(sensorManager.getNow(), value);
sensorManager.onChange(); sensorManager.onChange();
} }
@@ -85,7 +89,7 @@ public abstract class SensorHandler<T> {
} }
@NonNull @NonNull
protected abstract Aggregator<T, ?> createAggregator(); protected abstract Aggregator<AggregatorInput, AggregatorOutput> createAggregator();
protected abstract int getSensorPreferenceKey(); protected abstract int getSensorPreferenceKey();
@@ -93,14 +97,23 @@ public abstract class SensorHandler<T> {
return sensorManager.getContext(); return sensorManager.getContext();
} }
//TODO Try to keep aggregator private. void resetAggregated() {
Aggregator<T, ?> getAggregator() { if (aggregator != null) {
return aggregator; aggregator.resetAggregated();
}
}
@Nullable
SensorData<AggregatorOutput> getSensorData(Instant now) {
if (aggregator == null) return null;
if (!aggregator.hasReceivedData()) return null;
return aggregator.getAggregatedValueWithSensorName(now);
} }
//TODO REMOVE //TODO REMOVE
@VisibleForTesting @VisibleForTesting
public void setAggregator(Aggregator<T, ?> aggregator) { public void setAggregator(Aggregator<AggregatorInput, AggregatorOutput> aggregator) {
this.aggregator = aggregator; this.aggregator = aggregator;
} }
} }
@@ -18,7 +18,6 @@ import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Position; import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Speed;
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.AggregatorCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
@@ -121,13 +120,13 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
Log.i(TAG, "Resetting data"); Log.i(TAG, "Resetting data");
if (heartRateHandler.getAggregator() != null) heartRateHandler.getAggregator().resetAggregated(); heartRateHandler.resetAggregated();
if (temperatureHandler.getAggregator() != null) temperatureHandler.getAggregator().resetAggregated(); temperatureHandler.resetAggregated();
if (cyclingCadenceHandler.getAggregator() != null) cyclingCadenceHandler.getAggregator().resetAggregated(); cyclingCadenceHandler.resetAggregated();
if (cyclingDistanceSpeedHandler.getAggregator() != null) cyclingDistanceSpeedHandler.getAggregator().resetAggregated(); cyclingDistanceSpeedHandler.resetAggregated();
if (cyclingPowerHandler.getAggregator() != null) cyclingPowerHandler.getAggregator().resetAggregated(); cyclingPowerHandler.resetAggregated();
if (runningSpeedCadenceDistanceHandler.getAggregator() != null) runningSpeedCadenceDistanceHandler.getAggregator().resetAggregated(); runningSpeedCadenceDistanceHandler.resetAggregated();
if (altitudeChangeHandler.getAggregator() != null) altitudeChangeHandler.getAggregator().resetAggregated(); altitudeChangeHandler.resetAggregated();
if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated();
} }
@@ -189,8 +188,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
} }
private SensorData<HeartRate> getHeartRate(Instant now) { private SensorData<HeartRate> getHeartRate(Instant now) {
if (heartRateHandler.getAggregator() != null) { SensorData<HeartRate> value = heartRateHandler.getSensorData(now);
SensorData<HeartRate> value = ((AggregatorHeartRate) heartRateHandler.getAggregator()).getAggregatedValueWithSensorName(now); if (value != null) {
//TODO Move this check into HeartRateHandler //TODO Move this check into HeartRateHandler
if (value.data().isValid()) return value; if (value.data().isValid()) return value;
} }
@@ -199,25 +199,32 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
} }
private SensorData<Cadence> getCadence(Instant now) { private SensorData<Cadence> getCadence(Instant now) {
if (cyclingCadenceHandler.getAggregator() != null) { {
return ((AggregatorCyclingCadence) cyclingCadenceHandler.getAggregator()).getAggregatedValueWithSensorName(now); SensorData<Cadence> value = cyclingCadenceHandler.getSensorData(now);
if (value != null) {
return cyclingCadenceHandler.getSensorData(now);
}
} }
if (runningSpeedCadenceDistanceHandler.getAggregator() != null && runningSpeedCadenceDistanceHandler.getAggregator().hasReceivedData() && ((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).cadence() != null) { SensorData<AggregatorRunning.Data> value = runningSpeedCadenceDistanceHandler.getSensorData(now);
return new SensorData<>(((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue().cadence(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); if (value != null && value.data().cadence() != null) {
return new SensorData<>(value.data().cadence(), value.sensorNameOrAddress());
} }
return null; return null;
} }
private SensorData<Distance> getDistance(Instant now) { private SensorData<Distance> getDistance(Instant now) {
if (cyclingDistanceSpeedHandler.getAggregator() != null && cyclingDistanceSpeedHandler.getAggregator().hasReceivedData()) { {
return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); SensorData<AggregatorCyclingDistanceSpeed.Data> value = cyclingDistanceSpeedHandler.getSensorData(now);
if (value != null) {
return new SensorData<>(value.data().distanceOverall(), value.sensorNameOrAddress());
}
} }
if (runningSpeedCadenceDistanceHandler.getAggregator() != null && runningSpeedCadenceDistanceHandler.getAggregator().hasReceivedData()) { SensorData<AggregatorRunning.Data> value = runningSpeedCadenceDistanceHandler.getSensorData(now);
return new SensorData<>(((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).distance(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); if (value != null) {
return new SensorData<>(value.data().distance(), value.sensorNameOrAddress());
} }
return null; return null;
@@ -225,13 +232,16 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
//TOOD simplify? //TOOD simplify?
private SensorData<Speed> getSpeed(Instant now) { private SensorData<Speed> getSpeed(Instant now) {
{
if (cyclingDistanceSpeedHandler.getAggregator() != null && cyclingDistanceSpeedHandler.getAggregator().hasReceivedData() && ((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).speed() != null) { SensorData<AggregatorCyclingDistanceSpeed.Data> value = cyclingDistanceSpeedHandler.getSensorData(now);
return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).speed(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); if (value != null && value.data() != null && value.data().speed() != null) {
return new SensorData<>(value.data().speed(), value.sensorNameOrAddress());
}
} }
if (runningSpeedCadenceDistanceHandler.getAggregator() != null && runningSpeedCadenceDistanceHandler.getAggregator().hasReceivedData() && ((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).speed() != null) { SensorData<AggregatorRunning.Data> value = runningSpeedCadenceDistanceHandler.getSensorData(now);
return new SensorData<>(((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue().speed(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); if (value != null && value.data() != null && value.data().speed() != null) {
return new SensorData<>(value.data().speed(), value.sensorNameOrAddress());
} }
return null; return null;
@@ -273,7 +283,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
observer.onChange(); observer.onChange();
} }
// TODO inline with stop()?
@VisibleForTesting @VisibleForTesting
public void clear() { public void clear() {
Log.i(TAG, "Removing all aggregators"); Log.i(TAG, "Removing all aggregators");
@@ -307,17 +316,16 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
public SensorDataSet getSensorDataSet(Instant now) { public SensorDataSet getSensorDataSet(Instant now) {
AggregatorGPS gps = gpsManager.getAggregatorGPS(); AggregatorGPS gps = gpsManager.getAggregatorGPS();
AggregatorBarometer barometer = (AggregatorBarometer) altitudeChangeHandler.getAggregator();
return new SensorDataSet( return new SensorDataSet(
gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""),
getSpeed(now), getSpeed(now),
getDistance(now), getDistance(now),
getHeartRate(now), getHeartRate(now),
temperatureHandler.getAggregator() != null && temperatureHandler.getAggregator().hasReceivedData() ? ((AggregatorTemperature) temperatureHandler.getAggregator()).getAggregatedValueWithSensorName(now) : null, temperatureHandler.getSensorData(now),
getCadence(now), getCadence(now),
cyclingPowerHandler.getAggregator() != null && cyclingPowerHandler.getAggregator().hasReceivedData() ? ((AggregatorCyclingPower) cyclingPowerHandler.getAggregator()).getAggregatedValueWithSensorName(now) : null, cyclingPowerHandler.getSensorData(now),
barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null altitudeChangeHandler.getSensorData(now)
); );
} }
} }
@@ -7,10 +7,9 @@ import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.BluetoothDriver;
import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.Driver;
import de.dennisguse.opentracks.sensors.driver.TemperatureBluetooth; import de.dennisguse.opentracks.sensors.driver.TemperatureBluetooth;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
public class TemperatureHandler extends SensorHandler<Temperature> { public class TemperatureHandler extends SensorHandler<Temperature, Temperature> {
protected TemperatureHandler(SensorManager sensorManager) { protected TemperatureHandler(SensorManager sensorManager) {
super(sensorManager); super(sensorManager);
@@ -28,7 +27,7 @@ public class TemperatureHandler extends SensorHandler<Temperature> {
@NonNull @NonNull
@Override @Override
protected Aggregator<Temperature, ?> createAggregator() { protected AggregatorTemperature createAggregator() {
return new AggregatorTemperature("", null); return new AggregatorTemperature("", null);
} }
@@ -25,12 +25,12 @@ public abstract class Aggregator<Input, Output> {
this.sensorName = sensorName; this.sensorName = sensorName;
} }
public String getSensorNameOrAddress() { private String getSensorNameOrAddress() {
return sensorName != null ? sensorName : sensorAddress; return sensorName != null ? sensorName : sensorAddress;
} }
public final void add(Instant now, Input current) { public final void add(Instant now, Input current) {
Raw next = new Raw<>(now, current); Raw<Input> next = new Raw<>(now, current);
computeValue(next); computeValue(next);
previous = next; previous = next;
} }