From ea27db13fac0cac7a3c2e477f3e00c6ce55a61bf Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 20:46:08 +0100 Subject: [PATCH] Created RunningSpeedCadenceDistanceHandler. --- .../TrackRecordingServiceRecordingTest.java | 18 ++-- .../RunningSpeedCadenceDistanceHandler.java | 57 ++++++++++ .../opentracks/sensors/SensorManager.java | 100 ++++++------------ .../opentracks/settings/PreferencesUtils.java | 4 - 4 files changed, 103 insertions(+), 76 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 67b1ac760..b70073f66 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -810,19 +810,22 @@ public class TrackRecordingServiceRecordingTest { trackPointCreator.setClock(startTime); Track.Id trackId = service.startNewTrack(); + AggregatorRunning aggregatorRunning = new AggregatorRunning("", ""); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.add(new AggregatorRunning("", "")); + sensorManager.add(aggregatorRunning); // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); //Should be ignored - sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO)); + aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO)); + sensorManager.onChange(); // when String sensor2 = "2020-02-02T02:02:04Z"; trackPointCreator.setClock(sensor2); - sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2))); + aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2))); + sensorManager.onChange(); // when String gps1 = "2020-02-02T02:02:05Z"; @@ -831,13 +834,15 @@ public class TrackRecordingServiceRecordingTest { // when String sensor3 = "2020-02-02T02:02:06Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12))); + aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12))); + sensorManager.onChange(); // when String sensor4 = "2020-02-02T02:02:07Z"; trackPointCreator.setClock(sensor4); //Should be ignored - sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14))); + aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14))); + sensorManager.onChange(); // when String gps2 = "2020-02-02T02:02:08Z"; @@ -847,7 +852,8 @@ public class TrackRecordingServiceRecordingTest { String sensor5 = "2020-02-02T02:02:10Z"; trackPointCreator.setClock(sensor5); //Should be ignored - sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16))); + aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16))); + sensorManager.onChange(); // when String gps3 = "2020-02-02T02:02:12Z"; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java new file mode 100644 index 000000000..98e7ca033 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java @@ -0,0 +1,57 @@ +package de.dennisguse.opentracks.sensors; + +import androidx.annotation.NonNull; + +import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.sensors.driver.Driver; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; +import de.dennisguse.opentracks.sensors.sensorData.Aggregator; +import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; + +public class RunningSpeedCadenceDistanceHandler extends SensorHandler { + + protected RunningSpeedCadenceDistanceHandler(SensorManager sensorManager) { + super(sensorManager); + } + + @NonNull + @Override + protected Driver createDriverBluetooth(String address) { + return new BluetoothConnectionManager( + BluetoothUtils.getAdapter(getContext()), + new DriverObserver0() { + @Override + public void onConnect(Aggregator emptySensorData) { + driverObserver.onConnect(); + } + + @Override + public void onDisconnect(Aggregator emptySensorData) { + driverObserver.onDisconnect(); + } + + @Override + public void onRemove(Aggregator emptySensorData) { + driverObserver.onRemove(); + } + + @Override + public void onChange(Record value) { + driverObserver.onData((BluetoothHandlerRunningSpeedAndCadence.Data) value); + } + }, + new BluetoothHandlerRunningSpeedAndCadence() + ); + } + + @NonNull + @Override + protected AggregatorRunning createAggregator() { + return new AggregatorRunning("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_running_speed_and_cadence_key; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 3a83bbcd0..0adc79c2a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -1,6 +1,5 @@ package de.dennisguse.opentracks.sensors; -import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; @@ -13,7 +12,6 @@ import androidx.annotation.VisibleForTesting; import java.time.Instant; -import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.HeartRate; @@ -54,7 +52,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private CyclingCadenceHandler cyclingCadenceHandler; private CyclingDistanceSpeedHandler cyclingDistanceSpeedHandler; private CyclingPowerHandler cyclingPowerHandler; - private BluetoothConnectionManager runningSpeedAndCadenceManager; + private RunningSpeedCadenceDistanceHandler runningSpeedCadenceDistanceHandler; private GainManager altitudeSumManager; @@ -80,9 +78,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingCadenceHandler = new CyclingCadenceHandler(this); this.cyclingDistanceSpeedHandler = new CyclingDistanceSpeedHandler(this); this.cyclingPowerHandler = new CyclingPowerHandler(this); - - BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); - this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); + this.runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this); altitudeSumManager.start(context, handler); heartRateHandler.start(context, handler); @@ -90,6 +86,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingCadenceHandler.start(context, handler); cyclingDistanceSpeedHandler.start(context, handler); cyclingPowerHandler.start(context, handler); + runningSpeedCadenceDistanceHandler.start(context, handler); + onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -113,8 +111,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingPowerHandler.stop(); cyclingPowerHandler = null; - runningSpeedAndCadenceManager.disconnect(); - runningSpeedAndCadenceManager = null; + runningSpeedCadenceDistanceHandler.stop(); + runningSpeedCadenceDistanceHandler = null; altitudeSumManager.stop(); altitudeSumManager = null; @@ -141,7 +139,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingCadenceHandler.getAggregator() != null) cyclingCadenceHandler.getAggregator().resetAggregated(); if (cyclingDistanceSpeedHandler.getAggregator() != null) cyclingDistanceSpeedHandler.getAggregator().resetAggregated(); if (cyclingPowerHandler.getAggregator() != null) cyclingPowerHandler.getAggregator().resetAggregated(); - if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); + if (runningSpeedCadenceDistanceHandler.getAggregator() != null) runningSpeedCadenceDistanceHandler.getAggregator().resetAggregated(); if (altitudeSumManager.getAggregator() != null) altitudeSumManager.getAggregator().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); } @@ -195,10 +193,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingPowerHandler.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) { - String address = PreferencesUtils.getBluetoothRunningSpeedAndCadenceAddress(); - - connect(runningSpeedAndCadenceManager, address); + if (PreferencesUtils.isKey(runningSpeedCadenceDistanceHandler.getSensorPreferenceKey(), key)) { + runningSpeedCadenceDistanceHandler.connect(); } } } @@ -206,30 +202,32 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange //TODO Inlined from SensorDataAggregator; Aggregators will be moved into Drivers. @Deprecated public void onConnect(Aggregator aggregator) { - add(aggregator); + throw new UnsupportedOperationException(); } @Deprecated public void onDisconnect(Aggregator aggregator) { - add(aggregator); + throw new UnsupportedOperationException(); } @Deprecated public void onRemove(Aggregator aggregator) { - remove(aggregator); + throw new UnsupportedOperationException(); + } + + @Override + public void onChange(Record value) { + throw new UnsupportedOperationException(); } public Instant getNow() { return observer.getNow(); } - @VisibleForTesting - public AggregatorRunning runningDistanceSpeedCadence; - @VisibleForTesting public SensorData getHeartRate(Instant now) { if (heartRateHandler.getAggregator() != null) { - SensorData value = (SensorData) heartRateHandler.getAggregator().getAggregatedValueWithSensorName(now); + SensorData value = ((AggregatorHeartRate) heartRateHandler.getAggregator()).getAggregatedValueWithSensorName(now); //TODO Move this check into HeartRateHandler if (value.data().isValid()) return value; } @@ -239,11 +237,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private SensorData getCadence(Instant now) { if (cyclingCadenceHandler.getAggregator() != null) { - return (SensorData) cyclingCadenceHandler.getAggregator().getAggregatedValueWithSensorName(now); + return ((AggregatorCyclingCadence) cyclingCadenceHandler.getAggregator()).getAggregatedValueWithSensorName(now); } - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).cadence() != null) { - return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue().cadence(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + 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()); } return null; @@ -254,8 +252,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); } - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) { - return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue(now).distance(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + if (runningSpeedCadenceDistanceHandler.getAggregator() != null && runningSpeedCadenceDistanceHandler.getAggregator().hasReceivedData()) { + return new SensorData<>(((AggregatorRunning)runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).distance(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); } @@ -269,8 +267,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).speed(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); } - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) { - return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue().speed(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + 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()); } return null; @@ -297,46 +295,25 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return; } if (data instanceof AggregatorCyclingPower) { - cyclingPowerHandler.setAggregator((Aggregator) data); + cyclingPowerHandler.setAggregator((AggregatorCyclingPower) data); + return; + } + if (data instanceof AggregatorRunning) { + runningSpeedCadenceDistanceHandler.setAggregator((AggregatorRunning) data); return; } - set(data, data); - } - - @Deprecated - public void onChange(Record data) { - update(data); - onChange(); + throw new UnsupportedOperationException(data.getClass().getCanonicalName()); } public void onChange() { observer.onChange(); } - //TODO Refactor generic "fun" here: go explicit. - @Deprecated - private void update(@NonNull Record value) { - Instant now = getNow(); - if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { - this.runningDistanceSpeedCadence.add(now, (BluetoothHandlerRunningSpeedAndCadence.Data) value); - - return; - } - - throw new UnsupportedOperationException(value.getClass().getCanonicalName()); - } - - @Deprecated - public void remove(@NonNull Aggregator type) { - set(type, null); - } - // TODO inline with stop()? @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.runningDistanceSpeedCadence = null; //TODO This is to ExportImportTest alive; refactor test. if (this.altitudeSumManager != null) { @@ -357,6 +334,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingPowerHandler != null) { cyclingPowerHandler.setAggregator(null); } + if (runningSpeedCadenceDistanceHandler != null) { + runningSpeedCadenceDistanceHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -377,16 +357,4 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange 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 AggregatorRunning) { - runningDistanceSpeedCadence = (AggregatorRunning) sensorData; - return; - } - - throw new UnsupportedOperationException(type.getClass().getCanonicalName()); - } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 258d91344..acff98e07 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -269,10 +269,6 @@ public class PreferencesUtils { return Distance.ofMM(getInt(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key, DEFAULT)); } - public static String getBluetoothRunningSpeedAndCadenceAddress() { - return getString(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, getBluetoothSensorAddressNone()); - } - public static boolean getBluetoothFilterEnabled() { final boolean DEFAULT = resources.getBoolean(R.bool.settings_sensor_bluetooth_service_filter_enabled_default); return getBoolean(R.string.settings_sensor_bluetooth_service_filter_enabled_key, DEFAULT);