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