From 744853ee91a20a7adcae0a04362732d2a04a5bd6 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 26 Jan 2026 19:37:38 +0100 Subject: [PATCH 01/30] Cleanup: removed SensorConnector interface. Preparation for refactoring. --- .../sensors/BluetoothRemoteSensorManager.java | 8 +++----- .../de/dennisguse/opentracks/sensors/GainManager.java | 4 ++-- .../de/dennisguse/opentracks/sensors/GpsManager.java | 4 ++-- .../opentracks/sensors/SensorConnector.java | 11 ----------- .../dennisguse/opentracks/sensors/SensorManager.java | 8 ++++---- 5 files changed, 11 insertions(+), 24 deletions(-) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/SensorConnector.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java index 66bccbdce..844653017 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java @@ -34,7 +34,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; * TODO: listen for Bluetooth enabled/disabled events. * @author Sandor Dornbush */ -public class BluetoothRemoteSensorManager implements SensorConnector, SharedPreferences.OnSharedPreferenceChangeListener { +public class BluetoothRemoteSensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = BluetoothRemoteSensorManager.class.getSimpleName(); @@ -62,16 +62,14 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref this.runningSpeedAndCadence = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerRunningSpeedAndCadence()); } - @Override - public void start(Context context, Handler handler) { + public void start() { started = true; // Triggers connection startup onSharedPreferenceChanged(null, null); } - @Override - public synchronized void stop(Context context) { + public synchronized void stop() { heartRate.disconnect(); temperature.disconnect(); cyclingCadence.disconnect(); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index 0d63227bf..6cace34bb 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -13,7 +13,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; /** * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer). */ -public class GainManager implements SensorConnector { +public class GainManager { private static final String TAG = GainManager.class.getSimpleName(); @@ -36,7 +36,7 @@ public class GainManager implements SensorConnector { PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); } - public void stop(Context context) { + public void stop() { Log.d(TAG, "Stop"); this.context = null; this.handler = null; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index e1c5ef717..7398db858 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -26,7 +26,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.PermissionRequester; @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) -public class GpsManager implements SensorConnector, LocationListenerCompat, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { +public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { private final String TAG = GpsManager.class.getSimpleName(); @@ -68,7 +68,7 @@ public class GpsManager implements SensorConnector, LocationListenerCompat, GpsS } @SuppressWarnings({"MissingPermission"}) - public void stop(Context context) { + public void stop() { if (isStarted()) { LocationManagerCompat.removeUpdates(locationManager, this); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorConnector.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorConnector.java deleted file mode 100644 index cea9f44ee..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorConnector.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.dennisguse.opentracks.sensors; - -import android.content.Context; -import android.os.Handler; - -public interface SensorConnector { - - void start(Context context, Handler handler); - - void stop(Context context); -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index d645748ea..af804d493 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -85,19 +85,19 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager.start(context, handler); altitudeSumManager.start(context, handler); - bluetoothSensorManager.start(context, handler); + bluetoothSensorManager.start(); } public void stop(Context context) { wakeLock = SystemUtils.releaseWakeLock(wakeLock); - bluetoothSensorManager.stop(context); + bluetoothSensorManager.stop(); bluetoothSensorManager = null; - altitudeSumManager.stop(context); + altitudeSumManager.stop(); altitudeSumManager = null; - gpsManager.stop(context); + gpsManager.stop(); gpsManager = null; sensorDataAggregator.clear(); From 1a14fed287233950c3b20418a4d19bad8bd7d2b0 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 26 Jan 2026 20:13:11 +0100 Subject: [PATCH 02/30] Cleanup: SensorDataAggregator inlined into SensorManager. Preparation for refactoring. --- .../io/file/importer/ExportImportTest.java | 27 +- .../TrackRecordingServiceRecordingTest.java | 8 +- .../opentracks/sensors/SensorManager.java | 243 ++++++++++++++++-- .../sensors/sensorData/Aggregator.java | 5 + .../sensorData/SensorDataAggregator.java | 229 ----------------- 5 files changed, 250 insertions(+), 262 deletions(-) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 6743393fc..16c46d2e4 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -67,6 +67,7 @@ import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.exporter.TrackExporter; 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.AggregatorBarometer; 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.AggregatorTemperature; 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.handlers.TrackPointCreator; @@ -197,7 +197,7 @@ public class ExportImportTest { )); trackPointCreator.setClock("2020-02-02T02:02:18Z"); - trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); + trackPointCreator.getSensorManager().clear(); service.endCurrentTrack(); 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); - trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); + trackPointCreator.getSensorManager().clear(); trackPointCreator.setClock("2020-02-02T02:04:00Z"); 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) { - SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; + SensorManager sensorManager = trackPointCreator.getSensorManager(); AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null))); - sensorDataAggregator.add(cyclingPower); + sensorManager.add(cyclingPower); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate))); - sensorDataAggregator.add(avgHeartRate); + sensorManager.add(avgHeartRate); AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") { @NonNull @@ -684,7 +684,7 @@ public class ExportImportTest { return true; } }; - sensorDataAggregator.add(cyclingCadence); + sensorManager.add(cyclingCadence); if (distance != null && speed != null) { AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") { @@ -699,14 +699,14 @@ public class ExportImportTest { return true; } }; - sensorDataAggregator.add(aggregatorCyclingDistanceSpeed); + sensorManager.add(aggregatorCyclingDistanceSpeed); } else { - sensorDataAggregator.add(new AggregatorCyclingDistanceSpeed("", "")); + sensorManager.add(new AggregatorCyclingDistanceSpeed("", "")); } mockAltitudeChange(trackPointCreator, altitudeGain); - sensorDataAggregator.add(new AggregatorTemperature("", "'") { + sensorManager.add(new AggregatorTemperature("", "'") { @NonNull @Override public Temperature getAggregatedValue(Instant now) { @@ -723,10 +723,11 @@ public class ExportImportTest { } private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { - SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; + SensorManager sensorManager = trackPointCreator.getSensorManager(); + sensorManager.reset(); if (altitudeGain == null) { - sensorDataAggregator.add(new AggregatorBarometer("test", null)); + sensorManager.add(new AggregatorBarometer("test", null)); return; } @@ -742,7 +743,7 @@ public class ExportImportTest { 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) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 74dec63dc..0993e69d5 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -339,7 +339,7 @@ public class TrackRecordingServiceRecordingTest { mockAltitudeChange(trackPointCreator, 0); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.sensorDataAggregator.add(new AggregatorHeartRate("", "")); + sensorManager.add(new AggregatorHeartRate("", "")); // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); @@ -809,8 +809,8 @@ public class TrackRecordingServiceRecordingTest { Track.Id trackId = service.startNewTrack(); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.sensorDataAggregator.add(new AggregatorRunning("", "")); - sensorManager.sensorDataAggregator.barometer = null; + sensorManager.add(new AggregatorRunning("", "")); + sensorManager.barometer = null; // when String sensor1 = "2020-02-02T02:02:03Z"; @@ -962,7 +962,7 @@ public class TrackRecordingServiceRecordingTest { } private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { - trackPointCreator.getSensorManager().sensorDataAggregator.barometer = new AggregatorBarometer("", "") { + trackPointCreator.getSensorManager().barometer = new AggregatorBarometer("", "") { @Override public boolean hasReceivedData() { return true; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index af804d493..ea34eb109 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -6,26 +6,39 @@ import android.os.Handler; import android.os.PowerManager; 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.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.SensorDataAggregator; +import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; +import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.SystemUtils; public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { 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 final TrackPointCreator observer; @@ -34,23 +47,23 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Override public void onConnect(Aggregator aggregator) { - sensorDataAggregator.add(aggregator); + add(aggregator); } @Override public void onChange(Raw data) { - sensorDataAggregator.update(data); + update(data); observer.onChange(); } @Override public void onDisconnect(Aggregator aggregator) { - sensorDataAggregator.add(aggregator); + add(aggregator); } @Override public void onRemove(Aggregator aggregator) { - sensorDataAggregator.remove(aggregator); + remove(aggregator); } @Override @@ -67,7 +80,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public SensorManager(TrackPointCreator observer) { this.observer = observer; - this.sensorDataAggregator = new SensorDataAggregator(); } public void start(Context context, Handler handler) { @@ -100,11 +112,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager.stop(); gpsManager = null; - sensorDataAggregator.clear(); - } - - public SensorDataSet getSensorDataSet(Instant now) { - return sensorDataAggregator.getSensorData(now); + clear(); } public void reset() { @@ -112,7 +120,17 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange Log.d(TAG, "No recording running and no reset necessary."); 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 @@ -155,4 +173,197 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange 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 getHeartRate(Instant now) { + if (heartRate != null) { + SensorData value = heartRate.getAggregatedValueWithSensorName(now); + if (value.data().isValid()) return value; + } + + return null; + } + + private SensorData 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 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 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) data); + return; + } + + if (value instanceof Temperature) { + this.temperature.add((Raw) data); + return; + } + + if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { + this.cyclingCadence.add((Raw) data); + return; + } + if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { + this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. + this.cyclingDistanceSpeed.add((Raw) data); + return; + } + if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { + this.runningDistanceSpeedCadence.add((Raw) data); + + return; + } + if (value instanceof BluetoothHandlerCyclingPower.Data) { + this.cyclingPower.add((Raw) data); + return; + } + if (value instanceof AtmosphericPressure) { + this.barometer.add((Raw) data); + return; + } + if (value instanceof Position) { + this.gps.add((Raw) 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()); + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index 44f66136c..0b20aa1a9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -48,6 +48,11 @@ public abstract class Aggregator { @NonNull 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 public Output getAggregatedValue(Instant now) { if (!hasReceivedData()) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java deleted file mode 100644 index 61990e1d6..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java +++ /dev/null @@ -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 getHeartRate(Instant now) { - if (heartRate != null) { - SensorData value = heartRate.getAggregatedValueWithSensorName(now); - if (value.data().isValid()) return value; - } - - return null; - } - - private SensorData 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 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 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) data); - return; - } - - if (value instanceof Temperature) { - this.temperature.add((Raw) data); - return; - } - - if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { - this.cyclingCadence.add((Raw) data); - return; - } - if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { - this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. - this.cyclingDistanceSpeed.add((Raw) data); - return; - } - if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { - this.runningDistanceSpeedCadence.add((Raw) data); - - return; - } - if (value instanceof BluetoothHandlerCyclingPower.Data) { - this.cyclingPower.add((Raw) data); - return; - } - if (value instanceof AtmosphericPressure) { - this.barometer.add((Raw) data); - return; - } - if (value instanceof Position) { - this.gps.add((Raw) 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()); - } -} From 74954df600adc31a9f63211aaf8fb2d878fd2c10 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 26 Jan 2026 20:22:01 +0100 Subject: [PATCH 03/30] Cleanup: SensorManager.SensorDataChangedObserver inlined into SensorManager. Preparation for refactoring. --- .../TrackRecordingServiceRecordingTest.java | 18 +++-- .../sensors/BluetoothConnectionManager.java | 4 +- .../BluetoothHandlerBarometricPressure.java | 2 +- .../BluetoothHandlerCyclingCadence.java | 2 +- .../BluetoothHandlerCyclingDistanceSpeed.java | 2 +- .../sensors/BluetoothHandlerCyclingPower.java | 2 +- .../sensors/BluetoothHandlerHeartRate.java | 2 +- ...luetoothHandlerRunningSpeedAndCadence.java | 2 +- .../sensors/BluetoothHandlerTemperature.java | 2 +- .../sensors/BluetoothRemoteSensorManager.java | 2 +- .../opentracks/sensors/GainManager.java | 4 +- .../opentracks/sensors/GpsManager.java | 4 +- .../opentracks/sensors/SensorManager.java | 78 +++++++------------ .../opentracks/sensors/SensorType.java | 2 + .../sensors/driver/BarometerInternal.java | 4 +- .../sensorData/SensorHandlerInterface.java | 2 +- 16 files changed, 58 insertions(+), 74 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 0993e69d5..65c833770 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -344,11 +344,12 @@ public class TrackRecordingServiceRecordingTest { String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); - sensorManager.onChanged(new Raw<>(sensor1, HeartRate.of(5))); //Should be ignored + //Should be ignored + sensorManager.onChange(new Raw(sensor1, HeartRate.of(5))); String sensor3 = "2020-02-02T02:02:13Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChanged(new Raw<>(sensor3, HeartRate.of(7))); + sensorManager.onChange(new Raw(sensor3, HeartRate.of(7))); String stopTime = "2020-02-02T02:02:15Z"; trackPointCreator.setClock(stopTime); @@ -815,12 +816,13 @@ public class TrackRecordingServiceRecordingTest { // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); - sensorManager.onChanged(new Raw<>(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO))); //Should be ignored + //Should be ignored + sensorManager.onChange(new Raw(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO))); // when String sensor2 = "2020-02-02T02:02:04Z"; trackPointCreator.setClock(sensor2); - sensorManager.onChanged(new Raw<>(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2)))); + sensorManager.onChange(new Raw(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2)))); // when String gps1 = "2020-02-02T02:02:05Z"; @@ -829,12 +831,13 @@ public class TrackRecordingServiceRecordingTest { // when String sensor3 = "2020-02-02T02:02:06Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChanged(new Raw<>(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12)))); + sensorManager.onChange(new Raw(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12)))); // when String sensor4 = "2020-02-02T02:02:07Z"; trackPointCreator.setClock(sensor4); - sensorManager.onChanged(new Raw<>(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14)))); //Should be ignored + //Should be ignored + sensorManager.onChange(new Raw(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14)))); // when String gps2 = "2020-02-02T02:02:08Z"; @@ -843,7 +846,8 @@ public class TrackRecordingServiceRecordingTest { // when String sensor5 = "2020-02-02T02:02:10Z"; trackPointCreator.setClock(sensor5); - sensorManager.onChanged(new Raw<>(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16)))); //Should be ignored + //Should be ignored + sensorManager.onChange(new Raw(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16)))); // when String gps3 = "2020-02-02T02:02:12Z"; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java index ac1cc7ee2..9464d74fa 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java @@ -45,7 +45,7 @@ public class BluetoothConnectionManager implements Driver { private static final String TAG = BluetoothConnectionManager.class.getSimpleName(); - private final SensorManager.SensorDataChangedObserver observer; + private final SensorManager observer; private final SensorHandlerInterface sensorHandler; @@ -131,7 +131,7 @@ public class BluetoothConnectionManager implements Driver { } }; - BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, SensorManager.SensorDataChangedObserver observer, SensorHandlerInterface sensorHandler) { + BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, SensorManager observer, SensorHandlerInterface sensorHandler) { this.bluetoothAdapter = bluetoothAdapter; this.observer = observer; this.sensorHandler = sensorHandler; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java index ce7f58823..75868f03f 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java @@ -29,7 +29,7 @@ public class BluetoothHandlerBarometricPressure implements SensorHandlerInterfac } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { AtmosphericPressure value = parseEnvironmentalSensing(characteristic); if (value == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java index 64ba0e0b5..98de00f94 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java @@ -29,7 +29,7 @@ public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { if (serviceMeasurementUUID.equals(BluetoothHandlerCyclingPower.CYCLING_POWER)) { BluetoothHandlerCyclingPower.Data data = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); if (data != null && data.crank() != null) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java index 28219799f..f7ae6a60e 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java @@ -31,7 +31,7 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Pair data = parseCyclingCrankAndWheel(address, sensorName, characteristic); if (data.first != null) { observer.onChange(new Raw<>(observer.getNow(), data.first)); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java index 126bea6b0..b78a7609b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java @@ -31,7 +31,7 @@ public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data cyclingPower = parseCyclingPower(characteristic); if (cyclingPower != null) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java index 7294b3136..e9c741ba9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java @@ -41,7 +41,7 @@ public class BluetoothHandlerHeartRate implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { HeartRate heartRate = parseHeartRate(characteristic); if (heartRate != null) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java index fd147845c..3d9701b30 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java @@ -34,7 +34,7 @@ public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInte } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data data = parseRunningSpeedAndCadence(sensorName, characteristic); observer.onChange(new Raw<>(observer.getNow(), data)); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java index 18b1ac1fa..9625832e7 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java @@ -30,7 +30,7 @@ public class BluetoothHandlerTemperature implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Temperature value = parseEnvironmentalSensing(characteristic); if (value == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java index 844653017..9256aded6 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java @@ -49,7 +49,7 @@ public class BluetoothRemoteSensorManager implements SharedPreferences.OnSharedP private final BluetoothConnectionManager cyclingPower; private final BluetoothConnectionManager runningSpeedAndCadence; - public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) { + public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager observer) { this.context = context; this.handler = handler; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index 6cace34bb..822158e92 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -18,7 +18,7 @@ public class GainManager { private static final String TAG = GainManager.class.getSimpleName(); - private final SensorManager.SensorDataChangedObserver listener; + private final SensorManager listener; private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> connect(); @@ -26,7 +26,7 @@ public class GainManager { private Handler handler; private Driver driver; - public GainManager(SensorManager.SensorDataChangedObserver listener) { + public GainManager(SensorManager listener) { this.listener = listener; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index 7398db858..eceb62dda 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -34,7 +34,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS private TrackPointCreator trackPointCreator; - private SensorManager.SensorDataChangedObserver observer; + private SensorManager observer; private Context context; private Handler handler; @@ -43,7 +43,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS private Duration gpsInterval; private Distance thresholdHorizontalAccuracy; - public GpsManager(TrackPointCreator trackPointCreator, SensorManager.SensorDataChangedObserver observer) { + public GpsManager(TrackPointCreator trackPointCreator, SensorManager observer) { this.trackPointCreator = trackPointCreator; this.observer = observer; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index ea34eb109..1c03fad49 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -43,35 +43,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private final TrackPointCreator observer; - private final SensorDataChangedObserver listener = new SensorDataChangedObserver() { - - @Override - public void onConnect(Aggregator aggregator) { - add(aggregator); - } - - @Override - public void onChange(Raw data) { - update(data); - observer.onChange(); - } - - @Override - public void onDisconnect(Aggregator aggregator) { - add(aggregator); - } - - @Override - public void onRemove(Aggregator aggregator) { - remove(aggregator); - } - - @Override - public Instant getNow() { - return observer.createNow(); - } - }; - private BluetoothRemoteSensorManager bluetoothSensorManager; private GainManager altitudeSumManager; @@ -89,9 +60,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange wakeLock = SystemUtils.acquireWakeLock(context, wakeLock); - gpsManager = new GpsManager(observer, listener); - altitudeSumManager = new GainManager(listener); - bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener); + gpsManager = new GpsManager(observer, this); + altitudeSumManager = new GainManager(this); + bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, this); onSharedPreferenceChanged(null, null); @@ -133,9 +104,23 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (gps != null) gps.resetAggregated(); } - @VisibleForTesting - public void onChanged(Raw data) { - listener.onChange(data); + @Deprecated + public void onConnect(Aggregator aggregator) { + add(aggregator); + } + + @Deprecated + public void onDisconnect(Aggregator aggregator) { + add(aggregator); + } + + @Deprecated + public void onRemove(Aggregator aggregator) { + remove(aggregator); + } + + public Instant getNow() { + return observer.createNow(); } public GpsManager getGpsManager() { @@ -162,20 +147,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } } - public interface SensorDataChangedObserver { - - void onConnect(Aggregator sensorData); - void onChange(Raw sensorData); - - void onDisconnect(Aggregator sensorData); - - void onRemove(Aggregator sensorData); - - Instant getNow(); - } - - - //TODO Inline from SensorDataAggregator; Aggregators will be moved into Drivers. + //TODO Inlined from SensorDataAggregator; Aggregators will be moved into Drivers. @VisibleForTesting public AggregatorHeartRate heartRate; @@ -252,8 +224,14 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange set(data, data); } + @Deprecated + public void onChange(Raw data) { + update(data); + observer.onChange(); + } + //TODO Refactor generic "fun" here: go explicit. - public void update(@NonNull Raw data) { + private void update(@NonNull Raw data) { Object value = data.value(); if (value instanceof HeartRate) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java index ad66d7fce..9fefe5195 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java @@ -3,6 +3,8 @@ package de.dennisguse.opentracks.sensors; public enum SensorType { NONE("NONE"), INTERNAL("INTERNAL"), + + //NOTE: preferenceValue of REMOTE should not be used anywhere. REMOTE("*"); private final String preferenceValue; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index 0929e875c..d81967b45 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -22,7 +22,7 @@ public class BarometerInternal implements Driver { private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5); - private final SensorManager.SensorDataChangedObserver observer; + private final SensorManager observer; private Context context; @@ -43,7 +43,7 @@ public class BarometerInternal implements Driver { } }; - public BarometerInternal(@NonNull SensorManager.SensorDataChangedObserver observer) { + public BarometerInternal(@NonNull SensorManager observer) { this.observer = observer; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java index 3406c907f..d9a162eee 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java @@ -13,5 +13,5 @@ public interface SensorHandlerInterface { Aggregator createEmptySensorData(String address, String name); - void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); + void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); } From 0f2c5adf26e306dcacd19058504fdfc6208d3e5f Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 26 Jan 2026 22:07:59 +0100 Subject: [PATCH 04/30] Cleanup: SensorManager.SensorDataChangedObserver inlined into SensorManager. Preparation for refactoring. --- .../opentracks/sensors/SensorManager.java | 40 +++++++++---------- .../services/handlers/TrackPointCreator.java | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 1c03fad49..da2d228fa 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -71,7 +71,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange bluetoothSensorManager.start(); } - public void stop(Context context) { + public void stop() { wakeLock = SystemUtils.releaseWakeLock(wakeLock); bluetoothSensorManager.stop(); @@ -104,25 +104,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (gps != null) gps.resetAggregated(); } - @Deprecated - public void onConnect(Aggregator aggregator) { - add(aggregator); - } - - @Deprecated - public void onDisconnect(Aggregator aggregator) { - add(aggregator); - } - - @Deprecated - public void onRemove(Aggregator aggregator) { - remove(aggregator); - } - - public Instant getNow() { - return observer.createNow(); - } - public GpsManager getGpsManager() { return gpsManager; } @@ -148,6 +129,25 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } //TODO Inlined from SensorDataAggregator; Aggregators will be moved into Drivers. + @Deprecated + public void onConnect(Aggregator aggregator) { + add(aggregator); + } + + @Deprecated + public void onDisconnect(Aggregator aggregator) { + add(aggregator); + } + + @Deprecated + public void onRemove(Aggregator aggregator) { + remove(aggregator); + } + + public Instant getNow() { + return observer.createNow(); + } + @VisibleForTesting public AggregatorHeartRate heartRate; diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java index ff1e6191a..5105ed9f5 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java @@ -56,7 +56,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } public void stop() { - sensorManager.stop(context); + sensorManager.stop(); this.context = null; } From 18ff96733e8f41e4ae5778f24249ccf0ad83777a Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 27 Jan 2026 17:59:08 +0100 Subject: [PATCH 05/30] Cleanup: moved Raw into Aggregator. Preparation for refactoring. --- .../io/file/importer/ExportImportTest.java | 5 ++- .../sensorData/AggregatorBarometerTest.java | 2 +- .../sensorData/SensorDataCyclingTest.java | 32 +++++++++---------- .../TrackRecordingServiceRecordingTest.java | 15 ++++----- .../BluetoothHandlerBarometricPressure.java | 3 +- .../BluetoothHandlerCyclingCadence.java | 5 ++- .../BluetoothHandlerCyclingDistanceSpeed.java | 11 ++++--- .../sensors/BluetoothHandlerCyclingPower.java | 7 ++-- .../sensors/BluetoothHandlerHeartRate.java | 7 ++-- ...luetoothHandlerRunningSpeedAndCadence.java | 5 +-- .../sensors/BluetoothHandlerTemperature.java | 3 +- .../opentracks/sensors/GpsManager.java | 6 ++-- .../opentracks/sensors/SensorManager.java | 28 ++++++++-------- .../sensors/driver/BarometerInternal.java | 3 +- .../sensors/sensorData/Aggregator.java | 13 ++++++-- .../opentracks/sensors/sensorData/Raw.java | 22 ------------- .../services/handlers/TrackPointCreator.java | 8 ++--- 17 files changed, 77 insertions(+), 98 deletions(-) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/sensorData/Raw.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 16c46d2e4..f35131938 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -75,7 +75,6 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpee import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; @@ -664,12 +663,12 @@ public class ExportImportTest { SensorManager sensorManager = trackPointCreator.getSensorManager(); AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); - cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null))); + cyclingPower.add(trackPointCreator.getNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null)); sensorManager.add(cyclingPower); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); - avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate))); + avgHeartRate.add(trackPointCreator.getNow(), HeartRate.of(heartRate)); sensorManager.add(avgHeartRate); AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") { diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java index 01d929f3d..c3960161e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java @@ -11,7 +11,7 @@ public class AggregatorBarometerTest { private static void addSensorValue(AggregatorBarometer aggregatorBarometer, float[] values) { for (float f : values) { - aggregatorBarometer.add(new Raw<>(Instant.MIN, AtmosphericPressure.ofHPA(f))); + aggregatorBarometer.add(Instant.MIN, AtmosphericPressure.ofHPA(f)); } } diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java index b317c718a..23d404b03 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java @@ -25,8 +25,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 2048))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 2048)); // then assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -37,8 +37,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 6184))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 8016))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 6184)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 8016)); // then assertEquals(33.53, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -49,8 +49,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 2048))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 2048)); // then assertEquals(Cadence.of(0), current.getAggregatedValue(Instant.MIN)); @@ -62,8 +62,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 1024))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 1024)); // then assertFalse(current.hasReceivedData()); //TODO Cadence should be 0? @@ -74,8 +74,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, UintUtils.UINT16_MAX - 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 0))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, UintUtils.UINT16_MAX - 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 0)); // then assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -87,8 +87,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(UintUtils.UINT32_MAX - 1, 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(0, 2048))); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(UintUtils.UINT32_MAX - 1, 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(0, 2048)); // then // TODO See #953 @@ -102,8 +102,8 @@ public class SensorDataCyclingTest { current.setWheelCircumference(Distance.ofMM(2150)); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(1, 6184))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(2, 8016))); + current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(1, 6184)); + current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(2, 8016)); // then assertEquals(2.15, current.getAggregatedValue(Instant.MIN).distance().toM(), 0.01); @@ -117,8 +117,8 @@ public class SensorDataCyclingTest { current.setWheelCircumference(Distance.ofMM(2000)); // when - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(UintUtils.UINT32_MAX - 1, 1024))); - current.add(new Raw<>(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(0, 2048))); + current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(UintUtils.UINT32_MAX - 1, 1024)); + current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(0, 2048)); // then diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 65c833770..3f98b55fa 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -49,7 +49,6 @@ import de.dennisguse.opentracks.sensors.SensorManager; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; @@ -345,11 +344,11 @@ public class TrackRecordingServiceRecordingTest { trackPointCreator.setClock(sensor1); //Should be ignored - sensorManager.onChange(new Raw(sensor1, HeartRate.of(5))); + sensorManager.onChange(HeartRate.of(5)); String sensor3 = "2020-02-02T02:02:13Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChange(new Raw(sensor3, HeartRate.of(7))); + sensorManager.onChange(HeartRate.of(7)); String stopTime = "2020-02-02T02:02:15Z"; trackPointCreator.setClock(stopTime); @@ -817,12 +816,12 @@ public class TrackRecordingServiceRecordingTest { String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); //Should be ignored - sensorManager.onChange(new Raw(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO))); + sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO)); // when String sensor2 = "2020-02-02T02:02:04Z"; trackPointCreator.setClock(sensor2); - sensorManager.onChange(new Raw(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2)))); + sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2))); // when String gps1 = "2020-02-02T02:02:05Z"; @@ -831,13 +830,13 @@ public class TrackRecordingServiceRecordingTest { // when String sensor3 = "2020-02-02T02:02:06Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChange(new Raw(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12)))); + sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12))); // when String sensor4 = "2020-02-02T02:02:07Z"; trackPointCreator.setClock(sensor4); //Should be ignored - sensorManager.onChange(new Raw(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14)))); + sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14))); // when String gps2 = "2020-02-02T02:02:08Z"; @@ -847,7 +846,7 @@ public class TrackRecordingServiceRecordingTest { String sensor5 = "2020-02-02T02:02:10Z"; trackPointCreator.setClock(sensor5); //Should be ignored - sensorManager.onChange(new Raw(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16)))); + sensorManager.onChange(new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16))); // when String gps3 = "2020-02-02T02:02:12Z"; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java index 75868f03f..2ee719541 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java @@ -8,7 +8,6 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerBarometricPressure implements SensorHandlerInterface { @@ -33,7 +32,7 @@ public class BluetoothHandlerBarometricPressure implements SensorHandlerInterfac AtmosphericPressure value = parseEnvironmentalSensing(characteristic); if (value == null) return; - observer.onChange(new Raw<>(observer.getNow(), value)); + observer.onChange(value); } /** diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java index 98de00f94..9429bd8e9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java @@ -7,7 +7,6 @@ import android.util.Pair; import java.util.List; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { @@ -33,7 +32,7 @@ public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { if (serviceMeasurementUUID.equals(BluetoothHandlerCyclingPower.CYCLING_POWER)) { BluetoothHandlerCyclingPower.Data data = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); if (data != null && data.crank() != null) { - observer.onChange(new Raw<>(observer.getNow(), data.crank())); + observer.onChange(data.crank()); } return; } @@ -42,7 +41,7 @@ public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { Pair data = BluetoothHandlerCyclingDistanceSpeed.parseCyclingCrankAndWheel(address, sensorName, characteristic); if (data != null && data.second != null) { - observer.onChange(new Raw<>(observer.getNow(), data.second)); + observer.onChange(data.second); } return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java index f7ae6a60e..d582545fb 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterface { @@ -33,9 +32,10 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf @Override public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Pair data = parseCyclingCrankAndWheel(address, sensorName, characteristic); - if (data.first != null) { - observer.onChange(new Raw<>(observer.getNow(), data.first)); - } + if (data == null) return; + if (data.first == null) return; + + observer.onChange(data.first); } @@ -78,5 +78,6 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf long wheelRevolutionsCount, // UINT32 int wheelRevolutionsTime // UINT16; 1/1024s - ) {} + ) { + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java index b78a7609b..586ae3f12 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java @@ -10,7 +10,6 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { @@ -34,9 +33,9 @@ public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data cyclingPower = parseCyclingPower(characteristic); - if (cyclingPower != null) { - observer.onChange(new Raw<>(observer.getNow(), cyclingPower)); - } + if (cyclingPower == null) return; + + observer.onChange(cyclingPower); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java index e9c741ba9..59a8a2499 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java @@ -10,7 +10,6 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerHeartRate implements SensorHandlerInterface { @@ -44,9 +43,9 @@ public class BluetoothHandlerHeartRate implements SensorHandlerInterface { public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { HeartRate heartRate = parseHeartRate(characteristic); - if (heartRate != null) { - observer.onChange(new Raw<>(observer.getNow(), heartRate)); - } + if (heartRate == null) return; + + observer.onChange(heartRate); } @VisibleForTesting diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java index 3d9701b30..6e59ee920 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java @@ -12,7 +12,6 @@ import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInterface { @@ -36,7 +35,9 @@ public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInte @Override public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data data = parseRunningSpeedAndCadence(sensorName, characteristic); - observer.onChange(new Raw<>(observer.getNow(), data)); + if (data == null) return; + + observer.onChange(data); } @VisibleForTesting diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java index 9625832e7..ddfd49a30 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java @@ -10,7 +10,6 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.Temperature; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; public class BluetoothHandlerTemperature implements SensorHandlerInterface { @@ -34,7 +33,7 @@ public class BluetoothHandlerTemperature implements SensorHandlerInterface { Temperature value = parseEnvironmentalSensing(characteristic); if (value == null) return; - observer.onChange(new Raw<>(observer.getNow(), value)); + observer.onChange(value); } /** diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index eceb62dda..98c71542e 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -20,7 +20,6 @@ import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Position; import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS; -import de.dennisguse.opentracks.sensors.sensorData.Raw; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.PermissionRequester; @@ -32,6 +31,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER; + //TODO Refactor to just pass information via SensorManager. private TrackPointCreator trackPointCreator; private SensorManager observer; @@ -123,7 +123,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS @Override public void onLocationChanged(@NonNull Location location) { // Send each update to the status; please note that this TrackPoint is not stored. - Position position = Position.of(location, trackPointCreator.createNow()); + Position position = Position.of(location, observer.getNow()); gpsStatusManager.onNewTrackPoint(position); if (!position.hasValidLocation()) { @@ -136,7 +136,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS return; } - observer.onChange(new Raw<>(observer.getNow(), position)); + observer.onChange(position); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index da2d228fa..ad10f8da5 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -28,13 +28,13 @@ 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.SensorData; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.SystemUtils; +//TODO provide context and handler for different Managers (not passing via start(), but similar to getNow()). public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = SensorManager.class.getSimpleName(); @@ -145,7 +145,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } public Instant getNow() { - return observer.createNow(); + return observer.getNow(); } @VisibleForTesting @@ -225,53 +225,53 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } @Deprecated - public void onChange(Raw data) { + public void onChange(Record data) { update(data); observer.onChange(); } //TODO Refactor generic "fun" here: go explicit. - private void update(@NonNull Raw data) { - Object value = data.value(); + private void update(@NonNull Record value) { + Instant now = getNow(); if (value instanceof HeartRate) { - this.heartRate.add((Raw) data); + this.heartRate.add(now, (HeartRate) value); return; } if (value instanceof Temperature) { - this.temperature.add((Raw) data); + this.temperature.add(now, (Temperature) value); return; } if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { - this.cyclingCadence.add((Raw) data); + this.cyclingCadence.add(now, (BluetoothHandlerCyclingCadence.CrankData) value); return; } if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. - this.cyclingDistanceSpeed.add((Raw) data); + this.cyclingDistanceSpeed.add(now, (BluetoothHandlerCyclingDistanceSpeed.WheelData) value); return; } if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { - this.runningDistanceSpeedCadence.add((Raw) data); + this.runningDistanceSpeedCadence.add(now, (BluetoothHandlerRunningSpeedAndCadence.Data) value); return; } if (value instanceof BluetoothHandlerCyclingPower.Data) { - this.cyclingPower.add((Raw) data); + this.cyclingPower.add(now, (BluetoothHandlerCyclingPower.Data) value); return; } if (value instanceof AtmosphericPressure) { - this.barometer.add((Raw) data); + this.barometer.add(now, (AtmosphericPressure) value); return; } if (value instanceof Position) { - this.gps.add((Raw) data); + this.gps.add(now, (Position) value); return; } - throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName()); + throw new UnsupportedOperationException(value.getClass().getCanonicalName()); } public void remove(@NonNull Aggregator type) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index d81967b45..a4b5c8229 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -14,7 +14,6 @@ import java.util.concurrent.TimeUnit; import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.sensors.SensorManager; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; -import de.dennisguse.opentracks.sensors.sensorData.Raw; public class BarometerInternal implements Driver { @@ -34,7 +33,7 @@ public class BarometerInternal implements Driver { return; } - observer.onChange(new Raw<>(observer.getNow(), AtmosphericPressure.ofHPA(event.values[0]))); + observer.onChange(AtmosphericPressure.ofHPA(event.values[0])); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index 0b20aa1a9..d039c74e2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -29,9 +29,10 @@ public abstract class Aggregator { return sensorName != null ? sensorName : sensorAddress; } - public final void add(Raw current) { - computeValue(current); - previous = current; + public final void add(Instant now, Input current) { + Raw next = new Raw<>(now, current); + computeValue(next); + previous = next; } protected abstract void computeValue(Raw current); @@ -104,4 +105,10 @@ public abstract class Aggregator { public String toString() { return "sensorAddress=" + sensorAddress + " data=" + aggregatedValue; } + + protected record Raw( + @NonNull Instant time, + @NonNull T value + ) { + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Raw.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Raw.java deleted file mode 100644 index a946dca29..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Raw.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.dennisguse.opentracks.sensors.sensorData; - - -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; - -import java.time.Clock; -import java.time.Instant; - -public record Raw( - @NonNull Instant time, - @NonNull T value -) { - public Raw(@NonNull Clock clock, @NonNull T value) { - this(clock.instant(), value); - } - - @VisibleForTesting - public Raw(@NonNull String time, @NonNull T value) { - this(Instant.parse(time), value); - } -} diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java index 5105ed9f5..59ff7a970 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java @@ -73,7 +73,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } public synchronized TrackPoint createSegmentStartManual() { - return TrackPoint.createSegmentStartManualWithTime(createNow()); + return TrackPoint.createSegmentStartManualWithTime(getNow()); } public synchronized TrackPoint createSegmentEnd() { @@ -89,7 +89,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } public Pair createCurrentTrackPoint(@Nullable TrackPoint lastTrackPointUISpeed, @Nullable TrackPoint lastTrackPointUIAltitude, @Nullable TrackPoint lastStoredTrackPointWithLocation) { - Instant now = createNow(); + Instant now = getNow(); SensorDataSet sensorDataSet = sensorManager.getSensorDataSet(now); Position position = sensorDataSet.position().data(); @@ -123,7 +123,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } private TrackPoint createTrackPoint(TrackPoint.Type type) { - Instant now = createNow(); + Instant now = getNow(); SensorDataSet sensorDataSet = sensorManager.getSensorDataSet(now); @@ -146,7 +146,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh ); } - public Instant createNow() { + public Instant getNow() { return Instant.now(clock); } From 289e93eb5d3a2f923c42340e04175192660bc37a Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 27 Jan 2026 18:46:21 +0100 Subject: [PATCH 06/30] Cleanup: moved AggregatorGPS to GPSManager. --- .../opentracks/sensors/GpsManager.java | 21 +++++++++++++--- .../opentracks/sensors/SensorManager.java | 24 +++++++++---------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index 98c71542e..463945460 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -43,6 +43,8 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS private Duration gpsInterval; private Distance thresholdHorizontalAccuracy; + private AggregatorGPS aggregatorGPS; + public GpsManager(TrackPointCreator trackPointCreator, SensorManager observer) { this.trackPointCreator = trackPointCreator; this.observer = observer; @@ -57,7 +59,7 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS gpsStatusManager = new GpsStatusManager(context, this, handler); locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - observer.onConnect(new AggregatorGPS("internal")); + this.aggregatorGPS = new AggregatorGPS("internal"); registerLocationListener(); gpsStatusManager.start(); @@ -79,12 +81,24 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS gpsStatusManager.stop(); gpsStatusManager = null; - observer.onDisconnect(new AggregatorGPS("internal")); + this.aggregatorGPS = null; observer = null; trackPointCreator = null; } + //TODO Exposed for refactoring. Is this necessary? + @Deprecated + AggregatorGPS getAggregatorGPS() { + return aggregatorGPS; + } + + //TODO Exposed for refactoring. This is very ugly. + @Deprecated + void setAggregatorGPS() { + this.aggregatorGPS = null; + } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { boolean registerListener = false; @@ -136,7 +150,8 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS return; } - observer.onChange(position); + aggregatorGPS.add(observer.getNow(), position); + observer.onChange(); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index ad10f8da5..acb942147 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -101,7 +101,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingPower != null) cyclingPower.resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); if (barometer != null) barometer.resetAggregated(); - if (gps != null) gps.resetAggregated(); + if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); } public GpsManager getGpsManager() { @@ -169,8 +169,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public AggregatorBarometer barometer; - public AggregatorGPS gps; - @VisibleForTesting public SensorData getHeartRate(Instant now) { if (heartRate != null) { @@ -227,6 +225,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Deprecated public void onChange(Record data) { update(data); + onChange(); + } + + public void onChange() { observer.onChange(); } @@ -266,10 +268,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.barometer.add(now, (AtmosphericPressure) value); return; } - if (value instanceof Position) { - this.gps.add(now, (Position) value); - return; - } throw new UnsupportedOperationException(value.getClass().getCanonicalName()); } @@ -289,10 +287,16 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingPower = null; this.runningDistanceSpeedCadence = null; this.barometer = null; - this.gps = null; + + //TODO This is to ExportImportTest alive; refactor test. + if (this.gpsManager != null) { + this.gpsManager.setAggregatorGPS(); + } } public SensorDataSet getSensorDataSet(Instant now) { + AggregatorGPS gps = gpsManager.getAggregatorGPS(); + return new SensorDataSet( gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), getSpeed(now), @@ -337,10 +341,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange barometer = (AggregatorBarometer) sensorData; return; } - if (type instanceof AggregatorGPS) { - gps = (AggregatorGPS) sensorData; - return; - } throw new UnsupportedOperationException(type.getClass().getCanonicalName()); } From 476f3a517b19147fb5abea409438b44adf8945b5 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 27 Jan 2026 22:23:39 +0100 Subject: [PATCH 07/30] Cleanup: GainManager now processes AggregatorBarometer directly (instead of SensorManager). --- .../io/file/importer/ExportImportTest.java | 5 +- .../TrackRecordingServiceRecordingTest.java | 5 +- .../sensors/BluetoothConnectionManager.java | 5 +- .../BluetoothHandlerBarometricPressure.java | 3 +- .../BluetoothHandlerCyclingCadence.java | 3 +- .../BluetoothHandlerCyclingDistanceSpeed.java | 3 +- .../sensors/BluetoothHandlerCyclingPower.java | 3 +- .../sensors/BluetoothHandlerHeartRate.java | 3 +- ...luetoothHandlerRunningSpeedAndCadence.java | 3 +- .../sensors/BluetoothHandlerTemperature.java | 3 +- .../sensors/BluetoothRemoteSensorManager.java | 4 +- .../opentracks/sensors/GainManager.java | 59 +++++++++++++++---- .../opentracks/sensors/SensorManager.java | 23 +++----- .../sensors/driver/BarometerInternal.java | 7 +-- .../opentracks/sensors/driver/Driver.java | 1 + .../sensors/driver/DriverObserver0.java | 19 ++++++ .../sensorData/SensorHandlerInterface.java | 4 +- 17 files changed, 104 insertions(+), 49 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index f35131938..518521de2 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -723,10 +723,9 @@ public class ExportImportTest { private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.reset(); if (altitudeGain == null) { - sensorManager.add(new AggregatorBarometer("test", null)); + sensorManager.getAltitudeSumManager().setAggregatorBarometer(new AggregatorBarometer("test", null)); return; } @@ -742,7 +741,7 @@ public class ExportImportTest { return true; } }; - sensorManager.add(aggregatorBarometer); + sensorManager.getAltitudeSumManager().setAggregatorBarometer(aggregatorBarometer); } private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 3f98b55fa..3676d539b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -810,7 +810,6 @@ public class TrackRecordingServiceRecordingTest { SensorManager sensorManager = trackPointCreator.getSensorManager(); sensorManager.add(new AggregatorRunning("", "")); - sensorManager.barometer = null; // when String sensor1 = "2020-02-02T02:02:03Z"; @@ -965,7 +964,7 @@ public class TrackRecordingServiceRecordingTest { } private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { - trackPointCreator.getSensorManager().barometer = new AggregatorBarometer("", "") { + trackPointCreator.getSensorManager().getAltitudeSumManager().setAggregatorBarometer(new AggregatorBarometer("", "") { @Override public boolean hasReceivedData() { return true; @@ -976,7 +975,7 @@ public class TrackRecordingServiceRecordingTest { public AltitudeGainLoss getAggregatedValue(Instant now) { return new AltitudeGainLoss(altitudeGain, altitudeGain); } - }; + }); } private static void sendGPSLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, long speed) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java index 9464d74fa..deeb24d82 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java @@ -35,6 +35,7 @@ import java.util.Optional; import java.util.UUID; import de.dennisguse.opentracks.sensors.driver.Driver; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; /** @@ -45,7 +46,7 @@ public class BluetoothConnectionManager implements Driver { private static final String TAG = BluetoothConnectionManager.class.getSimpleName(); - private final SensorManager observer; + private final DriverObserver0 observer; private final SensorHandlerInterface sensorHandler; @@ -131,7 +132,7 @@ public class BluetoothConnectionManager implements Driver { } }; - BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, SensorManager observer, SensorHandlerInterface sensorHandler) { + BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, DriverObserver0 observer, SensorHandlerInterface sensorHandler) { this.bluetoothAdapter = bluetoothAdapter; this.observer = observer; this.sensorHandler = sensorHandler; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java index 2ee719541..6ef0256a2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.AtmosphericPressure; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -28,7 +29,7 @@ public class BluetoothHandlerBarometricPressure implements SensorHandlerInterfac } @Override - public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { AtmosphericPressure value = parseEnvironmentalSensing(characteristic); if (value == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java index 9429bd8e9..383feded5 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java @@ -6,6 +6,7 @@ import android.util.Pair; import java.util.List; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -28,7 +29,7 @@ public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { if (serviceMeasurementUUID.equals(BluetoothHandlerCyclingPower.CYCLING_POWER)) { BluetoothHandlerCyclingPower.Data data = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); if (data != null && data.crank() != null) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java index d582545fb..3cb3742d9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java @@ -9,6 +9,7 @@ import androidx.annotation.VisibleForTesting; import java.util.List; import java.util.UUID; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -30,7 +31,7 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf } @Override - public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Pair data = parseCyclingCrankAndWheel(address, sensorName, characteristic); if (data == null) return; if (data.first == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java index 586ae3f12..42c22d3a2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.Power; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -30,7 +31,7 @@ public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data cyclingPower = parseCyclingPower(characteristic); if (cyclingPower == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java index 59a8a2499..a359fc145 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.HeartRate; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -40,7 +41,7 @@ public class BluetoothHandlerHeartRate implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { HeartRate heartRate = parseHeartRate(characteristic); if (heartRate == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java index 6e59ee920..827cb98af 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java @@ -11,6 +11,7 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -33,7 +34,7 @@ public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInte } @Override - public void handlePayload(SensorManager observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Data data = parseRunningSpeedAndCadence(sensorName, characteristic); if (data == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java index ddfd49a30..a5e4e6f06 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.Temperature; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; @@ -29,7 +30,7 @@ public class BluetoothHandlerTemperature implements SensorHandlerInterface { } @Override - public void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Temperature value = parseEnvironmentalSensing(characteristic); if (value == null) return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java index 9256aded6..2613c9de5 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.settings.PreferencesUtils; /** @@ -34,6 +35,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; * TODO: listen for Bluetooth enabled/disabled events. * @author Sandor Dornbush */ +//TODO Merge into SensorManager public class BluetoothRemoteSensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = BluetoothRemoteSensorManager.class.getSimpleName(); @@ -49,7 +51,7 @@ public class BluetoothRemoteSensorManager implements SharedPreferences.OnSharedP private final BluetoothConnectionManager cyclingPower; private final BluetoothConnectionManager runningSpeedAndCadence; - public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager observer) { + public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable DriverObserver0 observer) { this.context = context; this.handler = handler; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index 822158e92..d45f46109 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -5,20 +5,24 @@ import android.content.SharedPreferences; import android.os.Handler; import android.util.Log; +import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.sensors.driver.BarometerInternal; 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.AggregatorBarometer; import de.dennisguse.opentracks.settings.PreferencesUtils; /** * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer). */ -public class GainManager { +//TODO Rename class +public class GainManager implements DriverObserver0 { private static final String TAG = GainManager.class.getSimpleName(); - private final SensorManager listener; + private final SensorManager sensorManager; private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> connect(); @@ -26,8 +30,10 @@ public class GainManager { private Handler handler; private Driver driver; - public GainManager(SensorManager listener) { - this.listener = listener; + private AggregatorBarometer aggregatorBarometer; + + public GainManager(SensorManager sensorManager) { + this.sensorManager = sensorManager; } public void start(Context context, Handler handler) { @@ -42,24 +48,32 @@ public class GainManager { this.handler = null; PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - onDisconnect(); + disconnect(); + } + + @Deprecated + public AggregatorBarometer getAggregatorBarometer() { + return aggregatorBarometer; + } + + @Deprecated + public void setAggregatorBarometer(AggregatorBarometer aggregatorBarometer) { + this.aggregatorBarometer = aggregatorBarometer; } private void connect() { - onDisconnect(); + disconnect(); String address = PreferencesUtils.getBarometerSensorAddress(); switch (PreferencesUtils.getSensorType(address)) { case NONE -> { - driver = null; - listener.onRemove(new AggregatorBarometer(null, null)); return; } - case INTERNAL -> driver = new BarometerInternal(listener); + case INTERNAL -> driver = new BarometerInternal(this); case REMOTE -> driver = new BluetoothConnectionManager( BluetoothUtils.getAdapter(context), - listener, + this, new BluetoothHandlerBarometricPressure() ); default -> throw new RuntimeException("Not implemented"); @@ -68,10 +82,31 @@ public class GainManager { driver.connect(context, handler, address); } - private void onDisconnect() { + private void disconnect() { if (driver == null) return; driver.disconnect(); - listener.onDisconnect(new AggregatorBarometer("GainManager", null)); + driver = null; + } + + @Override + public void onRemove(Aggregator emptySensorData) { + this.aggregatorBarometer = null; + } + + @Override + public void onConnect(Aggregator emptySensorData) { + //TODO Aggregator should be created here. + this.aggregatorBarometer = (AggregatorBarometer) emptySensorData; + } + + @Override + public void onDisconnect(Aggregator emptySensorData) { + this.aggregatorBarometer.resetAggregated(); + } + + @Override + public void onChange(Record first) { + this.aggregatorBarometer.add(sensorManager.getNow(), (AtmosphericPressure) first); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index acb942147..5367986e4 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -12,13 +12,13 @@ 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.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; @@ -35,7 +35,8 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.SystemUtils; //TODO provide context and handler for different Managers (not passing via start(), but similar to getNow()). -public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { +//TODO Remove DriverObserver from SensorManager +public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener, DriverObserver0 { private static final String TAG = SensorManager.class.getSimpleName(); @@ -100,7 +101,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); if (cyclingPower != null) cyclingPower.resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); - if (barometer != null) barometer.resetAggregated(); + if (altitudeSumManager.getAggregatorBarometer() != null) altitudeSumManager.getAggregatorBarometer().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); } @@ -166,9 +167,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public AggregatorRunning runningDistanceSpeedCadence; - @VisibleForTesting - public AggregatorBarometer barometer; - @VisibleForTesting public SensorData getHeartRate(Instant now) { if (heartRate != null) { @@ -264,10 +262,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingPower.add(now, (BluetoothHandlerCyclingPower.Data) value); return; } - if (value instanceof AtmosphericPressure) { - this.barometer.add(now, (AtmosphericPressure) value); - return; - } throw new UnsupportedOperationException(value.getClass().getCanonicalName()); } @@ -286,9 +280,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingDistanceSpeed = null; this.cyclingPower = null; this.runningDistanceSpeedCadence = null; - this.barometer = null; //TODO This is to ExportImportTest alive; refactor test. + if (this.altitudeSumManager != null) { + this.altitudeSumManager.setAggregatorBarometer(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -296,6 +292,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public SensorDataSet getSensorDataSet(Instant now) { AggregatorGPS gps = gpsManager.getAggregatorGPS(); + AggregatorBarometer barometer = altitudeSumManager.getAggregatorBarometer(); return new SensorDataSet( gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), @@ -337,10 +334,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange runningDistanceSpeedCadence = (AggregatorRunning) sensorData; return; } - if (type instanceof AggregatorBarometer) { - barometer = (AggregatorBarometer) sensorData; - return; - } throw new UnsupportedOperationException(type.getClass().getCanonicalName()); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index a4b5c8229..18fdde2af 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -12,7 +12,6 @@ import androidx.annotation.NonNull; import java.util.concurrent.TimeUnit; import de.dennisguse.opentracks.data.models.AtmosphericPressure; -import de.dennisguse.opentracks.sensors.SensorManager; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; public class BarometerInternal implements Driver { @@ -21,7 +20,7 @@ public class BarometerInternal implements Driver { private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5); - private final SensorManager observer; + private final DriverObserver0 observer; private Context context; @@ -42,9 +41,8 @@ public class BarometerInternal implements Driver { } }; - public BarometerInternal(@NonNull SensorManager observer) { + public BarometerInternal(@NonNull DriverObserver0 observer) { this.observer = observer; - } @Override @@ -66,6 +64,7 @@ public class BarometerInternal implements Driver { disconnect(); } + @Override public boolean isConnected() { return context != null; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java index 98157de60..6aac465b5 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java @@ -6,6 +6,7 @@ import android.os.Handler; public interface Driver { void connect(Context context, Handler handler, String address); + //TODO Remove from interface? boolean isConnected(); void disconnect(); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java new file mode 100644 index 000000000..f12b4700e --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java @@ -0,0 +1,19 @@ +package de.dennisguse.opentracks.sensors.driver; + +import de.dennisguse.opentracks.sensors.sensorData.Aggregator; + +//TODO Make onChange parametrized +public interface DriverObserver0 { + + //TODO Pass SensorName as parameter only + void onConnect(Aggregator emptySensorData); + + //TODO Remove parameter + void onDisconnect(Aggregator emptySensorData); + + //TODO Remove parameter + void onRemove(Aggregator emptySensorData); + + void onChange(Record value); + +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java index d9a162eee..de5a9ac2a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java @@ -4,8 +4,8 @@ import android.bluetooth.BluetoothGattCharacteristic; import java.util.List; -import de.dennisguse.opentracks.sensors.SensorManager; import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; +import de.dennisguse.opentracks.sensors.driver.DriverObserver0; public interface SensorHandlerInterface { @@ -13,5 +13,5 @@ public interface SensorHandlerInterface { Aggregator createEmptySensorData(String address, String name); - void handlePayload(SensorManager observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); + void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); } From 244ca26210b8bbef71e86cf4eb820a7b90619a8e Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 27 Jan 2026 22:42:07 +0100 Subject: [PATCH 08/30] Cleanup: created new DriverObserver interface. --- .../opentracks/sensors/GainManager.java | 46 +++++++++++++------ .../sensors/driver/BarometerInternal.java | 9 ++-- .../sensors/driver/DriverObserver.java | 12 +++++ .../sensors/driver/DriverObserver0.java | 2 +- 4 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index d45f46109..1f4e0e880 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -8,6 +8,7 @@ import android.util.Log; import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.sensors.driver.BarometerInternal; import de.dennisguse.opentracks.sensors.driver.Driver; +import de.dennisguse.opentracks.sensors.driver.DriverObserver; import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; @@ -17,7 +18,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer). */ //TODO Rename class -public class GainManager implements DriverObserver0 { +public class GainManager implements DriverObserver { private static final String TAG = GainManager.class.getSimpleName(); @@ -73,7 +74,27 @@ public class GainManager implements DriverObserver0 { case REMOTE -> driver = new BluetoothConnectionManager( BluetoothUtils.getAdapter(context), - this, + new DriverObserver0() { + @Override + public void onConnect(Aggregator emptySensorData) { + GainManager.this.onConnect(); + } + + @Override + public void onDisconnect(Aggregator emptySensorData) { + GainManager.this.onDisconnect(); + } + + @Override + public void onRemove(Aggregator emptySensorData) { + GainManager.this.onRemove(); + } + + @Override + public void onChange(Record value) { + onData((AtmosphericPressure) value); + } + }, new BluetoothHandlerBarometricPressure() ); default -> throw new RuntimeException("Not implemented"); @@ -90,23 +111,22 @@ public class GainManager implements DriverObserver0 { } @Override - public void onRemove(Aggregator emptySensorData) { - this.aggregatorBarometer = null; + public void onConnect() { + this.aggregatorBarometer = new AggregatorBarometer("", null); } @Override - public void onConnect(Aggregator emptySensorData) { - //TODO Aggregator should be created here. - this.aggregatorBarometer = (AggregatorBarometer) emptySensorData; - } - - @Override - public void onDisconnect(Aggregator emptySensorData) { + public void onDisconnect() { this.aggregatorBarometer.resetAggregated(); } @Override - public void onChange(Record first) { - this.aggregatorBarometer.add(sensorManager.getNow(), (AtmosphericPressure) first); + public void onData(AtmosphericPressure value) { + this.aggregatorBarometer.add(sensorManager.getNow(), value); + } + + @Override + public void onRemove() { + this.aggregatorBarometer = null; } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index 18fdde2af..4da4e4fd6 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -12,7 +12,6 @@ import androidx.annotation.NonNull; import java.util.concurrent.TimeUnit; import de.dennisguse.opentracks.data.models.AtmosphericPressure; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; public class BarometerInternal implements Driver { @@ -20,7 +19,7 @@ public class BarometerInternal implements Driver { private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5); - private final DriverObserver0 observer; + private final DriverObserver observer; private Context context; @@ -32,7 +31,7 @@ public class BarometerInternal implements Driver { return; } - observer.onChange(AtmosphericPressure.ofHPA(event.values[0])); + observer.onData(AtmosphericPressure.ofHPA(event.values[0])); } @Override @@ -41,7 +40,7 @@ public class BarometerInternal implements Driver { } }; - public BarometerInternal(@NonNull DriverObserver0 observer) { + public BarometerInternal(@NonNull DriverObserver observer) { this.observer = observer; } @@ -57,7 +56,7 @@ public class BarometerInternal implements Driver { if (sensorManager.registerListener(sensorEventListener, pressureSensor, SAMPLING_PERIOD, handler)) { this.context = context; - observer.onConnect(new AggregatorBarometer("internal", null)); + observer.onConnect(); return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java new file mode 100644 index 000000000..ba066142b --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java @@ -0,0 +1,12 @@ +package de.dennisguse.opentracks.sensors.driver; + + +public interface DriverObserver { + void onConnect(); + + void onDisconnect(); + + void onData(T value); + + void onRemove(); +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java index f12b4700e..14d5f15c7 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java @@ -2,7 +2,7 @@ package de.dennisguse.opentracks.sensors.driver; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; -//TODO Make onChange parametrized +@Deprecated //Use DriverObserver public interface DriverObserver0 { //TODO Pass SensorName as parameter only From 719a052f34d4dd56b24242b49398b34a9837d6ca Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Wed, 28 Jan 2026 18:00:04 +0100 Subject: [PATCH 09/30] Cleanup: merged BluetoothRemoteSensorManager into SensorManager. Preparation for refactoring. --- .../sensors/BluetoothRemoteSensorManager.java | 126 ------------------ .../opentracks/sensors/SensorManager.java | 86 +++++++++++- 2 files changed, 79 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java deleted file mode 100644 index 2613c9de5..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package de.dennisguse.opentracks.sensors; - -import android.bluetooth.BluetoothAdapter; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Handler; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.settings.PreferencesUtils; - -/** - * Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors. - *

- * Note: should only be instantiated once. - * TODO: listen for Bluetooth enabled/disabled events. - * @author Sandor Dornbush - */ -//TODO Merge into SensorManager -public class BluetoothRemoteSensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String TAG = BluetoothRemoteSensorManager.class.getSimpleName(); - - private final Context context; - private final Handler handler; - private boolean started = false; - - private final BluetoothConnectionManager heartRate; - private final BluetoothConnectionManager temperature; - private final BluetoothConnectionManager cyclingCadence; - private final BluetoothConnectionManager cyclingSpeed; - private final BluetoothConnectionManager cyclingPower; - private final BluetoothConnectionManager runningSpeedAndCadence; - - public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable DriverObserver0 observer) { - this.context = context; - this.handler = handler; - - BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); - this.heartRate = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerHeartRate()); - this.temperature = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerTemperature()); - this.cyclingCadence = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerCyclingCadence()); - this.cyclingSpeed = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerCyclingDistanceSpeed()); - this.cyclingPower = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerCyclingPower()); - this.runningSpeedAndCadence = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerRunningSpeedAndCadence()); - } - - public void start() { - started = true; - - // Triggers connection startup - onSharedPreferenceChanged(null, null); - } - - public synchronized void stop() { - heartRate.disconnect(); - temperature.disconnect(); - cyclingCadence.disconnect(); - cyclingSpeed.disconnect(); - cyclingPower.disconnect(); - runningSpeedAndCadence.disconnect(); - - started = false; - } - - private synchronized void connect(BluetoothConnectionManager connectionManager, String address) { - connectionManager.connect(context, handler, address); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences unused, @Nullable String key) { - if (!started) return; - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) { - String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(); - connect(heartRate, address); - } - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_temperature_key, key)) { - String address = PreferencesUtils.getBluetoothTemperatureSensorAddress(); - connect(temperature, address); - } - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress(); - connect(cyclingCadence, address); - } - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress(); - - connect(cyclingSpeed, address); - } - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(); - - connect(cyclingPower, address); - } - - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) { - String address = PreferencesUtils.getBluetoothRunningSpeedAndCadenceAddress(); - - connect(runningSpeedAndCadence, address); - } - } -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 5367986e4..f8d2d4250 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -1,5 +1,6 @@ package de.dennisguse.opentracks.sensors; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; @@ -12,6 +13,7 @@ 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; @@ -40,11 +42,20 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private static final String TAG = SensorManager.class.getSimpleName(); + private Context context; + + private Handler handler; + private PowerManager.WakeLock wakeLock; private final TrackPointCreator observer; - private BluetoothRemoteSensorManager bluetoothSensorManager; + private BluetoothConnectionManager heartRateManager; + private BluetoothConnectionManager temperatureManager; + private BluetoothConnectionManager cyclingCadenceManager; + private BluetoothConnectionManager cyclingSpeedManager; + private BluetoothConnectionManager cyclingPowerManager; + private BluetoothConnectionManager runningSpeedAndCadenceManager; private GainManager altitudeSumManager; @@ -60,23 +71,45 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } wakeLock = SystemUtils.acquireWakeLock(context, wakeLock); + this.context = context; + this.handler = handler; gpsManager = new GpsManager(observer, this); altitudeSumManager = new GainManager(this); - bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, this); + BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); + this.heartRateManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); + this.temperatureManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerTemperature()); + this.cyclingCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingCadence()); + this.cyclingSpeedManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingDistanceSpeed()); + this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); + this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); altitudeSumManager.start(context, handler); - bluetoothSensorManager.start(); } public void stop() { wakeLock = SystemUtils.releaseWakeLock(wakeLock); - bluetoothSensorManager.stop(); - bluetoothSensorManager = null; + heartRateManager.disconnect(); + heartRateManager = null; + + temperatureManager.disconnect(); + temperatureManager = null; + + cyclingCadenceManager.disconnect(); + cyclingCadenceManager = null; + + cyclingSpeedManager.disconnect(); + cyclingSpeedManager = null; + + cyclingPowerManager.disconnect(); + cyclingPowerManager = null; + + runningSpeedAndCadenceManager.disconnect(); + runningSpeedAndCadenceManager = null; altitudeSumManager.stop(); altitudeSumManager = null; @@ -84,11 +117,14 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager.stop(); gpsManager = null; + context = null; + handler = null; + clear(); } public void reset() { - if (bluetoothSensorManager == null || altitudeSumManager == null) { + if (gpsManager == null || altitudeSumManager == null) { Log.d(TAG, "No recording running and no reset necessary."); return; } @@ -121,11 +157,47 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.altitudeSumManager = altitudeSumManager; } + private synchronized void connect(BluetoothConnectionManager connectionManager, String address) { + connectionManager.connect(context, handler, address); + } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { if (gpsManager != null) { gpsManager.onSharedPreferenceChanged(sharedPreferences, key); - bluetoothSensorManager.onSharedPreferenceChanged(sharedPreferences, key); + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) { + String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(); + connect(heartRateManager, address); + } + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_temperature_key, key)) { + String address = PreferencesUtils.getBluetoothTemperatureSensorAddress(); + connect(temperatureManager, address); + } + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) { + String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress(); + connect(cyclingCadenceManager, address); + } + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) { + String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress(); + + connect(cyclingSpeedManager, address); + } + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) { + String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(); + + connect(cyclingPowerManager, address); + } + + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) { + String address = PreferencesUtils.getBluetoothRunningSpeedAndCadenceAddress(); + + connect(runningSpeedAndCadenceManager, address); + } } } From 167d90332ebf66edab38fef66b7ab4b3aa00c0b1 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Wed, 28 Jan 2026 20:21:55 +0100 Subject: [PATCH 10/30] Extract Driver for internal GPS to GpsInternal. --- .../io/file/importer/ExportImportTest.java | 2 +- .../TrackRecordingServiceRecordingTest.java | 6 +- .../opentracks/sensors/GpsManager.java | 110 ++++++------------ .../sensors/driver/GpsInternal.java | 88 ++++++++++++++ .../opentracks/settings/PreferencesUtils.java | 1 + 5 files changed, 127 insertions(+), 80 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 518521de2..f0c455c67 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -756,6 +756,6 @@ public class ExportImportTest { mockAltitudeChange(trackPointCreator, altitudeGain); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location); + trackPointCreator.getSensorManager().getGpsManager().onData(location); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 3676d539b..d8a8e7686 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -6,11 +6,9 @@ import static org.junit.Assert.assertFalse; import android.content.Context; import android.content.Intent; import android.location.Location; -import android.location.LocationManager; import android.os.Looper; import androidx.annotation.NonNull; -import androidx.core.location.LocationManagerCompat; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; @@ -153,7 +151,7 @@ public class TrackRecordingServiceRecordingTest { Track.Id trackId = service.startNewTrack(); //We do not want the real GPS to interfere. - LocationManagerCompat.removeUpdates((LocationManager) context.getSystemService(Context.LOCATION_SERVICE), trackPointCreator.getSensorManager().getGpsManager()); + trackPointCreator.getSensorManager().getGpsManager().driver.disconnect(); String gps1 = "2020-02-02T02:02:03Z"; sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15); @@ -987,6 +985,6 @@ public class TrackRecordingServiceRecordingTest { location.setSpeed(speed); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location); + trackPointCreator.getSensorManager().getGpsManager().onData(location); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index 463945460..8106bae7c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -3,34 +3,26 @@ package de.dennisguse.opentracks.sensors; import android.content.Context; import android.content.SharedPreferences; import android.location.Location; -import android.location.LocationManager; -import android.os.Bundle; import android.os.Handler; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import androidx.core.location.LocationListenerCompat; -import androidx.core.location.LocationManagerCompat; -import androidx.core.location.LocationRequestCompat; - -import java.time.Duration; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.sensors.driver.DriverObserver; +import de.dennisguse.opentracks.sensors.driver.GpsInternal; import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; -import de.dennisguse.opentracks.util.PermissionRequester; @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) -public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { +public class GpsManager implements DriverObserver, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { private final String TAG = GpsManager.class.getSimpleName(); - private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER; - //TODO Refactor to just pass information via SensorManager. private TrackPointCreator trackPointCreator; @@ -38,9 +30,9 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS private Context context; private Handler handler; - private LocationManager locationManager; + @VisibleForTesting + public GpsInternal driver; private GpsStatusManager gpsStatusManager; - private Duration gpsInterval; private Distance thresholdHorizontalAccuracy; private AggregatorGPS aggregatorGPS; @@ -57,24 +49,20 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS onSharedPreferenceChanged(null, null); gpsStatusManager = new GpsStatusManager(context, this, handler); - locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); this.aggregatorGPS = new AggregatorGPS("internal"); - registerLocationListener(); + this.driver = new GpsInternal(this); + this.driver.connect(context, handler, "internal"); gpsStatusManager.start(); } - private boolean isStarted() { - return locationManager != null; - } - @SuppressWarnings({"MissingPermission"}) public void stop() { - if (isStarted()) { - LocationManagerCompat.removeUpdates(locationManager, this); + if (driver.isConnected()) { + driver.disconnect(); } - locationManager = null; + driver = null; this.context = null; handler = null; @@ -106,36 +94,48 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS if (PreferencesUtils.isKey(R.string.min_sampling_interval_key, key)) { registerListener = true; - gpsInterval = PreferencesUtils.getMinSamplingInterval(); - if (gpsStatusManager != null) { - gpsStatusManager.onMinSamplingIntervalChanged(gpsInterval); + gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval()); } } if (PreferencesUtils.isKey(R.string.recording_gps_accuracy_key, key)) { thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(); } if (PreferencesUtils.isKey(R.string.recording_distance_interval_key, key)) { - registerListener = true; - if (gpsStatusManager != null) { Distance gpsMinDistance = PreferencesUtils.getRecordingDistanceInterval(); gpsStatusManager.onRecordingDistanceChanged(gpsMinDistance); } } - if (registerListener && isStarted()) { - registerLocationListener(); + if (registerListener && driver != null && driver.isConnected()) { + driver.disconnect(); + driver.connect(context, handler, "internal"); } } - /** - * Checks if location is valid and builds a track point that will be send through TrackPointCreator. - * - * @param location {@link Location} object. - */ @Override - public void onLocationChanged(@NonNull Location location) { + public void onGpsStatusChanged(GpsStatusValue currentStatus) { + trackPointCreator.sendGpsStatus(currentStatus); + } + + @Override + public void onConnect() { + gpsStatusManager.onGpsEnabled(); + } + + @Override + public void onDisconnect() { + gpsStatusManager.onGpsDisabled(); + } + + @Override + public void onRemove() { + gpsStatusManager.onGpsDisabled(); + } + + @Override + public void onData(Location location) { // Send each update to the status; please note that this TrackPoint is not stored. Position position = Position.of(location, observer.getNow()); gpsStatusManager.onNewTrackPoint(position); @@ -153,44 +153,4 @@ public class GpsManager implements LocationListenerCompat, GpsStatusManager.GpsS aggregatorGPS.add(observer.getNow(), position); observer.onChange(); } - - @Override - public void onStatusChanged(@NonNull String provider, int status, Bundle extras) { - } - - @Override - public void onProviderEnabled(@NonNull String provider) { - gpsStatusManager.onGpsEnabled(); - } - - @Override - public void onProviderDisabled(@NonNull String provider) { - gpsStatusManager.onGpsDisabled(); - } - - private void registerLocationListener() { - if (!LocationManagerCompat.hasProvider(locationManager, LOCATION_PROVIDER)) { - Log.e(TAG, "Device doesn't have GPS."); - return; - } - - LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(gpsInterval.toMillis()) - .setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY) - .setMaxUpdateDelayMillis(0) - .build(); - - if (PermissionRequester.GPS.hasPermission(context)) { - try { - Log.i(TAG, "Register for location updates " + context); - LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, this); - } catch (SecurityException e) { - Log.e(TAG, "Could not register location listener; permissions not granted.", e); - } - } - } - - @Override - public void onGpsStatusChanged(GpsStatusValue currentStatus) { - trackPointCreator.sendGpsStatus(currentStatus); - } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java new file mode 100644 index 000000000..216c9a562 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java @@ -0,0 +1,88 @@ +package de.dennisguse.opentracks.sensors.driver; + +import android.content.Context; +import android.location.Location; +import android.location.LocationManager; +import android.os.Handler; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.location.LocationListenerCompat; +import androidx.core.location.LocationManagerCompat; +import androidx.core.location.LocationRequestCompat; + +import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.util.PermissionRequester; + +public class GpsInternal implements Driver { + + private static final String TAG = GpsInternal.class.getSimpleName(); + + private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER; + + private final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() { + @Override + public void onLocationChanged(@NonNull Location location) { + driverObserver.onData(location); + } + + @Override + public void onProviderEnabled(@NonNull String provider) { + driverObserver.onConnect(); + } + + @Override + public void onProviderDisabled(@NonNull String provider) { + driverObserver.onDisconnect(); + } + }; + + private final DriverObserver driverObserver; + + private LocationManager locationManager; + + public GpsInternal(DriverObserver driverObserver) { + this.driverObserver = driverObserver; + } + + @Override + public void connect(Context context, Handler handler, String address) { + locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + + if (!LocationManagerCompat.hasProvider(locationManager, LOCATION_PROVIDER)) { + Log.e(TAG, "Device doesn't have GPS."); + return; + } + + LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(PreferencesUtils.getMinSamplingInterval().toMillis()) + .setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY) + .setMaxUpdateDelayMillis(0) + .build(); + + if (PermissionRequester.GPS.hasPermission(context)) { + try { + Log.i(TAG, "Register for location updates " + context); + LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat); + } catch (SecurityException e) { + Log.e(TAG, "Could not register location listener; permissions not granted.", e); + } + } + } + + @SuppressWarnings({"MissingPermission"}) + @Override + public void disconnect() { + if (!isConnected()) return; + + LocationManagerCompat.removeUpdates(locationManager, locationListenerCompat); + + locationManager = null; + driverObserver.onDisconnect(); + } + + + @Override + public boolean isConnected() { + return locationManager != null; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 2ed5d6ab9..3854035f7 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -579,6 +579,7 @@ public class PreferencesUtils { return entries; } + //TODO Rename to getGpsMinSamplingInterval public static Duration getMinSamplingInterval() { final Duration MIN_SAMPLING_INTERVAL = getMinSamplingIntervalDefault(); return Duration.ofSeconds(getInt(R.string.min_sampling_interval_key, (int) MIN_SAMPLING_INTERVAL.getSeconds())); From f8aa4565495f06d2fc88629533ff8b06fc470e40 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Thu, 29 Jan 2026 18:17:15 +0100 Subject: [PATCH 11/30] Extract SensorHandler from GainManager for re-use. --- .../io/file/importer/ExportImportTest.java | 4 +- .../TrackRecordingServiceRecordingTest.java | 2 +- .../opentracks/sensors/GainManager.java | 141 +++++------------- .../opentracks/sensors/SensorHandler.java | 126 ++++++++++++++++ .../opentracks/sensors/SensorManager.java | 9 +- .../opentracks/sensors/SensorType.java | 4 +- .../opentracks/sensors/driver/Driver.java | 2 + .../opentracks/settings/PreferencesUtils.java | 6 +- 8 files changed, 178 insertions(+), 116 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index f0c455c67..43bcbc68d 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -725,7 +725,7 @@ public class ExportImportTest { SensorManager sensorManager = trackPointCreator.getSensorManager(); if (altitudeGain == null) { - sensorManager.getAltitudeSumManager().setAggregatorBarometer(new AggregatorBarometer("test", null)); + sensorManager.getAltitudeSumManager().setAggregator(new AggregatorBarometer("test", null)); return; } @@ -741,7 +741,7 @@ public class ExportImportTest { return true; } }; - sensorManager.getAltitudeSumManager().setAggregatorBarometer(aggregatorBarometer); + sensorManager.getAltitudeSumManager().setAggregator(aggregatorBarometer); } private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index d8a8e7686..3eea9229e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -962,7 +962,7 @@ public class TrackRecordingServiceRecordingTest { } private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { - trackPointCreator.getSensorManager().getAltitudeSumManager().setAggregatorBarometer(new AggregatorBarometer("", "") { + trackPointCreator.getSensorManager().getAltitudeSumManager().setAggregator(new AggregatorBarometer("", "") { @Override public boolean hasReceivedData() { return true; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index 1f4e0e880..8aa136bc1 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -1,132 +1,69 @@ package de.dennisguse.opentracks.sensors; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Handler; -import android.util.Log; +import androidx.annotation.NonNull; +import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.sensors.driver.BarometerInternal; import de.dennisguse.opentracks.sensors.driver.Driver; -import de.dennisguse.opentracks.sensors.driver.DriverObserver; import de.dennisguse.opentracks.sensors.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; -import de.dennisguse.opentracks.settings.PreferencesUtils; /** * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer). */ //TODO Rename class -public class GainManager implements DriverObserver { - - private static final String TAG = GainManager.class.getSimpleName(); - - - private final SensorManager sensorManager; - - private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> connect(); - - private Context context; - private Handler handler; - private Driver driver; - - private AggregatorBarometer aggregatorBarometer; +public class GainManager extends SensorHandler { public GainManager(SensorManager sensorManager) { - this.sensorManager = sensorManager; - } - - public void start(Context context, Handler handler) { - this.context = context; - this.handler = handler; - PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - } - - public void stop() { - Log.d(TAG, "Stop"); - this.context = null; - this.handler = null; - PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - - disconnect(); - } - - @Deprecated - public AggregatorBarometer getAggregatorBarometer() { - return aggregatorBarometer; - } - - @Deprecated - public void setAggregatorBarometer(AggregatorBarometer aggregatorBarometer) { - this.aggregatorBarometer = aggregatorBarometer; - } - - private void connect() { - disconnect(); - - String address = PreferencesUtils.getBarometerSensorAddress(); - switch (PreferencesUtils.getSensorType(address)) { - case NONE -> { - return; - } - case INTERNAL -> driver = new BarometerInternal(this); - case REMOTE -> driver = - new BluetoothConnectionManager( - BluetoothUtils.getAdapter(context), - new DriverObserver0() { - @Override - public void onConnect(Aggregator emptySensorData) { - GainManager.this.onConnect(); - } - - @Override - public void onDisconnect(Aggregator emptySensorData) { - GainManager.this.onDisconnect(); - } - - @Override - public void onRemove(Aggregator emptySensorData) { - GainManager.this.onRemove(); - } - - @Override - public void onChange(Record value) { - onData((AtmosphericPressure) value); - } - }, - new BluetoothHandlerBarometricPressure() - ); - default -> throw new RuntimeException("Not implemented"); - } - - driver.connect(context, handler, address); - } - - private void disconnect() { - if (driver == null) return; - - driver.disconnect(); - driver = null; + super(sensorManager); } @Override - public void onConnect() { - this.aggregatorBarometer = new AggregatorBarometer("", null); + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_pressure_key; } + @NonNull @Override - public void onDisconnect() { - this.aggregatorBarometer.resetAggregated(); + protected Driver createDriverInternal() { + return new BarometerInternal(driverObserver); } + @NonNull @Override - public void onData(AtmosphericPressure value) { - this.aggregatorBarometer.add(sensorManager.getNow(), value); + 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((AtmosphericPressure) value); + } + }, + new BluetoothHandlerBarometricPressure() + ); } + @NonNull @Override - public void onRemove() { - this.aggregatorBarometer = null; + public Aggregator createAggregator() { + return new AggregatorBarometer("", null); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java new file mode 100644 index 000000000..32cbf1d7e --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -0,0 +1,126 @@ +package de.dennisguse.opentracks.sensors; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +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.settings.PreferencesUtils; + + +public abstract class SensorHandler { + + private final SensorManager sensorManager; + + private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> connect(); + + private Context context; + private Handler handler; + private Driver driver; + + private Aggregator aggregator; + + protected final DriverObserver driverObserver = new DriverObserver() { + @Override + public void onConnect() { + SensorHandler.this.aggregator = createAggregator(); + } + + @Override + public void onDisconnect() { + SensorHandler.this.aggregator.resetAggregated(); + } + + @Override + public void onData(T value) { + SensorHandler.this.aggregator.add(sensorManager.getNow(), value); + sensorManager.onChange(); + } + + @Override + public void onRemove() { + SensorHandler.this.aggregator = null; + } + }; + + + protected SensorHandler(SensorManager sensorManager) { + this.sensorManager = sensorManager; + } + + //TODO Do we really need start and stop? + void start(Context context, Handler handler) { + this.context = context; + this.handler = handler; + PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + void stop() { + this.context = null; + this.handler = null; + PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + + disconnect(); + } + + void connect() { + disconnect(); + + String address = PreferencesUtils.getString(getSensorPreferenceKey(), PreferencesUtils.getBluetoothSensorAddressNone()); + + switch (PreferencesUtils.getSensorType(address)) { + case NONE -> { + return; + } + case INTERNAL -> { + driver = createDriverInternal(); + } + case REMOTE -> { + driver = createDriverBluetooth(address); + } + default -> throw new UnsupportedOperationException(); + } + + driver.connect(context, handler, address); + } + + void disconnect() { + if (driver == null) return; + + driver.disconnect(); + driver = null; + } + + @NonNull + protected Driver createDriverInternal() { + throw new RuntimeException("Not implemented"); + } + + @NonNull + protected Driver createDriverBluetooth(String address) { + throw new RuntimeException("Not implemented"); + } + + @NonNull + protected abstract Aggregator createAggregator(); + + protected Context getContext() { + return context; + } + + //TODO Try to keep aggregator private. + Aggregator getAggregator() { + return aggregator; + } + + //TODO REMOVE + @VisibleForTesting + public void setAggregator(Aggregator aggregator) { + this.aggregator = aggregator; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index f8d2d4250..3e1f78276 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -84,10 +84,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); + altitudeSumManager.start(context, handler); + onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); - altitudeSumManager.start(context, handler); } public void stop() { @@ -137,7 +138,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); if (cyclingPower != null) cyclingPower.resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); - if (altitudeSumManager.getAggregatorBarometer() != null) altitudeSumManager.getAggregatorBarometer().resetAggregated(); + if (altitudeSumManager.getAggregator() != null) altitudeSumManager.getAggregator().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); } @@ -355,7 +356,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange //TODO This is to ExportImportTest alive; refactor test. if (this.altitudeSumManager != null) { - this.altitudeSumManager.setAggregatorBarometer(null); + this.altitudeSumManager.setAggregator(null); } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); @@ -364,7 +365,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public SensorDataSet getSensorDataSet(Instant now) { AggregatorGPS gps = gpsManager.getAggregatorGPS(); - AggregatorBarometer barometer = altitudeSumManager.getAggregatorBarometer(); + AggregatorBarometer barometer = (AggregatorBarometer) altitudeSumManager.getAggregator(); return new SensorDataSet( gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java index 9fefe5195..2a64246e2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java @@ -1,8 +1,8 @@ package de.dennisguse.opentracks.sensors; public enum SensorType { - NONE("NONE"), - INTERNAL("INTERNAL"), + NONE("NONE"), //TODO Use R.string.sensor_type_value_none + INTERNAL("INTERNAL"), //TODO Use R.string.sensor_type_value_none //NOTE: preferenceValue of REMOTE should not be used anywhere. REMOTE("*"); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java index 6aac465b5..bc5628393 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/Driver.java @@ -4,6 +4,8 @@ import android.content.Context; import android.os.Handler; public interface Driver { + + //TODO Address is optional for internal drivers. Move address to driver instantiation. void connect(Context context, Handler handler, String address); //TODO Remove from interface? diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 3854035f7..4e2175eb7 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -253,7 +253,7 @@ public class PreferencesUtils { return isReportSpeed(track.activityTypeLocalized()); } - private static String getBluetoothSensorAddressNone() { + public static String getBluetoothSensorAddressNone() { return SensorType.NONE.getPreferenceValue(); } @@ -264,10 +264,6 @@ public class PreferencesUtils { .orElse(SensorType.REMOTE); } - public static String getBarometerSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_pressure_key, getBluetoothSensorAddressNone()); - } - public static String getBluetoothHeartRateSensorAddress() { return getString(R.string.settings_sensor_bluetooth_heart_rate_key, getBluetoothSensorAddressNone()); } From e6e009ba1491ca3f8589fbb26242f8eeabdeaea1 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Thu, 29 Jan 2026 18:38:51 +0100 Subject: [PATCH 12/30] GainManager should only re-connect if sensor should be changed. --- .../de/dennisguse/opentracks/sensors/SensorHandler.java | 8 ++------ .../de/dennisguse/opentracks/sensors/SensorManager.java | 4 ++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index 32cbf1d7e..e4b93037c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -1,7 +1,6 @@ package de.dennisguse.opentracks.sensors; import android.content.Context; -import android.content.SharedPreferences; import android.os.Handler; import androidx.annotation.NonNull; @@ -17,8 +16,6 @@ public abstract class SensorHandler { private final SensorManager sensorManager; - private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> connect(); - private Context context; private Handler handler; private Driver driver; @@ -48,7 +45,6 @@ public abstract class SensorHandler { } }; - protected SensorHandler(SensorManager sensorManager) { this.sensorManager = sensorManager; } @@ -57,13 +53,11 @@ public abstract class SensorHandler { void start(Context context, Handler handler) { this.context = context; this.handler = handler; - PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); } void stop() { this.context = null; this.handler = null; - PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); disconnect(); } @@ -109,6 +103,8 @@ public abstract class SensorHandler { @NonNull protected abstract Aggregator createAggregator(); + protected abstract int getSensorPreferenceKey(); + protected Context getContext() { return context; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 3e1f78276..f7206fd74 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -167,6 +167,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (gpsManager != null) { gpsManager.onSharedPreferenceChanged(sharedPreferences, key); + if (PreferencesUtils.isKey(altitudeSumManager.getSensorPreferenceKey(), key)) { + altitudeSumManager.connect(); + } + if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) { String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(); connect(heartRateManager, address); From c6cb388ce42f4cb8839f650a808b12c8ef4bd6ab Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 09:09:33 +0100 Subject: [PATCH 13/30] Created HeartRateHandler. --- .../io/file/importer/ExportImportTest.java | 4 +- .../TrackRecordingServiceRecordingTest.java | 10 +++- .../opentracks/sensors/HeartRateHandler.java | 58 +++++++++++++++++++ .../opentracks/sensors/SensorManager.java | 49 ++++++++-------- 4 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 43bcbc68d..8b240c8bd 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -659,7 +659,7 @@ public class ExportImportTest { } } - private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain, float temperature) { + private static void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain, float temperature) { SensorManager sensorManager = trackPointCreator.getSensorManager(); AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); @@ -721,7 +721,7 @@ public class ExportImportTest { trackPointCreator.onChange(); } - private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { + private static void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { SensorManager sensorManager = trackPointCreator.getSensorManager(); if (altitudeGain == null) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 3eea9229e..67b1ac760 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -336,17 +336,21 @@ public class TrackRecordingServiceRecordingTest { mockAltitudeChange(trackPointCreator, 0); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.add(new AggregatorHeartRate("", "")); // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); + AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); + sensorManager.add(avgHeartRate); + //Should be ignored - sensorManager.onChange(HeartRate.of(5)); + avgHeartRate.add(trackPointCreator.getNow(), HeartRate.of(5)); + sensorManager.onChange(); String sensor3 = "2020-02-02T02:02:13Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChange(HeartRate.of(7)); + avgHeartRate.add(trackPointCreator.getNow(), HeartRate.of(7)); + sensorManager.onChange(); String stopTime = "2020-02-02T02:02:15Z"; trackPointCreator.setClock(stopTime); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java new file mode 100644 index 000000000..55df2dba6 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java @@ -0,0 +1,58 @@ +package de.dennisguse.opentracks.sensors; + +import androidx.annotation.NonNull; + +import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.data.models.HeartRate; +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.AggregatorHeartRate; + +public class HeartRateHandler extends SensorHandler { + + protected HeartRateHandler(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((HeartRate) value); + } + }, + new BluetoothHandlerHeartRate() + ); + } + + @NonNull + @Override + protected Aggregator createAggregator() { + return new AggregatorHeartRate("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_heart_rate_key; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index f7206fd74..a6620a10b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -50,7 +50,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private final TrackPointCreator observer; - private BluetoothConnectionManager heartRateManager; + private HeartRateHandler heartRateHandler; private BluetoothConnectionManager temperatureManager; private BluetoothConnectionManager cyclingCadenceManager; private BluetoothConnectionManager cyclingSpeedManager; @@ -77,7 +77,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager = new GpsManager(observer, this); altitudeSumManager = new GainManager(this); BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); - this.heartRateManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); + this.heartRateHandler = new HeartRateHandler(this); + + new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); this.temperatureManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerTemperature()); this.cyclingCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingCadence()); this.cyclingSpeedManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingDistanceSpeed()); @@ -85,7 +87,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); altitudeSumManager.start(context, handler); - + heartRateHandler.start(context, handler); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -94,8 +96,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public void stop() { wakeLock = SystemUtils.releaseWakeLock(wakeLock); - heartRateManager.disconnect(); - heartRateManager = null; + heartRateHandler.stop(); + heartRateHandler = null; temperatureManager.disconnect(); temperatureManager = null; @@ -132,7 +134,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange Log.i(TAG, "Resetting data"); - if (heartRate != null) heartRate.resetAggregated(); + if (heartRateHandler.getAggregator() != null) heartRateHandler.getAggregator().resetAggregated(); if (temperature != null) temperature.resetAggregated(); if (cyclingCadence != null) cyclingCadence.resetAggregated(); if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); @@ -171,9 +173,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange altitudeSumManager.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) { - String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(); - connect(heartRateManager, address); + if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) { + heartRateHandler.connect(); } if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_temperature_key, key)) { @@ -226,9 +227,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public AggregatorHeartRate heartRate; - @VisibleForTesting public AggregatorTemperature temperature; @@ -246,8 +244,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public SensorData getHeartRate(Instant now) { - if (heartRate != null) { - SensorData value = heartRate.getAggregatedValueWithSensorName(now); + if (heartRateHandler.getAggregator() != null) { + SensorData value = (SensorData) heartRateHandler.getAggregator().getAggregatedValueWithSensorName(now); + //TODO Move this check into HeartRateHandler if (value.data().isValid()) return value; } @@ -293,7 +292,14 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return null; } + //TODO Remove + @VisibleForTesting + @Deprecated public void add(@NonNull Aggregator data) { + if (data instanceof AggregatorHeartRate) { + heartRateHandler.setAggregator((AggregatorHeartRate) data); + return; + } set(data, data); } @@ -308,14 +314,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } //TODO Refactor generic "fun" here: go explicit. + @Deprecated private void update(@NonNull Record value) { Instant now = getNow(); - if (value instanceof HeartRate) { - this.heartRate.add(now, (HeartRate) value); - return; - } - if (value instanceof Temperature) { this.temperature.add(now, (Temperature) value); return; @@ -343,6 +345,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange throw new UnsupportedOperationException(value.getClass().getCanonicalName()); } + @Deprecated public void remove(@NonNull Aggregator type) { set(type, null); } @@ -351,7 +354,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.heartRate = null; this.temperature = null; this.cyclingCadence = null; this.cyclingDistanceSpeed = null; @@ -362,6 +364,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (this.altitudeSumManager != null) { this.altitudeSumManager.setAggregator(null); } + if (this.heartRateHandler != null) { + this.heartRateHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -387,10 +392,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange 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; From 0a9d4b207c6967b70f00d1b0f606222fd9fac87d Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 09:24:37 +0100 Subject: [PATCH 14/30] Created TemperatureHandler. --- .../opentracks/sensors/SensorManager.java | 40 ++++++------- .../sensors/TemperatureHandler.java | 58 +++++++++++++++++++ .../opentracks/settings/PreferencesUtils.java | 8 --- 3 files changed, 75 insertions(+), 31 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index a6620a10b..8e6d70d34 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -51,7 +51,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private final TrackPointCreator observer; private HeartRateHandler heartRateHandler; - private BluetoothConnectionManager temperatureManager; + private TemperatureHandler temperatureHandler; private BluetoothConnectionManager cyclingCadenceManager; private BluetoothConnectionManager cyclingSpeedManager; private BluetoothConnectionManager cyclingPowerManager; @@ -76,11 +76,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager = new GpsManager(observer, this); altitudeSumManager = new GainManager(this); - BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); this.heartRateHandler = new HeartRateHandler(this); + this.temperatureHandler = new TemperatureHandler(this); + BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); - this.temperatureManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerTemperature()); this.cyclingCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingCadence()); this.cyclingSpeedManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingDistanceSpeed()); this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); @@ -88,6 +88,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange altitudeSumManager.start(context, handler); heartRateHandler.start(context, handler); + temperatureHandler.start(context, handler); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -99,8 +100,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange heartRateHandler.stop(); heartRateHandler = null; - temperatureManager.disconnect(); - temperatureManager = null; + temperatureHandler.stop(); + temperatureHandler = null; cyclingCadenceManager.disconnect(); cyclingCadenceManager = null; @@ -135,7 +136,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange Log.i(TAG, "Resetting data"); if (heartRateHandler.getAggregator() != null) heartRateHandler.getAggregator().resetAggregated(); - if (temperature != null) temperature.resetAggregated(); + if (temperatureHandler.getAggregator() != null) temperatureHandler.getAggregator().resetAggregated(); if (cyclingCadence != null) cyclingCadence.resetAggregated(); if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); if (cyclingPower != null) cyclingPower.resetAggregated(); @@ -177,9 +178,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange heartRateHandler.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_temperature_key, key)) { - String address = PreferencesUtils.getBluetoothTemperatureSensorAddress(); - connect(temperatureManager, address); + if (PreferencesUtils.isKey(temperatureHandler.getSensorPreferenceKey(), key)) { + temperatureHandler.connect(); } if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) { @@ -227,9 +227,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public AggregatorTemperature temperature; - @VisibleForTesting public AggregatorCyclingCadence cyclingCadence; @@ -300,6 +297,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange heartRateHandler.setAggregator((AggregatorHeartRate) data); return; } + if (data instanceof AggregatorTemperature) { + temperatureHandler.setAggregator((AggregatorTemperature) data); + return; + } set(data, data); } @@ -318,11 +319,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void update(@NonNull Record value) { Instant now = getNow(); - if (value instanceof Temperature) { - this.temperature.add(now, (Temperature) value); - return; - } - if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { this.cyclingCadence.add(now, (BluetoothHandlerCyclingCadence.CrankData) value); return; @@ -354,7 +350,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.temperature = null; this.cyclingCadence = null; this.cyclingDistanceSpeed = null; this.cyclingPower = null; @@ -367,6 +362,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (this.heartRateHandler != null) { this.heartRateHandler.setAggregator(null); } + if (this.temperatureHandler != null) { + this.temperatureHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -381,7 +379,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange getSpeed(now), getDistance(now), getHeartRate(now), - temperature != null && temperature.hasReceivedData() ? temperature.getAggregatedValueWithSensorName(now) : null, + temperatureHandler.getAggregator() != null && temperatureHandler.getAggregator().hasReceivedData() ? (SensorData) temperatureHandler.getAggregator().getAggregatedValueWithSensorName(now) : null, getCadence(now), cyclingPower != null && cyclingPower.hasReceivedData() ? cyclingPower.getAggregatedValueWithSensorName(now) : null, barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null @@ -392,10 +390,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); - if (type instanceof AggregatorTemperature) { - temperature = (AggregatorTemperature) sensorData; - return; - } if (type instanceof AggregatorCyclingCadence) { cyclingCadence = (AggregatorCyclingCadence) sensorData; return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java new file mode 100644 index 000000000..8a1ddb3b0 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java @@ -0,0 +1,58 @@ +package de.dennisguse.opentracks.sensors; + +import androidx.annotation.NonNull; + +import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.data.models.Temperature; +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.AggregatorTemperature; + +public class TemperatureHandler extends SensorHandler { + + protected TemperatureHandler(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((Temperature) value); + } + }, + new BluetoothHandlerTemperature() + ); + } + + @NonNull + @Override + protected Aggregator createAggregator() { + return new AggregatorTemperature("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_temperature_key; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 4e2175eb7..89a18fa0a 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -264,14 +264,6 @@ public class PreferencesUtils { .orElse(SensorType.REMOTE); } - public static String getBluetoothHeartRateSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_heart_rate_key, getBluetoothSensorAddressNone()); - } - - public static String getBluetoothTemperatureSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_temperature_key, getBluetoothSensorAddressNone()); - } - public static String getBluetoothCyclingCadenceSensorAddress() { return getString(R.string.settings_sensor_bluetooth_cycling_cadence_key, getBluetoothSensorAddressNone()); } From 0dcb8010e2d79db6107e957b4d23dfad615913b4 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 09:41:19 +0100 Subject: [PATCH 15/30] Created CyclingCadenceHandler. --- .../sensors/CyclingCadenceHandler.java | 57 +++++++++++++++++++ .../opentracks/sensors/SensorManager.java | 39 ++++++------- .../opentracks/settings/PreferencesUtils.java | 4 -- 3 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java new file mode 100644 index 000000000..3f97b7edf --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.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.AggregatorCyclingCadence; + +public class CyclingCadenceHandler extends SensorHandler { + + protected CyclingCadenceHandler(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((BluetoothHandlerCyclingCadence.CrankData) value); + } + }, + new BluetoothHandlerCyclingCadence() + ); + } + + @NonNull + @Override + protected Aggregator createAggregator() { + return new AggregatorCyclingCadence("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_cycling_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 8e6d70d34..5fe6b0de2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -52,7 +52,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private HeartRateHandler heartRateHandler; private TemperatureHandler temperatureHandler; - private BluetoothConnectionManager cyclingCadenceManager; + private CyclingCadenceHandler cyclingCadenceHandler; private BluetoothConnectionManager cyclingSpeedManager; private BluetoothConnectionManager cyclingPowerManager; private BluetoothConnectionManager runningSpeedAndCadenceManager; @@ -78,10 +78,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange altitudeSumManager = new GainManager(this); this.heartRateHandler = new HeartRateHandler(this); this.temperatureHandler = new TemperatureHandler(this); + this.cyclingCadenceHandler = new CyclingCadenceHandler(this); BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); - this.cyclingCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingCadence()); this.cyclingSpeedManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingDistanceSpeed()); this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); @@ -89,6 +89,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange altitudeSumManager.start(context, handler); heartRateHandler.start(context, handler); temperatureHandler.start(context, handler); + cyclingCadenceHandler.start(context, handler); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -103,8 +104,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange temperatureHandler.stop(); temperatureHandler = null; - cyclingCadenceManager.disconnect(); - cyclingCadenceManager = null; + cyclingCadenceHandler.stop(); + cyclingCadenceHandler = null; cyclingSpeedManager.disconnect(); cyclingSpeedManager = null; @@ -137,7 +138,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (heartRateHandler.getAggregator() != null) heartRateHandler.getAggregator().resetAggregated(); if (temperatureHandler.getAggregator() != null) temperatureHandler.getAggregator().resetAggregated(); - if (cyclingCadence != null) cyclingCadence.resetAggregated(); + if (cyclingCadenceHandler.getAggregator() != null) cyclingCadenceHandler.getAggregator().resetAggregated(); if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); if (cyclingPower != null) cyclingPower.resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); @@ -182,9 +183,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange temperatureHandler.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress(); - connect(cyclingCadenceManager, address); + if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { + cyclingCadenceHandler.connect(); } if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) { @@ -227,9 +227,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public AggregatorCyclingCadence cyclingCadence; - @VisibleForTesting public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed; @@ -251,8 +248,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } private SensorData getCadence(Instant now) { - if (cyclingCadence != null) { - return cyclingCadence.getAggregatedValueWithSensorName(now); + if (cyclingCadenceHandler.getAggregator() != null) { + return (SensorData) cyclingCadenceHandler.getAggregator().getAggregatedValueWithSensorName(now); } if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).cadence() != null) { @@ -301,6 +298,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange temperatureHandler.setAggregator((AggregatorTemperature) data); return; } + if (data instanceof AggregatorCyclingCadence) { + cyclingCadenceHandler.setAggregator((AggregatorCyclingCadence) data); + return; + } set(data, data); } @@ -319,10 +320,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void update(@NonNull Record value) { Instant now = getNow(); - if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { - this.cyclingCadence.add(now, (BluetoothHandlerCyclingCadence.CrankData) value); - return; - } if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. this.cyclingDistanceSpeed.add(now, (BluetoothHandlerCyclingDistanceSpeed.WheelData) value); @@ -350,7 +347,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.cyclingCadence = null; this.cyclingDistanceSpeed = null; this.cyclingPower = null; this.runningDistanceSpeedCadence = null; @@ -365,6 +361,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (this.temperatureHandler != null) { this.temperatureHandler.setAggregator(null); } + if (this.cyclingCadenceHandler != null) { + this.cyclingCadenceHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -390,10 +389,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); - if (type instanceof AggregatorCyclingCadence) { - cyclingCadence = (AggregatorCyclingCadence) sensorData; - return; - } if (type instanceof AggregatorCyclingDistanceSpeed) { cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData; return; diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 89a18fa0a..f0746f188 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -264,10 +264,6 @@ public class PreferencesUtils { .orElse(SensorType.REMOTE); } - public static String getBluetoothCyclingCadenceSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_cycling_cadence_key, getBluetoothSensorAddressNone()); - } - public static String getBluetoothCyclingSpeedSensorAddress() { return getString(R.string.settings_sensor_bluetooth_cycling_speed_key, getBluetoothSensorAddressNone()); } From 4b7badbecc32a56d965cc0f4813be16eaa9ee8ce Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 11:15:43 +0100 Subject: [PATCH 16/30] Created CyclingDistanceSpeedHandler. --- .../sensors/CyclingDistanceSpeedHandler.java | 59 +++++++++++++++++++ .../opentracks/sensors/SensorManager.java | 47 ++++++--------- .../opentracks/settings/PreferencesUtils.java | 4 -- 3 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java new file mode 100644 index 000000000..c7bcb99bf --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java @@ -0,0 +1,59 @@ +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.AggregatorCyclingDistanceSpeed; +import de.dennisguse.opentracks.settings.PreferencesUtils; + +public class CyclingDistanceSpeedHandler extends SensorHandler { + + protected CyclingDistanceSpeedHandler(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) { + ((AggregatorCyclingDistanceSpeed) getAggregator()).setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes.); + driverObserver.onData((BluetoothHandlerCyclingDistanceSpeed.WheelData) value); + } + }, + new BluetoothHandlerCyclingDistanceSpeed() + ); + } + + @NonNull + @Override + protected AggregatorCyclingDistanceSpeed createAggregator() { + return new AggregatorCyclingDistanceSpeed("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_cycling_speed_key; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 5fe6b0de2..625281d29 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -53,7 +53,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private HeartRateHandler heartRateHandler; private TemperatureHandler temperatureHandler; private CyclingCadenceHandler cyclingCadenceHandler; - private BluetoothConnectionManager cyclingSpeedManager; + private CyclingDistanceSpeedHandler cyclingDistanceSpeedHandler; private BluetoothConnectionManager cyclingPowerManager; private BluetoothConnectionManager runningSpeedAndCadenceManager; @@ -79,10 +79,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.heartRateHandler = new HeartRateHandler(this); this.temperatureHandler = new TemperatureHandler(this); this.cyclingCadenceHandler = new CyclingCadenceHandler(this); + this.cyclingDistanceSpeedHandler = new CyclingDistanceSpeedHandler(this); BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); - new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerHeartRate()); - this.cyclingSpeedManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingDistanceSpeed()); this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); @@ -90,6 +89,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange heartRateHandler.start(context, handler); temperatureHandler.start(context, handler); cyclingCadenceHandler.start(context, handler); + cyclingDistanceSpeedHandler.start(context, handler); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -107,8 +107,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingCadenceHandler.stop(); cyclingCadenceHandler = null; - cyclingSpeedManager.disconnect(); - cyclingSpeedManager = null; + cyclingDistanceSpeedHandler.stop(); + cyclingDistanceSpeedHandler = null; cyclingPowerManager.disconnect(); cyclingPowerManager = null; @@ -139,7 +139,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (heartRateHandler.getAggregator() != null) heartRateHandler.getAggregator().resetAggregated(); if (temperatureHandler.getAggregator() != null) temperatureHandler.getAggregator().resetAggregated(); if (cyclingCadenceHandler.getAggregator() != null) cyclingCadenceHandler.getAggregator().resetAggregated(); - if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); + if (cyclingDistanceSpeedHandler.getAggregator() != null) cyclingDistanceSpeedHandler.getAggregator().resetAggregated(); if (cyclingPower != null) cyclingPower.resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); if (altitudeSumManager.getAggregator() != null) altitudeSumManager.getAggregator().resetAggregated(); @@ -187,10 +187,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingCadenceHandler.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress(); - - connect(cyclingSpeedManager, address); + if (PreferencesUtils.isKey(cyclingDistanceSpeedHandler.getSensorPreferenceKey(), key)) { + cyclingDistanceSpeedHandler.connect(); } if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) { @@ -227,9 +225,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed; - @VisibleForTesting public AggregatorCyclingPower cyclingPower; @@ -260,8 +255,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } private SensorData getDistance(Instant now) { - if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData()) { - return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeed.getSensorNameOrAddress()); + if (cyclingDistanceSpeedHandler.getAggregator() != null && cyclingDistanceSpeedHandler.getAggregator().hasReceivedData()) { + return new SensorData<>(((AggregatorCyclingDistanceSpeed)cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); } if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) { @@ -275,8 +270,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange //TOOD simplify? private SensorData getSpeed(Instant now) { - if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData() && cyclingDistanceSpeed.getAggregatedValue(now).speed() != null) { - return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).speed(), cyclingDistanceSpeed.getSensorNameOrAddress()); + 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()); } if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) { @@ -302,6 +297,10 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingCadenceHandler.setAggregator((AggregatorCyclingCadence) data); return; } + if (data instanceof AggregatorCyclingDistanceSpeed) { + cyclingDistanceSpeedHandler.setAggregator((AggregatorCyclingDistanceSpeed) data); + return; + } set(data, data); } @@ -319,12 +318,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Deprecated private void update(@NonNull Record value) { Instant now = getNow(); - - if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { - this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. - this.cyclingDistanceSpeed.add(now, (BluetoothHandlerCyclingDistanceSpeed.WheelData) value); - return; - } if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { this.runningDistanceSpeedCadence.add(now, (BluetoothHandlerRunningSpeedAndCadence.Data) value); @@ -347,7 +340,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.cyclingDistanceSpeed = null; this.cyclingPower = null; this.runningDistanceSpeedCadence = null; @@ -364,6 +356,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (this.cyclingCadenceHandler != null) { this.cyclingCadenceHandler.setAggregator(null); } + if (cyclingDistanceSpeedHandler != null) { + cyclingDistanceSpeedHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -389,10 +384,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); - if (type instanceof AggregatorCyclingDistanceSpeed) { - cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData; - return; - } if (type instanceof AggregatorCyclingPower) { cyclingPower = (AggregatorCyclingPower) sensorData; return; diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index f0746f188..68d0d2540 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -264,10 +264,6 @@ public class PreferencesUtils { .orElse(SensorType.REMOTE); } - public static String getBluetoothCyclingSpeedSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_cycling_speed_key, getBluetoothSensorAddressNone()); - } - public static Distance getWheelCircumference() { final int DEFAULT = Integer.parseInt(resources.getString(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_default)); return Distance.ofMM(getInt(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key, DEFAULT)); From 29d2e7c78c5bcf47844260a6e1562f1ce1a75f5a Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 17:32:05 +0100 Subject: [PATCH 17/30] Created CyclingPowerHandler. --- .../sensors/CyclingPowerHandler.java | 57 +++++++++++++++++++ .../opentracks/sensors/SensorManager.java | 48 +++++++--------- .../opentracks/settings/PreferencesUtils.java | 4 -- 3 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java new file mode 100644 index 000000000..a646333b0 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.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.AggregatorCyclingPower; + +public class CyclingPowerHandler extends SensorHandler { + + protected CyclingPowerHandler(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((BluetoothHandlerCyclingPower.Data) value); + } + }, + new BluetoothHandlerCyclingPower() + ); + } + + @NonNull + @Override + protected AggregatorCyclingPower createAggregator() { + return new AggregatorCyclingPower("", null); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_cycling_power_key; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 625281d29..3a83bbcd0 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -19,7 +19,6 @@ 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.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; @@ -54,7 +53,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private TemperatureHandler temperatureHandler; private CyclingCadenceHandler cyclingCadenceHandler; private CyclingDistanceSpeedHandler cyclingDistanceSpeedHandler; - private BluetoothConnectionManager cyclingPowerManager; + private CyclingPowerHandler cyclingPowerHandler; private BluetoothConnectionManager runningSpeedAndCadenceManager; private GainManager altitudeSumManager; @@ -80,9 +79,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.temperatureHandler = new TemperatureHandler(this); this.cyclingCadenceHandler = new CyclingCadenceHandler(this); this.cyclingDistanceSpeedHandler = new CyclingDistanceSpeedHandler(this); + this.cyclingPowerHandler = new CyclingPowerHandler(this); BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context); - this.cyclingPowerManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerCyclingPower()); this.runningSpeedAndCadenceManager = new BluetoothConnectionManager(bluetoothAdapter, this, new BluetoothHandlerRunningSpeedAndCadence()); altitudeSumManager.start(context, handler); @@ -90,6 +89,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange temperatureHandler.start(context, handler); cyclingCadenceHandler.start(context, handler); cyclingDistanceSpeedHandler.start(context, handler); + cyclingPowerHandler.start(context, handler); onSharedPreferenceChanged(null, null); gpsManager.start(context, handler); @@ -110,8 +110,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingDistanceSpeedHandler.stop(); cyclingDistanceSpeedHandler = null; - cyclingPowerManager.disconnect(); - cyclingPowerManager = null; + cyclingPowerHandler.stop(); + cyclingPowerHandler = null; runningSpeedAndCadenceManager.disconnect(); runningSpeedAndCadenceManager = null; @@ -140,7 +140,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (temperatureHandler.getAggregator() != null) temperatureHandler.getAggregator().resetAggregated(); if (cyclingCadenceHandler.getAggregator() != null) cyclingCadenceHandler.getAggregator().resetAggregated(); if (cyclingDistanceSpeedHandler.getAggregator() != null) cyclingDistanceSpeedHandler.getAggregator().resetAggregated(); - if (cyclingPower != null) cyclingPower.resetAggregated(); + if (cyclingPowerHandler.getAggregator() != null) cyclingPowerHandler.getAggregator().resetAggregated(); if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); if (altitudeSumManager.getAggregator() != null) altitudeSumManager.getAggregator().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); @@ -191,10 +191,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingDistanceSpeedHandler.connect(); } - if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) { - String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(); - - connect(cyclingPowerManager, address); + if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { + cyclingPowerHandler.connect(); } if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) { @@ -225,9 +223,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public AggregatorCyclingPower cyclingPower; - @VisibleForTesting public AggregatorRunning runningDistanceSpeedCadence; @@ -256,7 +251,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private SensorData getDistance(Instant now) { if (cyclingDistanceSpeedHandler.getAggregator() != null && cyclingDistanceSpeedHandler.getAggregator().hasReceivedData()) { - return new SensorData<>(((AggregatorCyclingDistanceSpeed)cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); + return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); } if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) { @@ -270,8 +265,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange //TOOD simplify? private SensorData 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()); + 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()); } if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) { @@ -301,6 +296,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingDistanceSpeedHandler.setAggregator((AggregatorCyclingDistanceSpeed) data); return; } + if (data instanceof AggregatorCyclingPower) { + cyclingPowerHandler.setAggregator((Aggregator) data); + return; + } + set(data, data); } @@ -323,10 +323,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return; } - if (value instanceof BluetoothHandlerCyclingPower.Data) { - this.cyclingPower.add(now, (BluetoothHandlerCyclingPower.Data) value); - return; - } throw new UnsupportedOperationException(value.getClass().getCanonicalName()); } @@ -340,7 +336,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); - this.cyclingPower = null; this.runningDistanceSpeedCadence = null; //TODO This is to ExportImportTest alive; refactor test. @@ -359,6 +354,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingDistanceSpeedHandler != null) { cyclingDistanceSpeedHandler.setAggregator(null); } + if (cyclingPowerHandler != null) { + cyclingPowerHandler.setAggregator(null); + } if (this.gpsManager != null) { this.gpsManager.setAggregatorGPS(); } @@ -373,9 +371,9 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange getSpeed(now), getDistance(now), getHeartRate(now), - temperatureHandler.getAggregator() != null && temperatureHandler.getAggregator().hasReceivedData() ? (SensorData) temperatureHandler.getAggregator().getAggregatedValueWithSensorName(now) : null, + temperatureHandler.getAggregator() != null && temperatureHandler.getAggregator().hasReceivedData() ? ((AggregatorTemperature) temperatureHandler.getAggregator()).getAggregatedValueWithSensorName(now) : null, getCadence(now), - cyclingPower != null && cyclingPower.hasReceivedData() ? cyclingPower.getAggregatedValueWithSensorName(now) : null, + cyclingPowerHandler.getAggregator() != null && cyclingPowerHandler.getAggregator().hasReceivedData() ? ((AggregatorCyclingPower) cyclingPowerHandler.getAggregator()).getAggregatedValueWithSensorName(now) : null, barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null ); } @@ -384,10 +382,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); - if (type instanceof AggregatorCyclingPower) { - cyclingPower = (AggregatorCyclingPower) sensorData; - return; - } if (type instanceof AggregatorRunning) { runningDistanceSpeedCadence = (AggregatorRunning) sensorData; return; diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 68d0d2540..258d91344 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 getBluetoothCyclingPowerSensorAddress() { - return getString(R.string.settings_sensor_bluetooth_cycling_power_key, getBluetoothSensorAddressNone()); - } - public static String getBluetoothRunningSpeedAndCadenceAddress() { return getString(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, getBluetoothSensorAddressNone()); } From ea27db13fac0cac7a3c2e477f3e00c6ce55a61bf Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Fri, 30 Jan 2026 20:46:08 +0100 Subject: [PATCH 18/30] 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); From 6d187fa66d6f56620136f9ad26a0eae4ad760583 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 31 Jan 2026 08:40:26 +0100 Subject: [PATCH 19/30] Cleanup: removed DriverObserver0 and moved sensor drivers to separate package. --- .../io/file/importer/ExportImportTest.java | 4 +- ...luetoothHandlerBarometricPressureTest.java | 6 +- .../BluetoothHandlerHeartRateTest.java | 10 ++-- .../CyclingDistanceSpeedBluetoothTest.java} | 16 +++--- .../CyclingPowerBluetoothTest.java} | 12 ++-- .../RunningSpeedAndCadenceBluetoothTest.java} | 8 +-- .../sensorData/SensorDataCyclingTest.java | 36 ++++++------ .../TrackRecordingServiceRecordingTest.java | 12 ++-- .../BluetoothHandlerCyclingCadence.java | 57 ------------------- .../sensors/BluetoothHandlerTemperature.java | 53 ----------------- .../sensors/CyclingCadenceHandler.java | 33 +++-------- .../sensors/CyclingDistanceSpeedHandler.java | 35 +++--------- .../sensors/CyclingPowerHandler.java | 32 ++--------- .../opentracks/sensors/GainManager.java | 29 ++-------- .../opentracks/sensors/HeartRateHandler.java | 29 ++-------- .../RunningSpeedCadenceDistanceHandler.java | 32 ++--------- .../opentracks/sensors/SensorHandler.java | 2 +- .../opentracks/sensors/SensorManager.java | 40 +++---------- .../sensors/TemperatureHandler.java | 29 ++-------- .../BarometerBluetooth.java} | 21 ++----- .../BluetoothDriver.java} | 52 ++++++++--------- .../driver/CyclingCadenceBluetooth.java | 49 ++++++++++++++++ .../CyclingDistanceSpeedBluetooth.java} | 30 ++++------ .../CyclingPowerBluetooth.java} | 32 ++++------- .../sensors/driver/DriverObserver0.java | 19 ------- .../HeartRateBluetooth.java} | 21 ++----- .../RunningSpeedAndCadenceBluetooth.java} | 20 ++----- .../sensors/{ => driver}/SensorType.java | 2 +- .../sensors/driver/TemperatureBluetooth.java | 42 ++++++++++++++ .../sensorData/AggregatorCyclingCadence.java | 6 +- .../AggregatorCyclingDistanceSpeed.java | 6 +- .../sensorData/AggregatorCyclingPower.java | 6 +- .../sensors/sensorData/AggregatorRunning.java | 6 +- .../sensorData/SensorHandlerInterface.java | 17 ------ .../opentracks/settings/PreferencesUtils.java | 2 +- .../BluetoothLeCyclingCadencePreference.java | 4 +- .../BluetoothLeCyclingPowerPreference.java | 4 +- .../BluetoothLeCyclingSpeedPreference.java | 4 +- .../BluetoothLeHeartRatePreference.java | 4 +- .../BluetoothLePressurePreference.java | 4 +- ...othLeRunningSpeedAndCadencePreference.java | 4 +- .../BluetoothLeSensorPreference.java | 2 +- .../BluetoothLeTemperaturePreference.java | 4 +- 43 files changed, 285 insertions(+), 551 deletions(-) rename src/androidTest/java/de/dennisguse/opentracks/sensors/{ => driver}/BluetoothHandlerBarometricPressureTest.java (69%) rename src/androidTest/java/de/dennisguse/opentracks/sensors/{ => driver}/BluetoothHandlerHeartRateTest.java (67%) rename src/androidTest/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerCyclingDistanceSpeedTest.java => driver/CyclingDistanceSpeedBluetoothTest.java} (57%) rename src/androidTest/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerCyclingPowerTest.java => driver/CyclingPowerBluetoothTest.java} (64%) rename src/androidTest/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerRunningSpeedAndCadenceTest.java => driver/RunningSpeedAndCadenceBluetoothTest.java} (67%) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerBarometricPressure.java => driver/BarometerBluetooth.java} (55%) rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothConnectionManager.java => driver/BluetoothDriver.java} (82%) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingCadenceBluetooth.java rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerCyclingDistanceSpeed.java => driver/CyclingDistanceSpeedBluetooth.java} (61%) rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerCyclingPower.java => driver/CyclingPowerBluetooth.java} (67%) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerHeartRate.java => driver/HeartRateBluetooth.java} (70%) rename src/main/java/de/dennisguse/opentracks/sensors/{BluetoothHandlerRunningSpeedAndCadence.java => driver/RunningSpeedAndCadenceBluetooth.java} (76%) rename src/main/java/de/dennisguse/opentracks/sensors/{ => driver}/SensorType.java (90%) create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/driver/TemperatureBluetooth.java delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 8b240c8bd..201fe3ddd 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -66,8 +66,8 @@ import de.dennisguse.opentracks.data.models.TrackBuilder; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.exporter.TrackExporter; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower; import de.dennisguse.opentracks.sensors.SensorManager; +import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; @@ -663,7 +663,7 @@ public class ExportImportTest { SensorManager sensorManager = trackPointCreator.getSensorManager(); AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); - cyclingPower.add(trackPointCreator.getNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null)); + cyclingPower.add(trackPointCreator.getNow(), new CyclingPowerBluetooth.Data(Power.of(power), null)); sensorManager.add(cyclingPower); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressureTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerBarometricPressureTest.java similarity index 69% rename from src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressureTest.java rename to src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerBarometricPressureTest.java index 1a4ae59c7..e75ef520b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressureTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerBarometricPressureTest.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import static org.junit.Assert.assertEquals; @@ -13,11 +13,11 @@ public class BluetoothHandlerBarometricPressureTest { @Test public void parseEnvironmentalSensing_Pa() { // given - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerBarometricPressure.BAROMETRIC_PRESSURE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BarometerBluetooth.BAROMETRIC_PRESSURE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{(byte) 0xB2, (byte) 0x48, (byte) 0x0F, (byte) 0x00}); // when - AtmosphericPressure pressure = BluetoothHandlerBarometricPressure.parseEnvironmentalSensing(characteristic); + AtmosphericPressure pressure = BarometerBluetooth.parseEnvironmentalSensing(characteristic); // then assertEquals(AtmosphericPressure.ofHPA(1001.65f), pressure); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRateTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerHeartRateTest.java similarity index 67% rename from src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRateTest.java rename to src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerHeartRateTest.java index 6cbfaa2d8..90f9b1301 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRateTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/BluetoothHandlerHeartRateTest.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import static org.junit.Assert.assertEquals; @@ -13,11 +13,11 @@ public class BluetoothHandlerHeartRateTest { @Test public void parseHeartRate_uint8() { // given - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerHeartRate.HEARTRATE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(HeartRateBluetooth.HEARTRATE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x02, 0x3C}); // when - HeartRate heartRate = BluetoothHandlerHeartRate.parseHeartRate(characteristic); + HeartRate heartRate = HeartRateBluetooth.parseHeartRate(characteristic); // then assertEquals(HeartRate.of(60), heartRate); @@ -26,11 +26,11 @@ public class BluetoothHandlerHeartRateTest { @Test public void parseHeartRate_uint16() { // given - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerHeartRate.HEARTRATE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(HeartRateBluetooth.HEARTRATE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x01, 0x01, 0x01}); // when - HeartRate heartRate = BluetoothHandlerHeartRate.parseHeartRate(characteristic); + HeartRate heartRate = HeartRateBluetooth.parseHeartRate(characteristic); // then assertEquals(HeartRate.of(257), heartRate); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeedTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetoothTest.java similarity index 57% rename from src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeedTest.java rename to src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetoothTest.java index 58bbbfacd..989757209 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeedTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetoothTest.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -8,14 +8,14 @@ import android.util.Pair; import org.junit.Test; -public class BluetoothHandlerCyclingDistanceSpeedTest { +public class CyclingDistanceSpeedBluetoothTest { @Test public void parseCyclingSpeedCadence_crankOnly() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x02, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99}); // when - Pair sensor = BluetoothHandlerCyclingDistanceSpeed.parseCyclingCrankAndWheel("address", "sensorName", characteristic); + Pair sensor = CyclingDistanceSpeedBluetooth.parseCyclingCrankAndWheel(characteristic); // then assertNull(sensor.first); @@ -24,11 +24,11 @@ public class BluetoothHandlerCyclingDistanceSpeedTest { @Test public void parseCyclingSpeedCadence_wheelOnly() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, 0, 1, 0x45, (byte) 0x99}); // when - Pair sensor = BluetoothHandlerCyclingDistanceSpeed.parseCyclingCrankAndWheel("address", "sensorName", characteristic); + Pair sensor = CyclingDistanceSpeedBluetooth.parseCyclingCrankAndWheel(characteristic); // then assertEquals(65535 + 16777216, sensor.first.wheelRevolutionsCount()); @@ -37,11 +37,11 @@ public class BluetoothHandlerCyclingDistanceSpeedTest { @Test public void parseCyclingSpeedCadence_crankWheel() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x03, (byte) 0xC8, 0x00, 0x00, 0x01, 0x06, (byte) 0x99, (byte) 0xE1, 0x00, 0x45, (byte) 0x99}); // when - Pair sensor = BluetoothHandlerCyclingDistanceSpeed.parseCyclingCrankAndWheel("address", "sensorName", characteristic); + Pair sensor = CyclingDistanceSpeedBluetooth.parseCyclingCrankAndWheel(characteristic); // then assertEquals(200 + 16777216, sensor.first.wheelRevolutionsCount()); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPowerTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetoothTest.java similarity index 64% rename from src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPowerTest.java rename to src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetoothTest.java index 494a1705e..9fa28f13c 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPowerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetoothTest.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import static org.junit.Assert.assertEquals; @@ -6,15 +6,15 @@ import android.bluetooth.BluetoothGattCharacteristic; import org.junit.Test; -public class BluetoothHandlerCyclingPowerTest { +public class CyclingPowerBluetoothTest { @Test public void parseCyclingPower_power() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CyclingPowerBluetooth.CYCLING_POWER.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0, 0, 40, 0}); // when - BluetoothHandlerCyclingPower.Data powerCadence = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); + CyclingPowerBluetooth.Data powerCadence = CyclingPowerBluetooth.parseCyclingPower(characteristic); // then assertEquals(40, powerCadence.power().getW(), 0.01); @@ -22,11 +22,11 @@ public class BluetoothHandlerCyclingPowerTest { @Test public void parseCyclingPower_power_with_cadence() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CyclingPowerBluetooth.CYCLING_POWER.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x2C, 0x00, 0x00, 0x00, (byte) 0x9F, 0x00, 0x0C, 0x00, (byte) 0xE5, 0x42}); // when - BluetoothHandlerCyclingPower.Data powerCadence = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); + CyclingPowerBluetooth.Data powerCadence = CyclingPowerBluetooth.parseCyclingPower(characteristic); // then assertEquals(0, powerCadence.power().getW(), 0.01); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadenceTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetoothTest.java similarity index 67% rename from src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadenceTest.java rename to src/androidTest/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetoothTest.java index 7ca2507e3..9442f4b80 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadenceTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetoothTest.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import static org.junit.Assert.assertEquals; @@ -10,15 +10,15 @@ import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; -public class BluetoothHandlerRunningSpeedAndCadenceTest { +public class RunningSpeedAndCadenceBluetoothTest { @Test public void parseRunningSpeedAndCadence_with_distance() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerRunningSpeedAndCadence.RUNNING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(RunningSpeedAndCadenceBluetooth.RUNNING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{2, 0, 5, 80, (byte) 0xFF, (byte) 0xFF, 0, 1}); // when - BluetoothHandlerRunningSpeedAndCadence.Data sensor = BluetoothHandlerRunningSpeedAndCadence.parseRunningSpeedAndCadence("sensorName", characteristic); + RunningSpeedAndCadenceBluetooth.Data sensor = RunningSpeedAndCadenceBluetooth.parseRunningSpeedAndCadence("sensorName", characteristic); // then assertEquals(Speed.of(5), sensor.speed()); diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java index 23d404b03..51b41cd15 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java @@ -13,9 +13,9 @@ import java.time.Instant; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.UintUtils; +import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth; +import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; @RunWith(AndroidJUnit4.class) public class SensorDataCyclingTest { @@ -25,8 +25,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 2048)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(2, 2048)); // then assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -37,8 +37,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 6184)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 8016)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, 6184)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(2, 8016)); // then assertEquals(33.53, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -49,8 +49,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 2048)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, 2048)); // then assertEquals(Cadence.of(0), current.getAggregatedValue(Instant.MIN)); @@ -62,8 +62,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(2, 1024)); // then assertFalse(current.hasReceivedData()); //TODO Cadence should be 0? @@ -74,8 +74,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(1, UintUtils.UINT16_MAX - 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(2, 0)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(1, UintUtils.UINT16_MAX - 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(2, 0)); // then assertEquals(60, current.getAggregatedValue(Instant.MIN).getRPM(), 0.01); @@ -87,8 +87,8 @@ public class SensorDataCyclingTest { AggregatorCyclingCadence current = new AggregatorCyclingCadence("", ""); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(UintUtils.UINT32_MAX - 1, 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingCadence.CrankData(0, 2048)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(UintUtils.UINT32_MAX - 1, 1024)); + current.add(Instant.MIN, new CyclingCadenceBluetooth.CrankData(0, 2048)); // then // TODO See #953 @@ -102,8 +102,8 @@ public class SensorDataCyclingTest { current.setWheelCircumference(Distance.ofMM(2150)); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(1, 6184)); - current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(2, 8016)); + current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(1, 6184)); + current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(2, 8016)); // then assertEquals(2.15, current.getAggregatedValue(Instant.MIN).distance().toM(), 0.01); @@ -117,8 +117,8 @@ public class SensorDataCyclingTest { current.setWheelCircumference(Distance.ofMM(2000)); // when - current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(UintUtils.UINT32_MAX - 1, 1024)); - current.add(Instant.MIN, new BluetoothHandlerCyclingDistanceSpeed.WheelData(0, 2048)); + current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(UintUtils.UINT32_MAX - 1, 1024)); + current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(0, 2048)); // then diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index b70073f66..ae74caa10 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -42,8 +42,8 @@ import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.io.file.importer.TrackPointAssert; -import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence; import de.dennisguse.opentracks.sensors.SensorManager; +import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; @@ -818,13 +818,13 @@ public class TrackRecordingServiceRecordingTest { String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); //Should be ignored - aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO)); + aggregatorRunning.add(trackPointCreator.getNow(), new RunningSpeedAndCadenceBluetooth.Data(Speed.of(5), Cadence.of(1), Distance.ZERO)); sensorManager.onChange(); // when String sensor2 = "2020-02-02T02:02:04Z"; trackPointCreator.setClock(sensor2); - aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2))); + aggregatorRunning.add(trackPointCreator.getNow(), new RunningSpeedAndCadenceBluetooth.Data(Speed.of(5), Cadence.of(2), Distance.of(2))); sensorManager.onChange(); // when @@ -834,14 +834,14 @@ public class TrackRecordingServiceRecordingTest { // when String sensor3 = "2020-02-02T02:02:06Z"; trackPointCreator.setClock(sensor3); - aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12))); + aggregatorRunning.add(trackPointCreator.getNow(), new RunningSpeedAndCadenceBluetooth.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 - aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14))); + aggregatorRunning.add(trackPointCreator.getNow(), new RunningSpeedAndCadenceBluetooth.Data(Speed.of(5), Cadence.of(4), Distance.of(14))); sensorManager.onChange(); // when @@ -852,7 +852,7 @@ public class TrackRecordingServiceRecordingTest { String sensor5 = "2020-02-02T02:02:10Z"; trackPointCreator.setClock(sensor5); //Should be ignored - aggregatorRunning.add(trackPointCreator.getNow(), new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16))); + aggregatorRunning.add(trackPointCreator.getNow(), new RunningSpeedAndCadenceBluetooth.Data(Speed.of(5), Cadence.of(5), Distance.of(16))); sensorManager.onChange(); // when diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java deleted file mode 100644 index 383feded5..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.dennisguse.opentracks.sensors; - -import android.bluetooth.BluetoothGattCharacteristic; -import android.util.Log; -import android.util.Pair; - -import java.util.List; - -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; - -public class BluetoothHandlerCyclingCadence implements SensorHandlerInterface { - private static final String TAG = BluetoothHandlerCyclingCadence.class.getSimpleName(); - - public static final List CYCLING_CADENCE = List.of( - BluetoothHandlerCyclingPower.CYCLING_POWER, - BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE - ); - - @Override - public List getServices() { - return CYCLING_CADENCE; - } - - @Override - public AggregatorCyclingCadence createEmptySensorData(String address, String name) { - return new AggregatorCyclingCadence(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - if (serviceMeasurementUUID.equals(BluetoothHandlerCyclingPower.CYCLING_POWER)) { - BluetoothHandlerCyclingPower.Data data = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic); - if (data != null && data.crank() != null) { - observer.onChange(data.crank()); - } - return; - } - - if (serviceMeasurementUUID.equals(BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE)) { - Pair data = BluetoothHandlerCyclingDistanceSpeed.parseCyclingCrankAndWheel(address, sensorName, characteristic); - - if (data != null && data.second != null) { - observer.onChange(data.second); - } - return; - } - - Log.e(TAG, "Don't know how to decode this payload."); - } - - public record CrankData( - long crankRevolutionsCount, // UINT32 - int crankRevolutionsTime // UINT16; 1/1024s - ) {} -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java deleted file mode 100644 index a5e4e6f06..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerTemperature.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.dennisguse.opentracks.sensors; - -import static de.dennisguse.opentracks.sensors.BluetoothHandlerBarometricPressure.ENVIRONMENTAL_SENSING_SERVICE; - -import android.bluetooth.BluetoothGattCharacteristic; - -import java.util.List; -import java.util.UUID; - -import de.dennisguse.opentracks.data.models.Temperature; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.Aggregator; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; - -public class BluetoothHandlerTemperature implements SensorHandlerInterface { - public static final ServiceMeasurementUUID TEMPERATURE = new ServiceMeasurementUUID( - ENVIRONMENTAL_SENSING_SERVICE, - new UUID(0x2A6E00001000L, 0x800000805f9b34fbL) - ); - - @Override - public List getServices() { - return List.of(TEMPERATURE); - } - - @Override - public Aggregator createEmptySensorData(String address, String name) { - return new AggregatorTemperature(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - Temperature value = parseEnvironmentalSensing(characteristic); - if (value == null) return; - - observer.onChange(value); - } - - /** - * Decoding: org.bluetooth.characteristic.temperature.xml - */ - public static Temperature parseEnvironmentalSensing(BluetoothGattCharacteristic characteristic) { - byte[] raw = characteristic.getValue(); - - if (raw.length < 2) { - return null; - } - - Integer pressure = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, 0); - return Temperature.ofCentiCelsius(pressure); - } -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java index 3f97b7edf..4fde2f997 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java @@ -3,12 +3,13 @@ package de.dennisguse.opentracks.sensors; import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; +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.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; -public class CyclingCadenceHandler extends SensorHandler { +public class CyclingCadenceHandler extends SensorHandler { protected CyclingCadenceHandler(SensorManager sensorManager) { super(sensorManager); @@ -17,36 +18,16 @@ public class CyclingCadenceHandler extends SensorHandler( 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((BluetoothHandlerCyclingCadence.CrankData) value); - } - }, - new BluetoothHandlerCyclingCadence() + driverObserver, + new CyclingCadenceBluetooth() ); } @NonNull @Override - protected Aggregator createAggregator() { + protected Aggregator createAggregator() { return new AggregatorCyclingCadence("", null); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java index c7bcb99bf..54d07c3b4 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java @@ -3,13 +3,12 @@ package de.dennisguse.opentracks.sensors; import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; +import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; 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.AggregatorCyclingDistanceSpeed; -import de.dennisguse.opentracks.settings.PreferencesUtils; -public class CyclingDistanceSpeedHandler extends SensorHandler { +public class CyclingDistanceSpeedHandler extends SensorHandler { protected CyclingDistanceSpeedHandler(SensorManager sensorManager) { super(sensorManager); @@ -18,31 +17,11 @@ public class CyclingDistanceSpeedHandler extends SensorHandler( 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) { - ((AggregatorCyclingDistanceSpeed) getAggregator()).setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes.); - driverObserver.onData((BluetoothHandlerCyclingDistanceSpeed.WheelData) value); - } - }, - new BluetoothHandlerCyclingDistanceSpeed() + driverObserver, + new CyclingDistanceSpeedBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java index a646333b0..65f43d2e4 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java @@ -3,12 +3,12 @@ package de.dennisguse.opentracks.sensors; import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; +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.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; -public class CyclingPowerHandler extends SensorHandler { +public class CyclingPowerHandler extends SensorHandler { protected CyclingPowerHandler(SensorManager sensorManager) { super(sensorManager); @@ -17,30 +17,10 @@ public class CyclingPowerHandler extends SensorHandler( 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((BluetoothHandlerCyclingPower.Data) value); - } - }, - new BluetoothHandlerCyclingPower() + driverObserver, + new CyclingPowerBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java index 8aa136bc1..64a67ff0c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java @@ -4,9 +4,10 @@ import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; 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.driver.DriverObserver0; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; @@ -34,30 +35,10 @@ public class GainManager extends SensorHandler { @NonNull @Override protected Driver createDriverBluetooth(String address) { - return new BluetoothConnectionManager( + return new BluetoothDriver<>( 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((AtmosphericPressure) value); - } - }, - new BluetoothHandlerBarometricPressure() + driverObserver, + new BarometerBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java index 55df2dba6..b4e911f24 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java @@ -4,8 +4,9 @@ import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; 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.DriverObserver0; +import de.dennisguse.opentracks.sensors.driver.HeartRateBluetooth; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; @@ -18,30 +19,10 @@ public class HeartRateHandler extends SensorHandler { @NonNull @Override protected Driver createDriverBluetooth(String address) { - return new BluetoothConnectionManager( + return new BluetoothDriver<>( 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((HeartRate) value); - } - }, - new BluetoothHandlerHeartRate() + driverObserver, + new HeartRateBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java index 98e7ca033..e2b2d6333 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java @@ -3,12 +3,12 @@ package de.dennisguse.opentracks.sensors; import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; 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.driver.RunningSpeedAndCadenceBluetooth; import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; -public class RunningSpeedCadenceDistanceHandler extends SensorHandler { +public class RunningSpeedCadenceDistanceHandler extends SensorHandler { protected RunningSpeedCadenceDistanceHandler(SensorManager sensorManager) { super(sensorManager); @@ -17,30 +17,10 @@ public class RunningSpeedCadenceDistanceHandler extends SensorHandler( 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() + driverObserver, + new RunningSpeedAndCadenceBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index e4b93037c..542f82126 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -22,7 +22,7 @@ public abstract class SensorHandler { private Aggregator aggregator; - protected final DriverObserver driverObserver = new DriverObserver() { + protected final DriverObserver driverObserver = new DriverObserver<>() { @Override public void onConnect() { SensorHandler.this.aggregator = createAggregator(); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 0adc79c2a..0bf27eec2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -17,7 +17,7 @@ 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.sensors.driver.DriverObserver0; +import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; @@ -34,8 +34,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.SystemUtils; //TODO provide context and handler for different Managers (not passing via start(), but similar to getNow()). -//TODO Remove DriverObserver from SensorManager -public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener, DriverObserver0 { +public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = SensorManager.class.getSimpleName(); @@ -122,8 +121,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange context = null; handler = null; - - clear(); } public void reset() { @@ -160,7 +157,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.altitudeSumManager = altitudeSumManager; } - private synchronized void connect(BluetoothConnectionManager connectionManager, String address) { + private synchronized void connect(BluetoothDriver connectionManager, String address) { connectionManager.connect(context, handler, address); } @@ -199,27 +196,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } } - //TODO Inlined from SensorDataAggregator; Aggregators will be moved into Drivers. - @Deprecated - public void onConnect(Aggregator aggregator) { - throw new UnsupportedOperationException(); - } - - @Deprecated - public void onDisconnect(Aggregator aggregator) { - throw new UnsupportedOperationException(); - } - - @Deprecated - public void onRemove(Aggregator aggregator) { - throw new UnsupportedOperationException(); - } - - @Override - public void onChange(Record value) { - throw new UnsupportedOperationException(); - } - public Instant getNow() { return observer.getNow(); } @@ -240,8 +216,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return ((AggregatorCyclingCadence) cyclingCadenceHandler.getAggregator()).getAggregatedValueWithSensorName(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()); + 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; @@ -253,7 +229,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } if (runningSpeedCadenceDistanceHandler.getAggregator() != null && runningSpeedCadenceDistanceHandler.getAggregator().hasReceivedData()) { - return new SensorData<>(((AggregatorRunning)runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).distance(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); + return new SensorData<>(((AggregatorRunning) runningSpeedCadenceDistanceHandler.getAggregator()).getAggregatedValue(now).distance(), runningSpeedCadenceDistanceHandler.getAggregator().getSensorNameOrAddress()); } @@ -267,8 +243,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).speed(), cyclingDistanceSpeedHandler.getAggregator().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()); + 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; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java index 8a1ddb3b0..5b990d72b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java @@ -4,8 +4,9 @@ import androidx.annotation.NonNull; import de.dennisguse.opentracks.R; 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.DriverObserver0; +import de.dennisguse.opentracks.sensors.driver.TemperatureBluetooth; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; @@ -18,30 +19,10 @@ public class TemperatureHandler extends SensorHandler { @NonNull @Override protected Driver createDriverBluetooth(String address) { - return new BluetoothConnectionManager( + return new BluetoothDriver<>( 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((Temperature) value); - } - }, - new BluetoothHandlerTemperature() + driverObserver, + new TemperatureBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerBluetooth.java similarity index 55% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerBluetooth.java index 6ef0256a2..cfb2186b9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerBarometricPressure.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerBluetooth.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.bluetooth.BluetoothGattCharacteristic; @@ -6,12 +6,9 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.AtmosphericPressure; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.Aggregator; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -public class BluetoothHandlerBarometricPressure implements SensorHandlerInterface { +public class BarometerBluetooth implements BluetoothDriver.BluetoothParser { static final UUID ENVIRONMENTAL_SENSING_SERVICE = new UUID(0x181A00001000L, 0x800000805f9b34fbL); public static final ServiceMeasurementUUID BAROMETRIC_PRESSURE = new ServiceMeasurementUUID( ENVIRONMENTAL_SENSING_SERVICE, @@ -24,16 +21,8 @@ public class BluetoothHandlerBarometricPressure implements SensorHandlerInterfac } @Override - public Aggregator createEmptySensorData(String address, String name) { - return new AggregatorBarometer(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - AtmosphericPressure value = parseEnvironmentalSensing(characteristic); - if (value == null) return; - - observer.onChange(value); + public AtmosphericPressure parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + return parseEnvironmentalSensing(characteristic); } /** diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java similarity index 82% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java index deeb24d82..811bdc769 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java @@ -14,7 +14,7 @@ * the License. */ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; @@ -31,24 +31,24 @@ import android.util.Log; import androidx.annotation.NonNull; +import java.util.List; import java.util.Optional; import java.util.UUID; -import de.dennisguse.opentracks.sensors.driver.Driver; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.BluetoothUtils; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; /** * Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications. */ @SuppressLint("MissingPermission") -public class BluetoothConnectionManager implements Driver { +public class BluetoothDriver implements Driver { - private static final String TAG = BluetoothConnectionManager.class.getSimpleName(); + private static final String TAG = BluetoothDriver.class.getSimpleName(); - private final DriverObserver0 observer; + private final DriverObserver observer; - private final SensorHandlerInterface sensorHandler; + private final BluetoothParser sensorHandler; private final BluetoothAdapter bluetoothAdapter; private BluetoothGatt bluetoothGatt; @@ -128,11 +128,15 @@ public class BluetoothConnectionManager implements Driver { return; } - sensorHandler.handlePayload(observer, serviceMeasurementUUID.get(), gatt.getDevice().getName(), gatt.getDevice().getAddress(), characteristic); + T value = sensorHandler.parsePayload(serviceMeasurementUUID.get(), gatt.getDevice().getName(), characteristic); + if (value == null) { + return; + } + observer.onData(value); } }; - BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, DriverObserver0 observer, SensorHandlerInterface sensorHandler) { + public BluetoothDriver(BluetoothAdapter bluetoothAdapter, DriverObserver observer, BluetoothParser sensorHandler) { this.bluetoothAdapter = bluetoothAdapter; this.observer = observer; this.sensorHandler = sensorHandler; @@ -145,26 +149,11 @@ public class BluetoothConnectionManager implements Driver { return; } - if (SensorType.NONE.getPreferenceValue().equals(address)) { - Log.w(TAG, "NONE: going to disconnect"); - if (isConnected()) { - disconnect(); - observer.onRemove(sensorHandler.createEmptySensorData(null, null)); - } - return; - } - if (isConnected()) { - Log.w(TAG, "Already connected; ignoring."); + Log.e(TAG, "Already connected; ignoring."); return; } - if (isSameBluetoothDevice(address)) { - return; - } else { - disconnect(); - } - BluetoothDevice device; try { device = bluetoothAdapter.getRemoteDevice(address); @@ -177,11 +166,11 @@ public class BluetoothConnectionManager implements Driver { bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler); - observer.onConnect(sensorHandler.createEmptySensorData(device.getAddress(), device.getName())); + observer.onConnect(); //TODO pass device.getAddress(), device.getName() } private synchronized void clearData() { - observer.onDisconnect(sensorHandler.createEmptySensorData(bluetoothGatt.getDevice().getAddress(), bluetoothGatt.getDevice().getName())); + observer.onDisconnect(); } @Override @@ -215,4 +204,11 @@ public class BluetoothConnectionManager implements Driver { public boolean isConnected() { return bluetoothGatt != null; } + + public interface BluetoothParser { + + List getServices(); + + T parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic); + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingCadenceBluetooth.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingCadenceBluetooth.java new file mode 100644 index 000000000..6177f131b --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingCadenceBluetooth.java @@ -0,0 +1,49 @@ +package de.dennisguse.opentracks.sensors.driver; + +import android.bluetooth.BluetoothGattCharacteristic; +import android.util.Log; +import android.util.Pair; + +import java.util.List; + +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; + +public class CyclingCadenceBluetooth implements BluetoothDriver.BluetoothParser { + private static final String TAG = CyclingCadenceBluetooth.class.getSimpleName(); + + public static final List CYCLING_CADENCE = List.of( + CyclingPowerBluetooth.CYCLING_POWER, + CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE + ); + + @Override + public List getServices() { + return CYCLING_CADENCE; + } + + @Override + public CrankData parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + if (serviceMeasurementUUID.equals(CyclingPowerBluetooth.CYCLING_POWER)) { + CyclingPowerBluetooth.Data data = CyclingPowerBluetooth.parseCyclingPower(characteristic); + if (data != null && data.crank() != null) { + return data.crank(); + } + } + + if (serviceMeasurementUUID.equals(CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE)) { + Pair data = CyclingDistanceSpeedBluetooth.parseCyclingCrankAndWheel(characteristic); + + if (data != null && data.second != null) { + return data.second; + } + } + + Log.e(TAG, "Don't know how to decode this payload."); + return null; + } + + public record CrankData( + long crankRevolutionsCount, // UINT32 + int crankRevolutionsTime // UINT16; 1/1024s + ) {} +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetooth.java similarity index 61% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetooth.java index 3cb3742d9..30959e422 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingDistanceSpeedBluetooth.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.bluetooth.BluetoothGattCharacteristic; import android.util.Pair; @@ -9,11 +9,9 @@ import androidx.annotation.VisibleForTesting; import java.util.List; import java.util.UUID; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterface { +public class CyclingDistanceSpeedBluetooth implements BluetoothDriver.BluetoothParser { public static final ServiceMeasurementUUID CYCLING_SPEED_CADENCE = new ServiceMeasurementUUID( new UUID(0x181600001000L, 0x800000805f9b34fbL), @@ -26,22 +24,18 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf } @Override - public AggregatorCyclingDistanceSpeed createEmptySensorData(String address, String name) { - return new AggregatorCyclingDistanceSpeed(address, name); - } + public WheelData parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + Pair data = parseCyclingCrankAndWheel(characteristic); + if (data != null && data.first != null) { + return data.first; + } - @Override - public void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - Pair data = parseCyclingCrankAndWheel(address, sensorName, characteristic); - if (data == null) return; - if (data.first == null) return; - - observer.onChange(data.first); + return null; } @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - public static Pair parseCyclingCrankAndWheel(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) { + public static Pair parseCyclingCrankAndWheel(@NonNull BluetoothGattCharacteristic characteristic) { // DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.csc_measurement.xml int valueLength = characteristic.getValue().length; if (valueLength == 0) { @@ -62,13 +56,13 @@ public class BluetoothHandlerCyclingDistanceSpeed implements SensorHandlerInterf index += 2; } - BluetoothHandlerCyclingCadence.CrankData crankData = null; + CyclingCadenceBluetooth.CrankData crankData = null; if (hasCrank && valueLength - index >= 4) { long crankCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); index += 2; int crankTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s - crankData = new BluetoothHandlerCyclingCadence.CrankData(crankCount, crankTime); + crankData = new CyclingCadenceBluetooth.CrankData(crankCount, crankTime); } return new Pair<>(wheelData, crankData); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetooth.java similarity index 67% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetooth.java index 42c22d3a2..15c70c069 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/CyclingPowerBluetooth.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.bluetooth.BluetoothGattCharacteristic; @@ -9,11 +9,9 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.Power; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { +public class CyclingPowerBluetooth implements BluetoothDriver.BluetoothParser { public static final ServiceMeasurementUUID CYCLING_POWER = new ServiceMeasurementUUID( new UUID(0x181800001000L, 0x800000805f9b34fbL), @@ -26,17 +24,8 @@ public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { } @Override - public AggregatorCyclingPower createEmptySensorData(String address, String name) { - return new AggregatorCyclingPower(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - Data cyclingPower = parseCyclingPower(characteristic); - - if (cyclingPower == null) return; - - observer.onChange(cyclingPower); + public CyclingPowerBluetooth.Data parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + return parseCyclingPower(characteristic); } @@ -69,19 +58,22 @@ public class BluetoothHandlerCyclingPower implements SensorHandlerInterface { index += 2 + 2; } - BluetoothHandlerCyclingCadence.CrankData crankData = null; + CyclingCadenceBluetooth.CrankData crankData = null; if (hasCrank && valueLength - index >= 4) { long crankCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); index += 2; int crankTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s - crankData = new BluetoothHandlerCyclingCadence.CrankData(crankCount, crankTime); + crankData = new CyclingCadenceBluetooth.CrankData(crankCount, crankTime); } return new Data(Power.of(instantaneousPower), crankData); } - public record Data(Power power, BluetoothHandlerCyclingCadence.CrankData crank) {} - + public record Data( + Power power, + CyclingCadenceBluetooth.CrankData crank + ) { + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java deleted file mode 100644 index 14d5f15c7..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver0.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.dennisguse.opentracks.sensors.driver; - -import de.dennisguse.opentracks.sensors.sensorData.Aggregator; - -@Deprecated //Use DriverObserver -public interface DriverObserver0 { - - //TODO Pass SensorName as parameter only - void onConnect(Aggregator emptySensorData); - - //TODO Remove parameter - void onDisconnect(Aggregator emptySensorData); - - //TODO Remove parameter - void onRemove(Aggregator emptySensorData); - - void onChange(Record value); - -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/HeartRateBluetooth.java similarity index 70% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/HeartRateBluetooth.java index a359fc145..15df1f19b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/HeartRateBluetooth.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.bluetooth.BluetoothGattCharacteristic; @@ -9,11 +9,9 @@ import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.HeartRate; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -public class BluetoothHandlerHeartRate implements SensorHandlerInterface { +public class HeartRateBluetooth implements BluetoothDriver.BluetoothParser { public static final ServiceMeasurementUUID HEARTRATE = new ServiceMeasurementUUID( new UUID(0x180D00001000L, 0x800000805f9b34fbL), @@ -36,17 +34,8 @@ public class BluetoothHandlerHeartRate implements SensorHandlerInterface { } @Override - public AggregatorHeartRate createEmptySensorData(String address, String name) { - return new AggregatorHeartRate(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - HeartRate heartRate = parseHeartRate(characteristic); - - if (heartRate == null) return; - - observer.onChange(heartRate); + public HeartRate parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + return parseHeartRate(characteristic); } @VisibleForTesting diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetooth.java similarity index 76% rename from src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetooth.java index 827cb98af..43460f2ec 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/RunningSpeedAndCadenceBluetooth.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; import android.bluetooth.BluetoothGattCharacteristic; @@ -11,11 +11,9 @@ import java.util.UUID; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; -import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning; -import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInterface { +public class RunningSpeedAndCadenceBluetooth implements BluetoothDriver.BluetoothParser { public static final ServiceMeasurementUUID RUNNING_SPEED_CADENCE = new ServiceMeasurementUUID( @@ -29,16 +27,8 @@ public class BluetoothHandlerRunningSpeedAndCadence implements SensorHandlerInte } @Override - public AggregatorRunning createEmptySensorData(String address, String name) { - return new AggregatorRunning(address, name); - } - - @Override - public void handlePayload(DriverObserver0 observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - Data data = parseRunningSpeedAndCadence(sensorName, characteristic); - if (data == null) return; - - observer.onChange(data); + public Data parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + return parseRunningSpeedAndCadence(sensorName, characteristic); } @VisibleForTesting diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/SensorType.java similarity index 90% rename from src/main/java/de/dennisguse/opentracks/sensors/SensorType.java rename to src/main/java/de/dennisguse/opentracks/sensors/driver/SensorType.java index 2a64246e2..f49575eea 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorType.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/SensorType.java @@ -1,4 +1,4 @@ -package de.dennisguse.opentracks.sensors; +package de.dennisguse.opentracks.sensors.driver; public enum SensorType { NONE("NONE"), //TODO Use R.string.sensor_type_value_none diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/TemperatureBluetooth.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/TemperatureBluetooth.java new file mode 100644 index 000000000..5f495848a --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/TemperatureBluetooth.java @@ -0,0 +1,42 @@ +package de.dennisguse.opentracks.sensors.driver; + +import static de.dennisguse.opentracks.sensors.driver.BarometerBluetooth.ENVIRONMENTAL_SENSING_SERVICE; + +import android.bluetooth.BluetoothGattCharacteristic; + +import java.util.List; +import java.util.UUID; + +import de.dennisguse.opentracks.data.models.Temperature; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; + +public class TemperatureBluetooth implements BluetoothDriver.BluetoothParser { + public static final ServiceMeasurementUUID TEMPERATURE = new ServiceMeasurementUUID( + ENVIRONMENTAL_SENSING_SERVICE, + new UUID(0x2A6E00001000L, 0x800000805f9b34fbL) + ); + + @Override + public List getServices() { + return List.of(TEMPERATURE); + } + + @Override + public Temperature parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, BluetoothGattCharacteristic characteristic) { + return parseEnvironmentalSensing(characteristic); + } + + /** + * Decoding: org.bluetooth.characteristic.temperature.xml + */ + public static Temperature parseEnvironmentalSensing(BluetoothGattCharacteristic characteristic) { + byte[] raw = characteristic.getValue(); + + if (raw.length < 2) { + return null; + } + + Integer pressure = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, 0); + return Temperature.ofCentiCelsius(pressure); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java index dfb4542f3..6f109d8e9 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java @@ -7,10 +7,10 @@ import androidx.annotation.NonNull; import java.time.Duration; import de.dennisguse.opentracks.data.models.Cadence; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence; import de.dennisguse.opentracks.sensors.UintUtils; +import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth; -public class AggregatorCyclingCadence extends Aggregator { +public class AggregatorCyclingCadence extends Aggregator { private final String TAG = AggregatorCyclingCadence.class.getSimpleName(); @@ -19,7 +19,7 @@ public class AggregatorCyclingCadence extends Aggregator current) { + protected void computeValue(Raw current) { if (previous == null) { return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingDistanceSpeed.java index 40c1baf47..4d1a273ca 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingDistanceSpeed.java @@ -8,10 +8,10 @@ import java.time.Duration; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.UintUtils; +import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; -public class AggregatorCyclingDistanceSpeed extends Aggregator { +public class AggregatorCyclingDistanceSpeed extends Aggregator { private final String TAG = AggregatorCyclingDistanceSpeed.class.getSimpleName(); @@ -22,7 +22,7 @@ public class AggregatorCyclingDistanceSpeed extends Aggregator current) { + protected void computeValue(Raw current) { if (previous == null) { return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingPower.java index c8050ec69..a369763a8 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingPower.java @@ -3,16 +3,16 @@ package de.dennisguse.opentracks.sensors.sensorData; import androidx.annotation.NonNull; import de.dennisguse.opentracks.data.models.Power; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower; +import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth; -public class AggregatorCyclingPower extends Aggregator { +public class AggregatorCyclingPower extends Aggregator { public AggregatorCyclingPower(String name, String address) { super(name, address); } @Override - public void computeValue(Raw current) { + public void computeValue(Raw current) { this.aggregatedValue = current.value().power(); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java index 2c415e59b..8cdf81b93 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java @@ -5,12 +5,12 @@ import androidx.annotation.NonNull; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; -import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence; +import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth; /** * Provides cadence in rpm and speed in milliseconds from Bluetooth LE Running Speed and Cadence sensors. */ -public final class AggregatorRunning extends Aggregator { +public final class AggregatorRunning extends Aggregator { private static final String TAG = AggregatorRunning.class.getSimpleName(); @@ -19,7 +19,7 @@ public final class AggregatorRunning extends Aggregator current) { + public void computeValue(Raw current) { if (previous == null) { return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java deleted file mode 100644 index de5a9ac2a..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.dennisguse.opentracks.sensors.sensorData; - -import android.bluetooth.BluetoothGattCharacteristic; - -import java.util.List; - -import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; -import de.dennisguse.opentracks.sensors.driver.DriverObserver0; - -public interface SensorHandlerInterface { - - List getServices(); - - Aggregator createEmptySensorData(String address, String name); - - void handlePayload(DriverObserver0 observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); -} diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index acff98e07..ede4d04c8 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -48,7 +48,7 @@ import de.dennisguse.opentracks.data.models.HeartRateZones; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.TrackFilenameGenerator; -import de.dennisguse.opentracks.sensors.SensorType; +import de.dennisguse.opentracks.sensors.driver.SensorType; import de.dennisguse.opentracks.ui.customRecordingLayout.DataField; import de.dennisguse.opentracks.ui.customRecordingLayout.RecordingLayout; import de.dennisguse.opentracks.ui.customRecordingLayout.RecordingLayoutIO; diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java index ce0d9a2f7..a078bdb34 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import androidx.preference.PreferenceDialogFragmentCompat; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence; +import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth; public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPrefer @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothHandlerCyclingCadence.CYCLING_CADENCE); + return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), CyclingCadenceBluetooth.CYCLING_CADENCE); } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java index ff99809cd..8a2ac7294 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java @@ -7,7 +7,7 @@ import androidx.preference.PreferenceDialogFragmentCompat; import java.util.List; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower; +import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth; public class BluetoothLeCyclingPowerPreference extends BluetoothLeSensorPreference { @@ -29,6 +29,6 @@ public class BluetoothLeCyclingPowerPreference extends BluetoothLeSensorPreferen @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(BluetoothHandlerCyclingPower.CYCLING_POWER)); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(CyclingPowerBluetooth.CYCLING_POWER)); } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java index bddce5a21..63ffcc644 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java @@ -7,7 +7,7 @@ import androidx.preference.PreferenceDialogFragmentCompat; import java.util.List; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed; +import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; public class BluetoothLeCyclingSpeedPreference extends BluetoothLeSensorPreference { @@ -29,6 +29,6 @@ public class BluetoothLeCyclingSpeedPreference extends BluetoothLeSensorPreferen @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(BluetoothHandlerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE)); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(CyclingDistanceSpeedBluetooth.CYCLING_SPEED_CADENCE)); } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeHeartRatePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeHeartRatePreference.java index 97a447ddd..5ce0f6243 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeHeartRatePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeHeartRatePreference.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import androidx.preference.PreferenceDialogFragmentCompat; -import de.dennisguse.opentracks.sensors.BluetoothHandlerHeartRate; +import de.dennisguse.opentracks.sensors.driver.HeartRateBluetooth; public class BluetoothLeHeartRatePreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeHeartRatePreference extends BluetoothLeSensorPreference @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothHandlerHeartRate.HEART_RATE_SUPPORTING_DEVICES); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), HeartRateBluetooth.HEART_RATE_SUPPORTING_DEVICES); } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLePressurePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLePressurePreference.java index ee3e495a9..165600826 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLePressurePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLePressurePreference.java @@ -9,7 +9,7 @@ import androidx.preference.PreferenceDialogFragmentCompat; import java.util.List; -import de.dennisguse.opentracks.sensors.BluetoothHandlerBarometricPressure; +import de.dennisguse.opentracks.sensors.driver.BarometerBluetooth; public class BluetoothLePressurePreference extends BluetoothLeSensorPreference { @@ -36,6 +36,6 @@ public class BluetoothLePressurePreference extends BluetoothLeSensorPreference { boolean hasInternalSensor = pressureSensor != null; return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog - .newInstance(getKey(), List.of(BluetoothHandlerBarometricPressure.BAROMETRIC_PRESSURE), hasInternalSensor); + .newInstance(getKey(), List.of(BarometerBluetooth.BAROMETRIC_PRESSURE), hasInternalSensor); } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java index 470b8d636..426ad1972 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java @@ -7,7 +7,7 @@ import androidx.preference.PreferenceDialogFragmentCompat; import java.util.List; -import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence; +import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth; public class BluetoothLeRunningSpeedAndCadencePreference extends BluetoothLeSensorPreference { @@ -29,6 +29,6 @@ public class BluetoothLeRunningSpeedAndCadencePreference extends BluetoothLeSens @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(BluetoothHandlerRunningSpeedAndCadence.RUNNING_SPEED_CADENCE)); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), List.of(RunningSpeedAndCadenceBluetooth.RUNNING_SPEED_CADENCE)); } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java index 531fb6f0d..1143d60b7 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java @@ -28,8 +28,8 @@ import java.util.List; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.sensors.BluetoothUtils; -import de.dennisguse.opentracks.sensors.SensorType; import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; +import de.dennisguse.opentracks.sensors.driver.SensorType; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.PermissionRequester; diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeTemperaturePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeTemperaturePreference.java index 6cca492ad..b79caf2c4 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeTemperaturePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeTemperaturePreference.java @@ -7,7 +7,7 @@ import androidx.preference.PreferenceDialogFragmentCompat; import java.util.List; -import de.dennisguse.opentracks.sensors.BluetoothHandlerTemperature; +import de.dennisguse.opentracks.sensors.driver.TemperatureBluetooth; public class BluetoothLeTemperaturePreference extends BluetoothLeSensorPreference { @@ -30,6 +30,6 @@ public class BluetoothLeTemperaturePreference extends BluetoothLeSensorPreferenc @Override public PreferenceDialogFragmentCompat createInstance() { return BluetoothLeSensorPreferenceDialog - .newInstance(getKey(), List.of(BluetoothHandlerTemperature.TEMPERATURE)); + .newInstance(getKey(), List.of(TemperatureBluetooth.TEMPERATURE)); } } \ No newline at end of file From 24ea718ff222e5efdd4699f188ceda4949b897d0 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 31 Jan 2026 18:45:12 +0100 Subject: [PATCH 20/30] Cleanup: renamed GainManager to AltitudeChangeHandler. --- .../io/file/importer/ExportImportTest.java | 4 +- .../TrackRecordingServiceRecordingTest.java | 2 +- ...anager.java => AltitudeChangeHandler.java} | 4 +- .../opentracks/sensors/SensorManager.java | 39 +++++++------------ 4 files changed, 19 insertions(+), 30 deletions(-) rename src/main/java/de/dennisguse/opentracks/sensors/{GainManager.java => AltitudeChangeHandler.java} (90%) diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 201fe3ddd..3ad3681a9 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -725,7 +725,7 @@ public class ExportImportTest { SensorManager sensorManager = trackPointCreator.getSensorManager(); if (altitudeGain == null) { - sensorManager.getAltitudeSumManager().setAggregator(new AggregatorBarometer("test", null)); + sensorManager.getAltitudeChangeHandler().setAggregator(new AggregatorBarometer("test", null)); return; } @@ -741,7 +741,7 @@ public class ExportImportTest { return true; } }; - sensorManager.getAltitudeSumManager().setAggregator(aggregatorBarometer); + sensorManager.getAltitudeChangeHandler().setAggregator(aggregatorBarometer); } private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index ae74caa10..2d2b74e05 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -972,7 +972,7 @@ public class TrackRecordingServiceRecordingTest { } private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { - trackPointCreator.getSensorManager().getAltitudeSumManager().setAggregator(new AggregatorBarometer("", "") { + trackPointCreator.getSensorManager().getAltitudeChangeHandler().setAggregator(new AggregatorBarometer("", "") { @Override public boolean hasReceivedData() { return true; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java similarity index 90% rename from src/main/java/de/dennisguse/opentracks/sensors/GainManager.java rename to src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java index 64a67ff0c..f909fc077 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GainManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java @@ -15,9 +15,9 @@ 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 GainManager extends SensorHandler { +public class AltitudeChangeHandler extends SensorHandler { - public GainManager(SensorManager sensorManager) { + public AltitudeChangeHandler(SensorManager sensorManager) { super(sensorManager); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 0bf27eec2..ab67bdef6 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -17,7 +17,6 @@ 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.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; @@ -53,7 +52,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private CyclingPowerHandler cyclingPowerHandler; private RunningSpeedCadenceDistanceHandler runningSpeedCadenceDistanceHandler; - private GainManager altitudeSumManager; + private AltitudeChangeHandler altitudeChangeHandler; private GpsManager gpsManager; @@ -71,7 +70,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.handler = handler; gpsManager = new GpsManager(observer, this); - altitudeSumManager = new GainManager(this); + altitudeChangeHandler = new AltitudeChangeHandler(this); this.heartRateHandler = new HeartRateHandler(this); this.temperatureHandler = new TemperatureHandler(this); this.cyclingCadenceHandler = new CyclingCadenceHandler(this); @@ -79,7 +78,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.cyclingPowerHandler = new CyclingPowerHandler(this); this.runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this); - altitudeSumManager.start(context, handler); + altitudeChangeHandler.start(context, handler); heartRateHandler.start(context, handler); temperatureHandler.start(context, handler); cyclingCadenceHandler.start(context, handler); @@ -113,8 +112,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange runningSpeedCadenceDistanceHandler.stop(); runningSpeedCadenceDistanceHandler = null; - altitudeSumManager.stop(); - altitudeSumManager = null; + altitudeChangeHandler.stop(); + altitudeChangeHandler = null; gpsManager.stop(); gpsManager = null; @@ -124,7 +123,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } public void reset() { - if (gpsManager == null || altitudeSumManager == null) { + if (gpsManager == null || altitudeChangeHandler == null) { Log.d(TAG, "No recording running and no reset necessary."); return; } @@ -137,7 +136,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (cyclingDistanceSpeedHandler.getAggregator() != null) cyclingDistanceSpeedHandler.getAggregator().resetAggregated(); if (cyclingPowerHandler.getAggregator() != null) cyclingPowerHandler.getAggregator().resetAggregated(); if (runningSpeedCadenceDistanceHandler.getAggregator() != null) runningSpeedCadenceDistanceHandler.getAggregator().resetAggregated(); - if (altitudeSumManager.getAggregator() != null) altitudeSumManager.getAggregator().resetAggregated(); + if (altitudeChangeHandler.getAggregator() != null) altitudeChangeHandler.getAggregator().resetAggregated(); if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); } @@ -147,18 +146,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Deprecated @VisibleForTesting - public GainManager getAltitudeSumManager() { - return altitudeSumManager; - } - - @Deprecated - @VisibleForTesting - public void setAltitudeSumManager(GainManager altitudeSumManager) { - this.altitudeSumManager = altitudeSumManager; - } - - private synchronized void connect(BluetoothDriver connectionManager, String address) { - connectionManager.connect(context, handler, address); + public AltitudeChangeHandler getAltitudeChangeHandler() { + return altitudeChangeHandler; } @Override @@ -166,8 +155,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (gpsManager != null) { gpsManager.onSharedPreferenceChanged(sharedPreferences, key); - if (PreferencesUtils.isKey(altitudeSumManager.getSensorPreferenceKey(), key)) { - altitudeSumManager.connect(); + if (PreferencesUtils.isKey(altitudeChangeHandler.getSensorPreferenceKey(), key)) { + altitudeChangeHandler.connect(); } if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) { @@ -292,8 +281,8 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange Log.i(TAG, "Removing all aggregators"); //TODO This is to ExportImportTest alive; refactor test. - if (this.altitudeSumManager != null) { - this.altitudeSumManager.setAggregator(null); + if (this.altitudeChangeHandler != null) { + this.altitudeChangeHandler.setAggregator(null); } if (this.heartRateHandler != null) { this.heartRateHandler.setAggregator(null); @@ -320,7 +309,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public SensorDataSet getSensorDataSet(Instant now) { AggregatorGPS gps = gpsManager.getAggregatorGPS(); - AggregatorBarometer barometer = (AggregatorBarometer) altitudeSumManager.getAggregator(); + AggregatorBarometer barometer = (AggregatorBarometer) altitudeChangeHandler.getAggregator(); return new SensorDataSet( gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), From b79acfb9420e5d395b9fccea19f1d83bfdb45c0a Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 31 Jan 2026 19:04:03 +0100 Subject: [PATCH 21/30] Cleanup: SensorManager provides context and handler. --- .../opentracks/sensors/SensorHandler.java | 20 +------- .../opentracks/sensors/SensorManager.java | 46 +++++++++---------- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index 542f82126..fdb684227 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -1,7 +1,6 @@ package de.dennisguse.opentracks.sensors; import android.content.Context; -import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -16,8 +15,6 @@ public abstract class SensorHandler { private final SensorManager sensorManager; - private Context context; - private Handler handler; private Driver driver; private Aggregator aggregator; @@ -49,19 +46,6 @@ public abstract class SensorHandler { this.sensorManager = sensorManager; } - //TODO Do we really need start and stop? - void start(Context context, Handler handler) { - this.context = context; - this.handler = handler; - } - - void stop() { - this.context = null; - this.handler = null; - - disconnect(); - } - void connect() { disconnect(); @@ -80,7 +64,7 @@ public abstract class SensorHandler { default -> throw new UnsupportedOperationException(); } - driver.connect(context, handler, address); + driver.connect(sensorManager.getContext(), sensorManager.getHandler(), address); } void disconnect() { @@ -106,7 +90,7 @@ public abstract class SensorHandler { protected abstract int getSensorPreferenceKey(); protected Context getContext() { - return context; + return sensorManager.getContext(); } //TODO Try to keep aggregator private. diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index ab67bdef6..8c65baec5 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -32,7 +32,6 @@ import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.util.SystemUtils; -//TODO provide context and handler for different Managers (not passing via start(), but similar to getNow()). public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = SensorManager.class.getSimpleName(); @@ -71,20 +70,12 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager = new GpsManager(observer, this); altitudeChangeHandler = new AltitudeChangeHandler(this); - this.heartRateHandler = new HeartRateHandler(this); - this.temperatureHandler = new TemperatureHandler(this); - this.cyclingCadenceHandler = new CyclingCadenceHandler(this); - this.cyclingDistanceSpeedHandler = new CyclingDistanceSpeedHandler(this); - this.cyclingPowerHandler = new CyclingPowerHandler(this); - this.runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this); - - altitudeChangeHandler.start(context, handler); - heartRateHandler.start(context, handler); - temperatureHandler.start(context, handler); - cyclingCadenceHandler.start(context, handler); - cyclingDistanceSpeedHandler.start(context, handler); - cyclingPowerHandler.start(context, handler); - runningSpeedCadenceDistanceHandler.start(context, handler); + heartRateHandler = new HeartRateHandler(this); + temperatureHandler = new TemperatureHandler(this); + cyclingCadenceHandler = new CyclingCadenceHandler(this); + cyclingDistanceSpeedHandler = new CyclingDistanceSpeedHandler(this); + cyclingPowerHandler = new CyclingPowerHandler(this); + runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this); onSharedPreferenceChanged(null, null); @@ -94,25 +85,25 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public void stop() { wakeLock = SystemUtils.releaseWakeLock(wakeLock); - heartRateHandler.stop(); + heartRateHandler.disconnect(); heartRateHandler = null; - temperatureHandler.stop(); + temperatureHandler.disconnect(); temperatureHandler = null; - cyclingCadenceHandler.stop(); + cyclingCadenceHandler.disconnect(); cyclingCadenceHandler = null; - cyclingDistanceSpeedHandler.stop(); + cyclingDistanceSpeedHandler.disconnect(); cyclingDistanceSpeedHandler = null; - cyclingPowerHandler.stop(); + cyclingPowerHandler.disconnect(); cyclingPowerHandler = null; - runningSpeedCadenceDistanceHandler.stop(); + runningSpeedCadenceDistanceHandler.disconnect(); runningSpeedCadenceDistanceHandler = null; - altitudeChangeHandler.stop(); + altitudeChangeHandler.disconnect(); altitudeChangeHandler = null; gpsManager.stop(); @@ -189,8 +180,15 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return observer.getNow(); } - @VisibleForTesting - public SensorData getHeartRate(Instant now) { + public Context getContext() { + return context; + } + + public Handler getHandler() { + return handler; + } + + private SensorData getHeartRate(Instant now) { if (heartRateHandler.getAggregator() != null) { SensorData value = ((AggregatorHeartRate) heartRateHandler.getAggregator()).getAggregatedValueWithSensorName(now); //TODO Move this check into HeartRateHandler From a1a363698f22a308129ba56ce6585d41042f907f Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 31 Jan 2026 19:45:32 +0100 Subject: [PATCH 22/30] SensorHandler now interacts with Aggregator. --- .../sensors/AltitudeChangeHandler.java | 6 +- .../sensors/CyclingCadenceHandler.java | 6 +- .../sensors/CyclingDistanceSpeedHandler.java | 2 +- .../sensors/CyclingPowerHandler.java | 3 +- .../opentracks/sensors/HeartRateHandler.java | 5 +- .../RunningSpeedCadenceDistanceHandler.java | 2 +- .../opentracks/sensors/SensorHandler.java | 31 ++++++--- .../opentracks/sensors/SensorManager.java | 66 +++++++++++-------- .../sensors/TemperatureHandler.java | 5 +- .../sensors/sensorData/Aggregator.java | 4 +- 10 files changed, 75 insertions(+), 55 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java index f909fc077..c79550143 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java @@ -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 { +public class AltitudeChangeHandler extends SensorHandler { public AltitudeChangeHandler(SensorManager sensorManager) { super(sensorManager); @@ -44,7 +44,7 @@ public class AltitudeChangeHandler extends SensorHandler { @NonNull @Override - public Aggregator createAggregator() { + public AggregatorBarometer createAggregator() { return new AggregatorBarometer("", null); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java index 4fde2f997..64de38dad 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingCadenceHandler.java @@ -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 { +public class CyclingCadenceHandler extends SensorHandler { protected CyclingCadenceHandler(SensorManager sensorManager) { super(sensorManager); @@ -27,7 +27,7 @@ public class CyclingCadenceHandler extends SensorHandler createAggregator() { + protected AggregatorCyclingCadence createAggregator() { return new AggregatorCyclingCadence("", null); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java index 54d07c3b4..76ba0c82d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java @@ -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 { +public class CyclingDistanceSpeedHandler extends SensorHandler { protected CyclingDistanceSpeedHandler(SensorManager sensorManager) { super(sensorManager); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java index 65f43d2e4..1d5065c79 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingPowerHandler.java @@ -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 { +public class CyclingPowerHandler extends SensorHandler { protected CyclingPowerHandler(SensorManager sensorManager) { super(sensorManager); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java index b4e911f24..5f61fccd6 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java @@ -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 { +public class HeartRateHandler extends SensorHandler { protected HeartRateHandler(SensorManager sensorManager) { super(sensorManager); @@ -28,7 +27,7 @@ public class HeartRateHandler extends SensorHandler { @NonNull @Override - protected Aggregator createAggregator() { + protected AggregatorHeartRate createAggregator() { return new AggregatorHeartRate("", null); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java index e2b2d6333..c39c246cd 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java @@ -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 { +public class RunningSpeedCadenceDistanceHandler extends SensorHandler { protected RunningSpeedCadenceDistanceHandler(SensorManager sensorManager) { super(sensorManager); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index fdb684227..6cbe671d7 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -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 { +public abstract class SensorHandler { private final SensorManager sensorManager; private Driver driver; - private Aggregator aggregator; + private Aggregator aggregator; - protected final DriverObserver driverObserver = new DriverObserver<>() { + protected final DriverObserver driverObserver = new DriverObserver<>() { @Override public void onConnect() { SensorHandler.this.aggregator = createAggregator(); @@ -31,7 +35,7 @@ public abstract class SensorHandler { } @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 { } @NonNull - protected abstract Aggregator createAggregator(); + protected abstract Aggregator createAggregator(); protected abstract int getSensorPreferenceKey(); @@ -93,14 +97,23 @@ public abstract class SensorHandler { return sensorManager.getContext(); } - //TODO Try to keep aggregator private. - Aggregator getAggregator() { - return aggregator; + void resetAggregated() { + if (aggregator != null) { + aggregator.resetAggregated(); + } + } + + @Nullable + SensorData getSensorData(Instant now) { + if (aggregator == null) return null; + if (!aggregator.hasReceivedData()) return null; + + return aggregator.getAggregatedValueWithSensorName(now); } //TODO REMOVE @VisibleForTesting - public void setAggregator(Aggregator aggregator) { + public void setAggregator(Aggregator aggregator) { this.aggregator = aggregator; } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 8c65baec5..5589e1ff2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -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 getHeartRate(Instant now) { - if (heartRateHandler.getAggregator() != null) { - SensorData value = ((AggregatorHeartRate) heartRateHandler.getAggregator()).getAggregatedValueWithSensorName(now); + SensorData 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 getCadence(Instant now) { - if (cyclingCadenceHandler.getAggregator() != null) { - return ((AggregatorCyclingCadence) cyclingCadenceHandler.getAggregator()).getAggregatedValueWithSensorName(now); + { + SensorData 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 value = runningSpeedCadenceDistanceHandler.getSensorData(now); + if (value != null && value.data().cadence() != null) { + return new SensorData<>(value.data().cadence(), value.sensorNameOrAddress()); } return null; } private SensorData getDistance(Instant now) { - if (cyclingDistanceSpeedHandler.getAggregator() != null && cyclingDistanceSpeedHandler.getAggregator().hasReceivedData()) { - return new SensorData<>(((AggregatorCyclingDistanceSpeed) cyclingDistanceSpeedHandler.getAggregator()).getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeedHandler.getAggregator().getSensorNameOrAddress()); + { + SensorData 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 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 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 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 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) ); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java index 5b990d72b..823732b20 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java @@ -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 { +public class TemperatureHandler extends SensorHandler { protected TemperatureHandler(SensorManager sensorManager) { super(sensorManager); @@ -28,7 +27,7 @@ public class TemperatureHandler extends SensorHandler { @NonNull @Override - protected Aggregator createAggregator() { + protected AggregatorTemperature createAggregator() { return new AggregatorTemperature("", null); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index d039c74e2..4b5be814c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -25,12 +25,12 @@ public abstract class Aggregator { 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 next = new Raw<>(now, current); computeValue(next); previous = next; } From fa558c9ab7f29d0801553ba05c831a191f4ec57b Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 31 Jan 2026 19:51:26 +0100 Subject: [PATCH 23/30] Cleanup: SensorManager avoids instanceof for testing. --- .../io/file/importer/ExportImportTest.java | 12 +-- .../TrackRecordingServiceRecordingTest.java | 4 +- .../opentracks/sensors/SensorManager.java | 87 +++++++++---------- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 3ad3681a9..7587f038f 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -664,12 +664,12 @@ public class ExportImportTest { AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); cyclingPower.add(trackPointCreator.getNow(), new CyclingPowerBluetooth.Data(Power.of(power), null)); - sensorManager.add(cyclingPower); + sensorManager.setAggregator(cyclingPower); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); avgHeartRate.add(trackPointCreator.getNow(), HeartRate.of(heartRate)); - sensorManager.add(avgHeartRate); + sensorManager.setAggregator(avgHeartRate); AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") { @NonNull @@ -683,7 +683,7 @@ public class ExportImportTest { return true; } }; - sensorManager.add(cyclingCadence); + sensorManager.setAggregator(cyclingCadence); if (distance != null && speed != null) { AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") { @@ -698,14 +698,14 @@ public class ExportImportTest { return true; } }; - sensorManager.add(aggregatorCyclingDistanceSpeed); + sensorManager.setAggregator(aggregatorCyclingDistanceSpeed); } else { - sensorManager.add(new AggregatorCyclingDistanceSpeed("", "")); + sensorManager.setAggregator(new AggregatorCyclingDistanceSpeed("", "")); } mockAltitudeChange(trackPointCreator, altitudeGain); - sensorManager.add(new AggregatorTemperature("", "'") { + sensorManager.setAggregator(new AggregatorTemperature("", "'") { @NonNull @Override public Temperature getAggregatedValue(Instant now) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 2d2b74e05..abba894c5 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -341,7 +341,7 @@ public class TrackRecordingServiceRecordingTest { trackPointCreator.setClock(sensor1); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); - sensorManager.add(avgHeartRate); + sensorManager.setAggregator(avgHeartRate); //Should be ignored avgHeartRate.add(trackPointCreator.getNow(), HeartRate.of(5)); @@ -812,7 +812,7 @@ public class TrackRecordingServiceRecordingTest { AggregatorRunning aggregatorRunning = new AggregatorRunning("", ""); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.add(aggregatorRunning); + sensorManager.setAggregator(aggregatorRunning); // when String sensor1 = "2020-02-02T02:02:03Z"; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index 5589e1ff2..eb850db69 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -17,7 +17,6 @@ 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.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower; @@ -247,42 +246,25 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange return null; } - //TODO Remove - @VisibleForTesting - @Deprecated - public void add(@NonNull Aggregator data) { - if (data instanceof AggregatorHeartRate) { - heartRateHandler.setAggregator((AggregatorHeartRate) data); - return; - } - if (data instanceof AggregatorTemperature) { - temperatureHandler.setAggregator((AggregatorTemperature) data); - return; - } - if (data instanceof AggregatorCyclingCadence) { - cyclingCadenceHandler.setAggregator((AggregatorCyclingCadence) data); - return; - } - if (data instanceof AggregatorCyclingDistanceSpeed) { - cyclingDistanceSpeedHandler.setAggregator((AggregatorCyclingDistanceSpeed) data); - return; - } - if (data instanceof AggregatorCyclingPower) { - cyclingPowerHandler.setAggregator((AggregatorCyclingPower) data); - return; - } - if (data instanceof AggregatorRunning) { - runningSpeedCadenceDistanceHandler.setAggregator((AggregatorRunning) data); - return; - } - - throw new UnsupportedOperationException(data.getClass().getCanonicalName()); - } - public void onChange() { observer.onChange(); } + public SensorDataSet getSensorDataSet(Instant now) { + AggregatorGPS gps = gpsManager.getAggregatorGPS(); + + return new SensorDataSet( + gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), + getSpeed(now), + getDistance(now), + getHeartRate(now), + temperatureHandler.getSensorData(now), + getCadence(now), + cyclingPowerHandler.getSensorData(now), + altitudeChangeHandler.getSensorData(now) + ); + } + @VisibleForTesting public void clear() { Log.i(TAG, "Removing all aggregators"); @@ -314,18 +296,33 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } } - public SensorDataSet getSensorDataSet(Instant now) { - AggregatorGPS gps = gpsManager.getAggregatorGPS(); + @VisibleForTesting + public void setAggregator(AggregatorHeartRate data) { + heartRateHandler.setAggregator(data); + } - return new SensorDataSet( - gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), - getSpeed(now), - getDistance(now), - getHeartRate(now), - temperatureHandler.getSensorData(now), - getCadence(now), - cyclingPowerHandler.getSensorData(now), - altitudeChangeHandler.getSensorData(now) - ); + @VisibleForTesting + public void setAggregator(@NonNull AggregatorTemperature data) { + temperatureHandler.setAggregator(data); + } + + @VisibleForTesting + public void setAggregator(@NonNull AggregatorCyclingCadence data) { + cyclingCadenceHandler.setAggregator(data); + } + + @VisibleForTesting + public void setAggregator(@NonNull AggregatorCyclingDistanceSpeed data) { + cyclingDistanceSpeedHandler.setAggregator(data); + } + + @VisibleForTesting + public void setAggregator(@NonNull AggregatorCyclingPower data) { + cyclingPowerHandler.setAggregator(data); + } + + @VisibleForTesting + public void setAggregator(@NonNull AggregatorRunning data) { + runningSpeedCadenceDistanceHandler.setAggregator(data); } } From dfa80d61d746b7718c3d9ce46ab27e618dc3b154 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sun, 1 Feb 2026 09:13:03 +0100 Subject: [PATCH 24/30] Restored functionality: sensor name/address is shown AFTER connecting. --- .../opentracks/sensors/AltitudeChangeHandler.java | 4 ++-- .../opentracks/sensors/CyclingCadenceHandler.java | 4 ++-- .../opentracks/sensors/CyclingDistanceSpeedHandler.java | 4 ++-- .../dennisguse/opentracks/sensors/CyclingPowerHandler.java | 4 ++-- .../java/de/dennisguse/opentracks/sensors/GpsManager.java | 2 +- .../de/dennisguse/opentracks/sensors/HeartRateHandler.java | 4 ++-- .../sensors/RunningSpeedCadenceDistanceHandler.java | 2 +- .../de/dennisguse/opentracks/sensors/SensorHandler.java | 6 +++--- .../dennisguse/opentracks/sensors/TemperatureHandler.java | 4 ++-- .../opentracks/sensors/driver/BarometerInternal.java | 2 +- .../opentracks/sensors/driver/BluetoothDriver.java | 2 +- .../opentracks/sensors/driver/DriverObserver.java | 2 +- .../dennisguse/opentracks/sensors/driver/GpsInternal.java | 2 +- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java index c79550143..af429029a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java @@ -44,7 +44,7 @@ public class AltitudeChangeHandler extends SensorHandler, GpsStatusManager.Gp } @Override - public void onConnect() { + public void onConnect(String sensorAddress, String sensorName) { gpsStatusManager.onGpsEnabled(); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java index 5f61fccd6..4241cd16d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java @@ -27,8 +27,8 @@ public class HeartRateHandler extends SensorHandler { @NonNull @Override - protected AggregatorHeartRate createAggregator() { - return new AggregatorHeartRate("", null); + protected AggregatorHeartRate createAggregator(String sensorAddress, String sensorName) { + return new AggregatorHeartRate(sensorAddress, sensorName); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java index c39c246cd..2fa8c5712 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java @@ -26,7 +26,7 @@ public class RunningSpeedCadenceDistanceHandler extends SensorHandler { protected final DriverObserver driverObserver = new DriverObserver<>() { @Override - public void onConnect() { - SensorHandler.this.aggregator = createAggregator(); + public void onConnect(String sensorAddress, String sensorName) { + SensorHandler.this.aggregator = createAggregator(sensorAddress, sensorName); } @Override @@ -89,7 +89,7 @@ public abstract class SensorHandler { } @NonNull - protected abstract Aggregator createAggregator(); + protected abstract Aggregator createAggregator(String sensorAddress, String sensorName); protected abstract int getSensorPreferenceKey(); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java index 823732b20..7c1a6d972 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java @@ -27,8 +27,8 @@ public class TemperatureHandler extends SensorHandler @NonNull @Override - protected AggregatorTemperature createAggregator() { - return new AggregatorTemperature("", null); + protected AggregatorTemperature createAggregator(String sensorAddress, String sensorName) { + return new AggregatorTemperature(sensorAddress, sensorName); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index 4da4e4fd6..fbcb5a839 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -56,7 +56,7 @@ public class BarometerInternal implements Driver { if (sensorManager.registerListener(sensorEventListener, pressureSensor, SAMPLING_PERIOD, handler)) { this.context = context; - observer.onConnect(); + observer.onConnect(null, null); return; } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java index 811bdc769..37d1d264f 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java @@ -166,7 +166,7 @@ public class BluetoothDriver implements Driver { bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler); - observer.onConnect(); //TODO pass device.getAddress(), device.getName() + observer.onConnect(device.getAddress(), device.getName()); } private synchronized void clearData() { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java index ba066142b..eecf89096 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java @@ -2,7 +2,7 @@ package de.dennisguse.opentracks.sensors.driver; public interface DriverObserver { - void onConnect(); + void onConnect(String sensorAddress, String sensorName); void onDisconnect(); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java index 216c9a562..cbde65a29 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java @@ -28,7 +28,7 @@ public class GpsInternal implements Driver { @Override public void onProviderEnabled(@NonNull String provider) { - driverObserver.onConnect(); + driverObserver.onConnect(null, provider); } @Override From 1c767c41a79107dddc083cf8c8c5e2e06c6dc8cf Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 2 Feb 2026 21:15:50 +0100 Subject: [PATCH 25/30] DriverObserver: renamed methods and all drivers properly use onConnected, onConnectionLost and onDisconnected. --- .../io/file/importer/ExportImportTest.java | 2 +- .../TrackRecordingServiceRecordingTest.java | 2 +- .../opentracks/sensors/GpsManager.java | 8 ++-- .../opentracks/sensors/SensorHandler.java | 9 +++-- .../sensors/driver/BarometerInternal.java | 28 +++++-------- .../sensors/driver/BluetoothDriver.java | 40 +++++++------------ .../sensors/driver/DriverObserver.java | 21 ++++++++-- .../sensors/driver/GpsInternal.java | 12 ++++-- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 7587f038f..8315d5e8a 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -756,6 +756,6 @@ public class ExportImportTest { mockAltitudeChange(trackPointCreator, altitudeGain); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onData(location); + trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index abba894c5..9b94d2595 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -995,6 +995,6 @@ public class TrackRecordingServiceRecordingTest { location.setSpeed(speed); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onData(location); + trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index a79b29680..c89938007 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -120,22 +120,22 @@ public class GpsManager implements DriverObserver, GpsStatusManager.Gp } @Override - public void onConnect(String sensorAddress, String sensorName) { + public void onConnected(String sensorAddress, String sensorName) { gpsStatusManager.onGpsEnabled(); } @Override - public void onDisconnect() { + public void onConnectionLost() { gpsStatusManager.onGpsDisabled(); } @Override - public void onRemove() { + public void onDisconnected() { gpsStatusManager.onGpsDisabled(); } @Override - public void onData(Location location) { + public void onDataReceived(Location location) { // Send each update to the status; please note that this TrackPoint is not stored. Position position = Position.of(location, observer.getNow()); gpsStatusManager.onNewTrackPoint(position); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index cbb5d5b98..e8d45f548 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -25,23 +25,23 @@ public abstract class SensorHandler { protected final DriverObserver driverObserver = new DriverObserver<>() { @Override - public void onConnect(String sensorAddress, String sensorName) { + public void onConnected(String sensorAddress, String sensorName) { SensorHandler.this.aggregator = createAggregator(sensorAddress, sensorName); } @Override - public void onDisconnect() { + public void onConnectionLost() { SensorHandler.this.aggregator.resetAggregated(); } @Override - public void onData(AggregatorInput value) { + public void onDataReceived(AggregatorInput value) { SensorHandler.this.aggregator.add(sensorManager.getNow(), value); sensorManager.onChange(); } @Override - public void onRemove() { + public void onDisconnected() { SensorHandler.this.aggregator = null; } }; @@ -57,6 +57,7 @@ public abstract class SensorHandler { switch (PreferencesUtils.getSensorType(address)) { case NONE -> { + driverObserver.onDisconnected(); return; } case INTERNAL -> { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java index fbcb5a839..b200d1f09 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BarometerInternal.java @@ -21,7 +21,7 @@ public class BarometerInternal implements Driver { private final DriverObserver observer; - private Context context; + private android.hardware.SensorManager sensorService; private final SensorEventListener sensorEventListener = new SensorEventListener() { @Override @@ -31,7 +31,7 @@ public class BarometerInternal implements Driver { return; } - observer.onData(AtmosphericPressure.ofHPA(event.values[0])); + observer.onDataReceived(AtmosphericPressure.ofHPA(event.values[0])); } @Override @@ -46,34 +46,28 @@ public class BarometerInternal implements Driver { @Override public void connect(Context context, Handler handler, String addressIgnored) { + sensorService = (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + Sensor pressureSensor = sensorService.getDefaultSensor(Sensor.TYPE_PRESSURE); - android.hardware.SensorManager sensorManager = (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); - if (pressureSensor == null) { - Log.w(TAG, "No pressure sensor available."); + if (pressureSensor != null && sensorService.registerListener(sensorEventListener, pressureSensor, SAMPLING_PERIOD, handler)) { + observer.onConnected(null, null); return; } - if (sensorManager.registerListener(sensorEventListener, pressureSensor, SAMPLING_PERIOD, handler)) { - this.context = context; - observer.onConnect(null, null); - return; - } - - disconnect(); + Log.w(TAG, "No pressure sensor available."); + observer.onDisconnected(); } @Override public boolean isConnected() { - return context != null; + return sensorService != null; } @Override public void disconnect() { if (!isConnected()) return; - android.hardware.SensorManager sensorManager = (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - sensorManager.unregisterListener(sensorEventListener); - this.context = null; + sensorService.unregisterListener(sensorEventListener); + sensorService = null; } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java index 37d1d264f..e3b088383 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java @@ -56,27 +56,29 @@ public class BluetoothDriver implements Driver { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { switch (newState) { - case BluetoothProfile.STATE_CONNECTING -> - Log.i(TAG, gatt.getDevice() + ": connecting to sensor"); + case BluetoothProfile.STATE_CONNECTING -> { + Log.i(TAG, gatt.getDevice() + ": connecting to sensor"); + } case BluetoothProfile.STATE_CONNECTED -> { Log.i(TAG, gatt.getDevice() + ": connected to sensor; discovering services"); gatt.discoverServices(); } - case BluetoothProfile.STATE_DISCONNECTING -> - Log.i(TAG, gatt.getDevice() + ": disconnecting from sensor: "); + case BluetoothProfile.STATE_DISCONNECTING -> Log.i(TAG, gatt.getDevice() + ": disconnecting from sensor: "); case BluetoothProfile.STATE_DISCONNECTED -> { //This is also triggered, if no connection was established (ca. 30s) Log.i(TAG, gatt.getDevice() + ": disconnected from sensor: trying to reconnect"); if (gatt.connect()) { Log.e(TAG, gatt.getDevice() + ": could not trigger reconnect for sensor"); } - clearData(); + observer.onConnectionLost(); } } } @Override public void onServicesDiscovered(@NonNull BluetoothGatt gatt, int status) { + BluetoothDevice device = gatt.getDevice(); + BluetoothGattService gattService = null; ServiceMeasurementUUID serviceMeasurement = null; for (ServiceMeasurementUUID s : sensorHandler.getServices()) { @@ -88,13 +90,13 @@ public class BluetoothDriver implements Driver { } if (gattService == null) { - Log.e(TAG, gatt.getDevice() + ": could not get gattService for serviceUUID=" + serviceMeasurement); + Log.e(TAG, device + ": could not get gattService for serviceUUID=" + serviceMeasurement); return; } BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(serviceMeasurement.measurementUUID()); if (characteristic == null) { - Log.e(TAG, gatt.getDevice() + ": could not get BluetoothCharacteristic for serviceUUID=" + serviceMeasurement.serviceUUID() + " characteristicUUID=" + serviceMeasurement.measurementUUID()); + Log.e(TAG, device + ": could not get BluetoothCharacteristic for serviceUUID=" + serviceMeasurement.serviceUUID() + " characteristicUUID=" + serviceMeasurement.measurementUUID()); return; } gatt.setCharacteristicNotification(characteristic, true); @@ -112,6 +114,8 @@ public class BluetoothDriver implements Driver { if (!gatt.writeDescriptor(descriptor)) { Log.e(TAG, "CLIENT_CHARACTERISTIC_CONFIG_UUID descriptor could not be written"); } + + observer.onConnected(device.getAddress(), device.getName()); } @Override @@ -132,7 +136,7 @@ public class BluetoothDriver implements Driver { if (value == null) { return; } - observer.onData(value); + observer.onDataReceived(value); } }; @@ -165,37 +169,23 @@ public class BluetoothDriver implements Driver { Log.d(TAG, device + ": trying to connect"); bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler); - - observer.onConnect(device.getAddress(), device.getName()); - } - - private synchronized void clearData() { - observer.onDisconnect(); } @Override public synchronized void disconnect() { if (!isConnected()) { - Log.w(TAG, "Not connected; no need to re-connect."); + Log.w(TAG, "Not connected; cannot disconnect."); return; } Log.i(TAG, bluetoothGatt.getDevice() + ": start disconnect"); bluetoothGatt.disconnect(); bluetoothGatt.close(); - clearData(); Log.i(TAG, bluetoothGatt.getDevice() + ": disconnect finished"); bluetoothGatt = null; + + observer.onDisconnected(); } - private synchronized boolean isSameBluetoothDevice(String address) { - if (bluetoothGatt == null) { - return false; - } - - return address.equals(bluetoothGatt.getDevice().getAddress()); - } - - private boolean isBluetoothEnabled() { return bluetoothAdapter != null && bluetoothAdapter.isEnabled(); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java index eecf89096..4fda6d99d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java @@ -2,11 +2,24 @@ package de.dennisguse.opentracks.sensors.driver; public interface DriverObserver { - void onConnect(String sensorAddress, String sensorName); + /** + * The Driver could connect to the sensor. + */ + void onConnected(String sensorAddress, String sensorName); - void onDisconnect(); + /** + * Sensor got temporarily disconnected, Driver should try to re-connect. + */ + void onConnectionLost(); - void onData(T value); + /** + * The Driver provided data from the sensor. + */ + void onDataReceived(T value); - void onRemove(); + /** + * The Driver was shutdown and no further data will be provided. + */ + //TODO check if really need this, because the driver was told to disconnect and then just signalizes that it finished this task. + void onDisconnected(); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java index cbde65a29..77b668bf2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java @@ -23,17 +23,17 @@ public class GpsInternal implements Driver { private final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() { @Override public void onLocationChanged(@NonNull Location location) { - driverObserver.onData(location); + driverObserver.onDataReceived(location); } @Override public void onProviderEnabled(@NonNull String provider) { - driverObserver.onConnect(null, provider); + driverObserver.onConnected(null, provider); } @Override public void onProviderDisabled(@NonNull String provider) { - driverObserver.onDisconnect(); + driverObserver.onConnectionLost(); } }; @@ -63,10 +63,14 @@ public class GpsInternal implements Driver { try { Log.i(TAG, "Register for location updates " + context); LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat); + driverObserver.onConnected(null, null); + return; } catch (SecurityException e) { Log.e(TAG, "Could not register location listener; permissions not granted.", e); } } + + driverObserver.onDisconnected(); } @SuppressWarnings({"MissingPermission"}) @@ -77,7 +81,7 @@ public class GpsInternal implements Driver { LocationManagerCompat.removeUpdates(locationManager, locationListenerCompat); locationManager = null; - driverObserver.onDisconnect(); + driverObserver.onDisconnected(); } From 0b849c3d55a25fc6bd6c0f2dc18f7c2618b5a889 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 2 Feb 2026 21:39:23 +0100 Subject: [PATCH 26/30] CyclingDistanceSpeedHandler: uses wheel size (again). Skipped while to SensorHandler: a5dcbec3961957dfc651cf4ffd62ec075324c0ba --- .../sensors/AltitudeChangeHandler.java | 14 +++--- .../sensors/CyclingCadenceHandler.java | 2 +- .../sensors/CyclingDistanceSpeedHandler.java | 12 ++++- .../sensors/CyclingPowerHandler.java | 2 +- .../opentracks/sensors/HeartRateHandler.java | 2 +- .../RunningSpeedCadenceDistanceHandler.java | 2 +- .../opentracks/sensors/SensorHandler.java | 49 +++++++++---------- .../sensors/TemperatureHandler.java | 2 +- 8 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java index af429029a..1eee74bfc 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/AltitudeChangeHandler.java @@ -21,15 +21,10 @@ public class AltitudeChangeHandler extends SensorHandler( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new BarometerBluetooth() ); } @@ -47,4 +42,9 @@ public class AltitudeChangeHandler extends SensorHandler( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new CyclingCadenceBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java index 7bef5c16d..79dbd6d9a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/CyclingDistanceSpeedHandler.java @@ -7,6 +7,7 @@ import de.dennisguse.opentracks.sensors.driver.BluetoothDriver; import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed; +import de.dennisguse.opentracks.settings.PreferencesUtils; public class CyclingDistanceSpeedHandler extends SensorHandler { @@ -17,10 +18,9 @@ public class CyclingDistanceSpeedHandler extends SensorHandler( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new CyclingDistanceSpeedBluetooth() ); } @@ -35,4 +35,12 @@ public class CyclingDistanceSpeedHandler extends SensorHandler( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new CyclingPowerBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java index 4241cd16d..d44bd8b66 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/HeartRateHandler.java @@ -20,7 +20,7 @@ public class HeartRateHandler extends SensorHandler { protected Driver createDriverBluetooth(String address) { return new BluetoothDriver<>( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new HeartRateBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java index 2fa8c5712..d9581d669 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/RunningSpeedCadenceDistanceHandler.java @@ -19,7 +19,7 @@ public class RunningSpeedCadenceDistanceHandler extends SensorHandler( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new RunningSpeedAndCadenceBluetooth() ); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index e8d45f548..7d2003b3f 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -15,36 +15,13 @@ import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.settings.PreferencesUtils; -public abstract class SensorHandler { +public abstract class SensorHandler implements DriverObserver { private final SensorManager sensorManager; private Driver driver; - private Aggregator aggregator; - - protected final DriverObserver driverObserver = new DriverObserver<>() { - @Override - public void onConnected(String sensorAddress, String sensorName) { - SensorHandler.this.aggregator = createAggregator(sensorAddress, sensorName); - } - - @Override - public void onConnectionLost() { - SensorHandler.this.aggregator.resetAggregated(); - } - - @Override - public void onDataReceived(AggregatorInput value) { - SensorHandler.this.aggregator.add(sensorManager.getNow(), value); - sensorManager.onChange(); - } - - @Override - public void onDisconnected() { - SensorHandler.this.aggregator = null; - } - }; + protected Aggregator aggregator; protected SensorHandler(SensorManager sensorManager) { this.sensorManager = sensorManager; @@ -57,7 +34,7 @@ public abstract class SensorHandler { switch (PreferencesUtils.getSensorType(address)) { case NONE -> { - driverObserver.onDisconnected(); + onDisconnected(); return; } case INTERNAL -> { @@ -117,4 +94,24 @@ public abstract class SensorHandler { public void setAggregator(Aggregator aggregator) { this.aggregator = aggregator; } + + public void onConnected(String sensorAddress, String sensorName) { + SensorHandler.this.aggregator = createAggregator(sensorAddress, sensorName); + } + + @Override + public void onConnectionLost() { + SensorHandler.this.aggregator.resetAggregated(); + } + + @Override + public void onDataReceived(AggregatorInput value) { + SensorHandler.this.aggregator.add(sensorManager.getNow(), value); + sensorManager.onChange(); + } + + @Override + public void onDisconnected() { + SensorHandler.this.aggregator = null; + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java index 7c1a6d972..146797d5d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/TemperatureHandler.java @@ -20,7 +20,7 @@ public class TemperatureHandler extends SensorHandler protected Driver createDriverBluetooth(String address) { return new BluetoothDriver<>( BluetoothUtils.getAdapter(getContext()), - driverObserver, + this, new TemperatureBluetooth() ); } From d75472ef118783c7351ac8cbe726e092fdc53d46 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Wed, 4 Feb 2026 19:01:11 +0100 Subject: [PATCH 27/30] BluetoothLeSensorPreference was not adhering to configured default value. --- .../settings/bluetooth/BluetoothLeSensorPreference.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java index 1143d60b7..7e90f94d9 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeSensorPreference.java @@ -10,6 +10,7 @@ import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.content.DialogInterface; +import android.content.res.TypedArray; import android.os.Bundle; import android.os.ParcelUuid; import android.text.TextUtils; @@ -18,6 +19,7 @@ import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.preference.DialogPreference; import androidx.preference.PreferenceDialogFragmentCompat; @@ -80,6 +82,12 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference { } } + @Nullable + @Override + protected Object onGetDefaultValue(@NonNull TypedArray a, int index) { + return a.getString(index); + } + @Override protected void onSetInitialValue(Object defaultValue) { setValue(getPersistedString((String) defaultValue)); From b651a8ca6a36733d70ecfc24fedc6b4d093e857c Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Wed, 4 Feb 2026 22:37:19 +0100 Subject: [PATCH 28/30] GPS is now optional: data source (internal, none) be selected in settings. Migrated to GPSHandler. Fixes #1279. --- .../io/file/importer/ExportImportTest.java | 13 +- .../TrackRecordingServiceRecordingTest.java | 7 +- .../{GpsManager.java => GpsHandler.java} | 150 +++++++----------- .../opentracks/sensors/GpsStatusManager.java | 16 +- .../opentracks/sensors/SensorHandler.java | 13 +- .../opentracks/sensors/SensorManager.java | 84 +++++----- .../sensors/driver/BluetoothDriver.java | 1 + .../sensors/driver/DriverObserver.java | 6 + .../sensors/driver/GpsInternal.java | 13 +- .../sensors/sensorData/Aggregator.java | 4 - .../sensors/sensorData/AggregatorGPS.java | 12 +- .../opentracks/settings/PreferencesUtils.java | 4 - .../bluetooth/BluetoothLeGpsPreference.java | 41 +++++ src/main/res/values/settings.xml | 1 + src/main/res/xml/settings_sensors.xml | 9 +- 15 files changed, 203 insertions(+), 171 deletions(-) rename src/main/java/de/dennisguse/opentracks/sensors/{GpsManager.java => GpsHandler.java} (52%) create mode 100644 src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeGpsPreference.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 8315d5e8a..bf12ed3ab 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -77,6 +77,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; +import de.dennisguse.opentracks.settings.PreferencesUtils; /** * Export a track to {@link TrackFileFormat} and verify that the import is identical. @@ -88,7 +89,7 @@ import de.dennisguse.opentracks.services.handlers.TrackPointCreator; public class ExportImportTest { @Rule - public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS); + public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(50, TimeUnit.SECONDS); //TODO 5s @Rule public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule(); @@ -97,13 +98,15 @@ public class ExportImportTest { @Rule public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin")); + private static final Context context = ApplicationProvider.getApplicationContext(); + @BeforeClass public static void preSetUp() { // Prepare looper for Android's message queue if (Looper.myLooper() == null) Looper.prepare(); - } - private final Context context = ApplicationProvider.getApplicationContext(); + PreferencesUtils.resetPreferences(context, true); + } private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context); @@ -161,7 +164,7 @@ public class ExportImportTest { "Marker 1 desc", "Marker 1 typeLocalized", new Position( - Instant.parse("2020-02-02T02:02:03Z"), + Instant.parse("2020-02-02T02:02:03Z"), 3.1234567, 14.0014567, Distance.of(10), Altitude.WGS84.of(1020.25), @@ -756,6 +759,6 @@ public class ExportImportTest { mockAltitudeChange(trackPointCreator, altitudeGain); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location); + trackPointCreator.getSensorManager().getGpsHandler().onDataReceived(location); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 9b94d2595..27c54e79c 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -9,6 +9,7 @@ import android.location.Location; import android.os.Looper; import androidx.annotation.NonNull; +import androidx.core.location.LocationManagerCompat; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; @@ -43,6 +44,7 @@ import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.io.file.importer.TrackPointAssert; import de.dennisguse.opentracks.sensors.SensorManager; +import de.dennisguse.opentracks.sensors.driver.GpsInternal; import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth; import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer; import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate; @@ -151,7 +153,8 @@ public class TrackRecordingServiceRecordingTest { Track.Id trackId = service.startNewTrack(); //We do not want the real GPS to interfere. - trackPointCreator.getSensorManager().getGpsManager().driver.disconnect(); + GpsInternal gpsInternal = (GpsInternal)trackPointCreator.getSensorManager().getGpsHandler().driver; + LocationManagerCompat.removeUpdates(gpsInternal.locationManager, gpsInternal.locationListenerCompat); String gps1 = "2020-02-02T02:02:03Z"; sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15); @@ -995,6 +998,6 @@ public class TrackRecordingServiceRecordingTest { location.setSpeed(speed); trackPointCreator.setClock(time); - trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location); + trackPointCreator.getSensorManager().getGpsHandler().onDataReceived(location); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsHandler.java similarity index 52% rename from src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java rename to src/main/java/de/dennisguse/opentracks/sensors/GpsHandler.java index c89938007..ff2527720 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsHandler.java @@ -1,9 +1,7 @@ package de.dennisguse.opentracks.sensors; -import android.content.Context; import android.content.SharedPreferences; import android.location.Location; -import android.os.Handler; import android.util.Log; import androidx.annotation.NonNull; @@ -12,95 +10,25 @@ import androidx.annotation.VisibleForTesting; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Position; -import de.dennisguse.opentracks.sensors.driver.DriverObserver; +import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.GpsInternal; +import de.dennisguse.opentracks.sensors.driver.SensorType; import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) -public class GpsManager implements DriverObserver, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { +public class GpsHandler extends SensorHandler { - private final String TAG = GpsManager.class.getSimpleName(); + private final String TAG = GpsHandler.class.getSimpleName(); //TODO Refactor to just pass information via SensorManager. private TrackPointCreator trackPointCreator; - private SensorManager observer; - private Context context; - private Handler handler; - - @VisibleForTesting - public GpsInternal driver; private GpsStatusManager gpsStatusManager; private Distance thresholdHorizontalAccuracy; - private AggregatorGPS aggregatorGPS; - - public GpsManager(TrackPointCreator trackPointCreator, SensorManager observer) { - this.trackPointCreator = trackPointCreator; - this.observer = observer; - } - - public void start(@NonNull Context context, @NonNull Handler handler) { - this.context = context; - this.handler = handler; - - onSharedPreferenceChanged(null, null); - - gpsStatusManager = new GpsStatusManager(context, this, handler); - - this.aggregatorGPS = new AggregatorGPS("internal"); - - this.driver = new GpsInternal(this); - this.driver.connect(context, handler, "internal"); - gpsStatusManager.start(); - } - - @SuppressWarnings({"MissingPermission"}) - public void stop() { - if (driver.isConnected()) { - driver.disconnect(); - } - driver = null; - this.context = null; - handler = null; - - gpsStatusManager.stop(); - gpsStatusManager = null; - - this.aggregatorGPS = null; - observer = null; - - trackPointCreator = null; - } - - //TODO Exposed for refactoring. Is this necessary? - @Deprecated - AggregatorGPS getAggregatorGPS() { - return aggregatorGPS; - } - - //TODO Exposed for refactoring. This is very ugly. - @Deprecated - void setAggregatorGPS() { - this.aggregatorGPS = null; - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - boolean registerListener = false; - - if (PreferencesUtils.isKey(R.string.min_sampling_interval_key, key)) { - registerListener = true; - - if (gpsStatusManager != null) { - gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval()); - } - } - if (PreferencesUtils.isKey(R.string.recording_gps_accuracy_key, key)) { - thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(); - } + private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { if (PreferencesUtils.isKey(R.string.recording_distance_interval_key, key)) { if (gpsStatusManager != null) { Distance gpsMinDistance = PreferencesUtils.getRecordingDistanceInterval(); @@ -108,49 +36,85 @@ public class GpsManager implements DriverObserver, GpsStatusManager.Gp } } - if (registerListener && driver != null && driver.isConnected()) { - driver.disconnect(); - driver.connect(context, handler, "internal"); + if (PreferencesUtils.isKey(R.string.recording_gps_accuracy_key, key)) { + thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(); } - } - @Override - public void onGpsStatusChanged(GpsStatusValue currentStatus) { - trackPointCreator.sendGpsStatus(currentStatus); + if (PreferencesUtils.isKey(R.string.min_sampling_interval_key, key)) { + if (gpsStatusManager != null) { + gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval()); + } + + //TODO + connect(); + } + }; + + public GpsHandler(SensorManager sensorManager, TrackPointCreator trackPointCreator) { + super(sensorManager); + this.trackPointCreator = trackPointCreator; + gpsStatusManager = new GpsStatusManager(sensorManager.getContext(), trackPointCreator::sendGpsStatus, sensorManager.getHandler()); + + sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null); } @Override public void onConnected(String sensorAddress, String sensorName) { + super.onConnected(sensorAddress, sensorName); gpsStatusManager.onGpsEnabled(); - } - - @Override - public void onConnectionLost() { - gpsStatusManager.onGpsDisabled(); + gpsStatusManager.start(); } @Override public void onDisconnected() { + super.onDisconnected(); + gpsStatusManager.stop(); + } + + @Override + public void onSensorDeactivated() { + super.onSensorDeactivated(); gpsStatusManager.onGpsDisabled(); } @Override public void onDataReceived(Location location) { // Send each update to the status; please note that this TrackPoint is not stored. - Position position = Position.of(location, observer.getNow()); + Position position = Position.of(location, trackPointCreator.getNow()); gpsStatusManager.onNewTrackPoint(position); + //TODO We could move the following check into the AggregatorGPS if (!position.hasValidLocation()) { Log.w(TAG, "Ignore newTrackPoint. Location is invalid."); return; } - if (!position.fulfillsAccuracy(thresholdHorizontalAccuracy)) { Log.d(TAG, "Ignore newTrackPoint. Poor accuracy."); return; } - aggregatorGPS.add(observer.getNow(), position); - observer.onChange(); + super.onDataReceived(location); + } + + @NonNull + @Override + protected Driver createDriverInternal() { + return new GpsInternal(this); + } + + @NonNull + @Override + protected AggregatorGPS createAggregator(String sensorAddress, String sensorName) { + return new AggregatorGPS(sensorAddress, sensorName); + } + + @Override + protected int getSensorPreferenceKey() { + return R.string.settings_sensor_bluetooth_gps_key; + } + + @Override + protected String getSensorPreferenceDefaultValue() { + return SensorType.INTERNAL.getPreferenceValue(); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java index 2b2296c35..5a5154d95 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java @@ -31,7 +31,7 @@ class GpsStatusManager { private Duration signalLostThreshold; private GpsStatusValue gpsStatus = GpsStatusValue.GPS_NONE; - private GpsStatusListener client; + private GpsStatusListener observer; private final Context context; @Nullable @@ -44,8 +44,8 @@ class GpsStatusManager { }; - public GpsStatusManager(Context context, GpsStatusListener client, Handler handler) { - this.client = client; + public GpsStatusManager(Context context, GpsStatusListener observer, Handler handler) { + this.observer = observer; this.context = context; this.handler = handler; @@ -54,7 +54,7 @@ class GpsStatusManager { } public void start() { - client.onGpsStatusChanged(GpsStatusValue.GPS_ENABLED); + observer.onGpsStatusChanged(GpsStatusValue.GPS_ENABLED); } /** @@ -62,9 +62,7 @@ class GpsStatusManager { */ public void stop() { stopTimer(); - client.onGpsStatusChanged(GpsStatusValue.GPS_NONE); - client = null; - handler = null; + observer.onGpsStatusChanged(GpsStatusValue.GPS_NONE); } /** @@ -159,8 +157,8 @@ class GpsStatusManager { private void setGpsStatus(GpsStatusValue current) { gpsStatus = current; - if (client != null) { - client.onGpsStatusChanged(current); + if (observer != null) { + observer.onGpsStatusChanged(current); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index 7d2003b3f..a94036425 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -10,6 +10,7 @@ import java.time.Instant; import de.dennisguse.opentracks.sensors.driver.Driver; import de.dennisguse.opentracks.sensors.driver.DriverObserver; +import de.dennisguse.opentracks.sensors.driver.SensorType; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.settings.PreferencesUtils; @@ -19,7 +20,8 @@ public abstract class SensorHandler implement private final SensorManager sensorManager; - private Driver driver; + @VisibleForTesting + public Driver driver; protected Aggregator aggregator; @@ -30,7 +32,7 @@ public abstract class SensorHandler implement void connect() { disconnect(); - String address = PreferencesUtils.getString(getSensorPreferenceKey(), PreferencesUtils.getBluetoothSensorAddressNone()); + String address = PreferencesUtils.getString(getSensorPreferenceKey(), getSensorPreferenceDefaultValue()); switch (PreferencesUtils.getSensorType(address)) { case NONE -> { @@ -71,6 +73,10 @@ public abstract class SensorHandler implement protected abstract int getSensorPreferenceKey(); + protected String getSensorPreferenceDefaultValue() { + return SensorType.NONE.getPreferenceValue(); + } + protected Context getContext() { return sensorManager.getContext(); } @@ -106,6 +112,9 @@ public abstract class SensorHandler implement @Override public void onDataReceived(AggregatorInput value) { + if (aggregator == null) { + throw new RuntimeException("Received data while being disconnected."); + } SensorHandler.this.aggregator.add(sensorManager.getNow(), value); sensorManager.onChange(); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index eb850db69..6021848a7 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -20,7 +20,6 @@ import de.dennisguse.opentracks.data.models.Speed; 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; @@ -51,14 +50,14 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange private AltitudeChangeHandler altitudeChangeHandler; - private GpsManager gpsManager; + private GpsHandler gpsHandler; public SensorManager(TrackPointCreator observer) { this.observer = observer; } public void start(Context context, Handler handler) { - if (gpsManager != null) { + if (isStarted()) { throw new RuntimeException("SensorManager cannot be started twice; stop first."); } @@ -66,7 +65,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange this.context = context; this.handler = handler; - gpsManager = new GpsManager(observer, this); + gpsHandler = new GpsHandler(this, observer); altitudeChangeHandler = new AltitudeChangeHandler(this); heartRateHandler = new HeartRateHandler(this); temperatureHandler = new TemperatureHandler(this); @@ -76,8 +75,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this); onSharedPreferenceChanged(null, null); - - gpsManager.start(context, handler); } public void stop() { @@ -104,15 +101,15 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange altitudeChangeHandler.disconnect(); altitudeChangeHandler = null; - gpsManager.stop(); - gpsManager = null; + gpsHandler.disconnect(); + gpsHandler = null; context = null; handler = null; } public void reset() { - if (gpsManager == null || altitudeChangeHandler == null) { + if (gpsHandler == null || altitudeChangeHandler == null) { Log.d(TAG, "No recording running and no reset necessary."); return; } @@ -126,11 +123,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange cyclingPowerHandler.resetAggregated(); runningSpeedCadenceDistanceHandler.resetAggregated(); altitudeChangeHandler.resetAggregated(); - if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated(); + gpsHandler.resetAggregated(); } - public GpsManager getGpsManager() { - return gpsManager; + public GpsHandler getGpsHandler() { + return gpsHandler; } @Deprecated @@ -141,36 +138,38 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { - if (gpsManager != null) { - gpsManager.onSharedPreferenceChanged(sharedPreferences, key); + if (!isStarted()) return; - if (PreferencesUtils.isKey(altitudeChangeHandler.getSensorPreferenceKey(), key)) { - altitudeChangeHandler.connect(); - } + if (PreferencesUtils.isKey(gpsHandler.getSensorPreferenceKey(), key)) { + gpsHandler.connect(); + } - if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) { - heartRateHandler.connect(); - } + if (PreferencesUtils.isKey(altitudeChangeHandler.getSensorPreferenceKey(), key)) { + altitudeChangeHandler.connect(); + } - if (PreferencesUtils.isKey(temperatureHandler.getSensorPreferenceKey(), key)) { - temperatureHandler.connect(); - } + if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) { + heartRateHandler.connect(); + } - if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { - cyclingCadenceHandler.connect(); - } + if (PreferencesUtils.isKey(temperatureHandler.getSensorPreferenceKey(), key)) { + temperatureHandler.connect(); + } - if (PreferencesUtils.isKey(cyclingDistanceSpeedHandler.getSensorPreferenceKey(), key)) { - cyclingDistanceSpeedHandler.connect(); - } + if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { + cyclingCadenceHandler.connect(); + } - if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { - cyclingPowerHandler.connect(); - } + if (PreferencesUtils.isKey(cyclingDistanceSpeedHandler.getSensorPreferenceKey(), key)) { + cyclingDistanceSpeedHandler.connect(); + } - if (PreferencesUtils.isKey(runningSpeedCadenceDistanceHandler.getSensorPreferenceKey(), key)) { - runningSpeedCadenceDistanceHandler.connect(); - } + if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) { + cyclingPowerHandler.connect(); + } + + if (PreferencesUtils.isKey(runningSpeedCadenceDistanceHandler.getSensorPreferenceKey(), key)) { + runningSpeedCadenceDistanceHandler.connect(); } } @@ -251,10 +250,13 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange } public SensorDataSet getSensorDataSet(Instant now) { - AggregatorGPS gps = gpsManager.getAggregatorGPS(); + SensorData gpsSensorData = gpsHandler.getSensorData(now); + + var a = temperatureHandler.getSensorData(now); + var b = altitudeChangeHandler.getSensorData(now); return new SensorDataSet( - gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), + gpsSensorData != null ? gpsSensorData : new SensorData<>(Position.of(now), ""), //We always need a Position(now) getSpeed(now), getDistance(now), getHeartRate(now), @@ -291,11 +293,15 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange if (runningSpeedCadenceDistanceHandler != null) { runningSpeedCadenceDistanceHandler.setAggregator(null); } - if (this.gpsManager != null) { - this.gpsManager.setAggregatorGPS(); + if (this.gpsHandler != null) { + this.gpsHandler.setAggregator(null); } } + private boolean isStarted() { + return wakeLock != null; + } + @VisibleForTesting public void setAggregator(AggregatorHeartRate data) { heartRateHandler.setAggregator(data); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java index e3b088383..ad30977ef 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/BluetoothDriver.java @@ -41,6 +41,7 @@ import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; /** * Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications. */ +//TODO Re-act to Bluetooth disabled/enabled @SuppressLint("MissingPermission") public class BluetoothDriver implements Driver { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java index 4fda6d99d..538c5f48b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/DriverObserver.java @@ -22,4 +22,10 @@ public interface DriverObserver { */ //TODO check if really need this, because the driver was told to disconnect and then just signalizes that it finished this task. void onDisconnected(); + + /** + * The Driver detected that the sensor got deactivated. + * For example, the user deactivated the internal GPS. + */ + default void onSensorDeactivated() {} } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java index 77b668bf2..cb9316d56 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/driver/GpsInternal.java @@ -7,6 +7,7 @@ import android.os.Handler; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import androidx.core.location.LocationListenerCompat; import androidx.core.location.LocationManagerCompat; import androidx.core.location.LocationRequestCompat; @@ -18,9 +19,10 @@ public class GpsInternal implements Driver { private static final String TAG = GpsInternal.class.getSimpleName(); - private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER; + public static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER; - private final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() { + @VisibleForTesting + public final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() { @Override public void onLocationChanged(@NonNull Location location) { driverObserver.onDataReceived(location); @@ -33,13 +35,14 @@ public class GpsInternal implements Driver { @Override public void onProviderDisabled(@NonNull String provider) { - driverObserver.onConnectionLost(); + driverObserver.onSensorDeactivated(); } }; private final DriverObserver driverObserver; - private LocationManager locationManager; + @VisibleForTesting + public LocationManager locationManager; public GpsInternal(DriverObserver driverObserver) { this.driverObserver = driverObserver; @@ -62,8 +65,8 @@ public class GpsInternal implements Driver { if (PermissionRequester.GPS.hasPermission(context)) { try { Log.i(TAG, "Register for location updates " + context); - LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat); driverObserver.onConnected(null, null); + LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat); return; } catch (SecurityException e) { Log.e(TAG, "Could not register location listener; permissions not granted.", e); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index 4b5be814c..d61cd8a5a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -16,10 +16,6 @@ public abstract class Aggregator { private final String sensorAddress; private final String sensorName; - Aggregator(String sensorAddress) { - this(sensorAddress, null); - } - Aggregator(String sensorAddress, String sensorName) { this.sensorAddress = sensorAddress; this.sensorName = sensorName; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java index 62838e11d..af6731b86 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java @@ -1,21 +1,23 @@ package de.dennisguse.opentracks.sensors.sensorData; +import android.location.Location; + import androidx.annotation.NonNull; import java.time.Instant; import de.dennisguse.opentracks.data.models.Position; -public class AggregatorGPS extends Aggregator { +public class AggregatorGPS extends Aggregator { - public AggregatorGPS(String sensorAddress) { - super(sensorAddress); + public AggregatorGPS(String sensorAddress, String sensorName) { + super(sensorAddress, sensorName); } @Override - protected void computeValue(Raw current) { - aggregatedValue = current.value(); + protected void computeValue(Raw current) { + aggregatedValue = Position.of(current.value(), current.time()); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index ede4d04c8..8412b2266 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -253,10 +253,6 @@ public class PreferencesUtils { return isReportSpeed(track.activityTypeLocalized()); } - public static String getBluetoothSensorAddressNone() { - return SensorType.NONE.getPreferenceValue(); - } - public static SensorType getSensorType(String address) { return Arrays.stream(SensorType.values()) .filter(it -> it.getPreferenceValue().equals(address)) diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeGpsPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeGpsPreference.java new file mode 100644 index 000000000..56dc14f8d --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeGpsPreference.java @@ -0,0 +1,41 @@ +package de.dennisguse.opentracks.settings.bluetooth; + +import android.content.Context; +import android.location.LocationManager; +import android.util.AttributeSet; + +import androidx.core.location.LocationManagerCompat; +import androidx.preference.PreferenceDialogFragmentCompat; + +import java.util.List; + +import de.dennisguse.opentracks.sensors.driver.GpsInternal; + +public class BluetoothLeGpsPreference extends BluetoothLeSensorPreference { + + public BluetoothLeGpsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public BluetoothLeGpsPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public BluetoothLeGpsPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public BluetoothLeGpsPreference(Context context) { + super(context); + } + + @Override + public PreferenceDialogFragmentCompat createInstance() { + boolean hasInternalSensor = LocationManagerCompat.hasProvider((LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE), GpsInternal.LOCATION_PROVIDER); + + return BluetoothLeSensorPreferenceDialog + .newInstance(getKey(), List.of(), hasInternalSensor); + } + + +} \ No newline at end of file diff --git a/src/main/res/values/settings.xml b/src/main/res/values/settings.xml index 91f08907a..769c78495 100644 --- a/src/main/res/values/settings.xml +++ b/src/main/res/values/settings.xml @@ -26,6 +26,7 @@ bluetoothCyclingPowerSensor bluetoothRunningSpeedAndCadenceSensor bluetoothPressureSensor + bluetoothGPSSensor NONE INTERNAL diff --git a/src/main/res/xml/settings_sensors.xml b/src/main/res/xml/settings_sensors.xml index 582e1bcfe..ac18e1879 100644 --- a/src/main/res/xml/settings_sensors.xml +++ b/src/main/res/xml/settings_sensors.xml @@ -5,12 +5,15 @@ android:title="@string/settings_sensors_title"> + - + android:title="@string/settings_sensor_bluetooth_service_filter_title" /> \ No newline at end of file From 14cebf3fec0b9e3b0a43be6f1e7981f4923637f7 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sun, 18 Jan 2026 18:38:46 +0100 Subject: [PATCH 29/30] Aggregator: there are no default values anymore. --- .../sensorData/AggregatorBarometerTest.java | 4 +- .../sensorData/SensorDataCyclingTest.java | 7 ++- .../sensors/sensorData/Aggregator.java | 47 ++++++++----------- .../sensorData/AggregatorBarometer.java | 19 +++----- .../sensorData/AggregatorCyclingCadence.java | 22 ++------- .../AggregatorCyclingDistanceSpeed.java | 26 ++++------ .../sensorData/AggregatorCyclingPower.java | 19 +------- .../sensors/sensorData/AggregatorGPS.java | 22 +++------ .../sensorData/AggregatorHeartRate.java | 19 +------- .../sensors/sensorData/AggregatorRunning.java | 26 +++++----- .../sensorData/AggregatorTemperature.java | 15 +----- .../sensors/sensorData/SensorData.java | 4 ++ 12 files changed, 70 insertions(+), 160 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java index c3960161e..27466970d 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometerTest.java @@ -24,7 +24,7 @@ public class AggregatorBarometerTest { addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f}); // then - Assert.assertEquals(0f, subject.aggregatedValue.gain_m(), 0.01); - Assert.assertEquals(15f, subject.aggregatedValue.loss_m(), 0.01); + Assert.assertEquals(0f, subject.output.gain_m(), 0.01); + Assert.assertEquals(15f, subject.output.loss_m(), 0.01); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java index 51b41cd15..f7f06e13e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingTest.java @@ -2,6 +2,7 @@ package de.dennisguse.opentracks.sensors.sensorData; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -12,7 +13,6 @@ import java.time.Instant; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; -import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.sensors.UintUtils; import de.dennisguse.opentracks.sensors.driver.CyclingCadenceBluetooth; import de.dennisguse.opentracks.sensors.driver.CyclingDistanceSpeedBluetooth; @@ -93,7 +93,7 @@ public class SensorDataCyclingTest { // then // TODO See #953 // assertEquals(60, current.getValue().getRPM(), 0.01); - assertEquals(Cadence.of(0), current.getAggregatedValue(Instant.MIN)); + assertNull(current.getAggregatedValue(Instant.MIN)); } @Test @@ -120,11 +120,10 @@ public class SensorDataCyclingTest { current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(UintUtils.UINT32_MAX - 1, 1024)); current.add(Instant.MIN, new CyclingDistanceSpeedBluetooth.WheelData(0, 2048)); - // then // TODO See #953 // assertEquals(2, current.getValue().getDistance().toM(), 0.01); // assertEquals(2, current.getValue().getSpeed().toMPS(), 0.01); - assertEquals(new AggregatorCyclingDistanceSpeed.Data(Distance.ZERO, Distance.ZERO, Speed.ZERO), current.getAggregatedValue(Instant.MIN)); + assertNull(current.getAggregatedValue(Instant.MIN)); } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index d61cd8a5a..0cec85cc3 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -1,17 +1,20 @@ package de.dennisguse.opentracks.sensors.sensorData; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.time.Duration; import java.time.Instant; -public abstract class Aggregator { +public abstract class Aggregator { private static final Duration MAX_SENSOR_DATE_SET_AGE = Duration.ofSeconds(5); - protected Raw previous; + @Nullable + protected Raw previous; - protected Output aggregatedValue; + //TODO Make private + protected OutputType output; private final String sensorAddress; private final String sensorName; @@ -25,57 +28,47 @@ public abstract class Aggregator { return sensorName != null ? sensorName : sensorAddress; } - public final void add(Instant now, Input current) { - Raw next = new Raw<>(now, current); + public final void add(Instant now, InputType current) { + Raw next = new Raw<>(now, current); computeValue(next); previous = next; } - protected abstract void computeValue(Raw current); + protected abstract void computeValue(Raw current); /** * @return did we process data from a sensor. * NOTE: for some sensors this may require more than one measurement. */ public boolean hasReceivedData() { - return aggregatedValue != null; + return output != null; } - @Deprecated //TODO Remove: for sensor there is no default value. Make getAggregatedValue() @Nullable - @NonNull - 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 - public Output getAggregatedValue(Instant now) { - if (!hasReceivedData()) { - return getNoneValue(); - } + @Nullable + protected OutputType getAggregatedValue(Instant now) { if (isOutdated(now)) { - resetImmediate(); + resetOutdated(); } - return aggregatedValue; + return output; } @NonNull - public SensorData getAggregatedValueWithSensorName(Instant now) { + public SensorData getAggregatedValueWithSensorName(Instant now) { return new SensorData<>(getAggregatedValue(now), getSensorNameOrAddress()); } /** * Reset short-term (i.e., non-aggregated) values that were directly derived from sensor data. */ - protected abstract void resetImmediate(); + protected void resetOutdated() { + output = null; + }; /** * Reset long-term (i.e., aggregated) values (more than derived from previous SensorData) like overall distance. */ - public abstract void resetAggregated(); + public void resetAggregated() {}; /** * Is the data recent considering the current time. @@ -99,7 +92,7 @@ public abstract class Aggregator { @NonNull @Override public String toString() { - return "sensorAddress=" + sensorAddress + " data=" + aggregatedValue; + return "sensorAddress=" + sensorAddress + " data=" + output; } protected record Raw( diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometer.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometer.java index bd6b1b017..c5b9be679 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometer.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorBarometer.java @@ -1,7 +1,5 @@ package de.dennisguse.opentracks.sensors.sensorData; -import androidx.annotation.NonNull; - import de.dennisguse.opentracks.data.models.Altitude; import de.dennisguse.opentracks.data.models.AltitudeGainLoss; import de.dennisguse.opentracks.data.models.AtmosphericPressure; @@ -19,31 +17,28 @@ public class AggregatorBarometer extends Aggregator current) { if (previous == null) { lastAcceptedSensorValue = current.value(); - aggregatedValue = getNoneValue(); + output = new AltitudeGainLoss(0f, 0f); return; } PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChangesWithSmoothing_m(lastAcceptedSensorValue, previous.value(), current.value()); if (altitudeChange != null) { - aggregatedValue = new AltitudeGainLoss(aggregatedValue.gain_m() + altitudeChange.getAltitudeGain_m(), aggregatedValue.loss_m() + altitudeChange.getAltitudeLoss_m()); + if (output == null) { + output = new AltitudeGainLoss(0f, 0f); + } + output = new AltitudeGainLoss(output.gain_m() + altitudeChange.getAltitudeGain_m(), output.loss_m() + altitudeChange.getAltitudeLoss_m()); lastAcceptedSensorValue = altitudeChange.currentSensorValue(); } } @Override - protected void resetImmediate() { + protected void resetOutdated() { } @Override public void resetAggregated() { - aggregatedValue = getNoneValue(); - } - - @NonNull - @Override - protected AltitudeGainLoss getNoneValue() { - return new AltitudeGainLoss(0f, 0f); + output = null; } public record Data(Altitude gain, Altitude loss) {} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java index 6f109d8e9..7cb7c21fa 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorCyclingCadence.java @@ -2,8 +2,6 @@ package de.dennisguse.opentracks.sensors.sensorData; import android.util.Log; -import androidx.annotation.NonNull; - import java.time.Duration; import de.dennisguse.opentracks.data.models.Cadence; @@ -32,32 +30,18 @@ public class AggregatorCyclingCadence extends Aggregator current) { - this.aggregatedValue = current.value().power(); - } - - @Override - protected void resetImmediate() { - aggregatedValue = getNoneValue(); - } - - @Override - public void resetAggregated() { - } - - @NonNull - @Override - protected Power getNoneValue() { - return Power.of(0f); + this.output = current.value().power(); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java index af6731b86..f57f3bbfb 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java @@ -10,19 +10,13 @@ import de.dennisguse.opentracks.data.models.Position; public class AggregatorGPS extends Aggregator { - public AggregatorGPS(String sensorAddress, String sensorName) { super(sensorAddress, sensorName); } @Override protected void computeValue(Raw current) { - aggregatedValue = Position.of(current.value(), current.time()); - } - - @Override - protected void resetImmediate() { - aggregatedValue = Position.empty(); + output = Position.of(current.value(), current.time()); } @Override @@ -32,19 +26,15 @@ public class AggregatorGPS extends Aggregator { * The data is too large to save it more often than needed (i.e., duplicated values). * TODO: this behavior can be changed if TrackRecordingManager.insertTrackPoint() would strip GPS data if it was already saved. This would simplify TrackPointCreator.createCurrentTrackPoint() */ - aggregatedValue = Position.empty(); - } - - @NonNull - @Override - protected Position getNoneValue() { - return Position.empty(); + output = null; } @NonNull @Override public Position getAggregatedValue(Instant now) { - return super.getAggregatedValue(now) - .with(now); + Position value = super.getAggregatedValue(now); + if (value == null) value = Position.empty(); + + return value.with(now); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorHeartRate.java index 22c7bea24..b7bc6ad9d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorHeartRate.java @@ -1,7 +1,5 @@ package de.dennisguse.opentracks.sensors.sensorData; -import androidx.annotation.NonNull; - import de.dennisguse.opentracks.data.models.HeartRate; public class AggregatorHeartRate extends Aggregator { @@ -13,22 +11,7 @@ public class AggregatorHeartRate extends Aggregator { @Override protected void computeValue(Raw current) { if (current.value().isValid()) { - this.aggregatedValue = current.value(); + this.output = current.value(); } } - - @Override - protected void resetImmediate() { - aggregatedValue = getNoneValue(); - } - - @Override - public void resetAggregated() { - } - - @NonNull - @Override - protected HeartRate getNoneValue() { - return HeartRate.of(0); - } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java index 8cdf81b93..a5c7bc34e 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorRunning.java @@ -27,33 +27,31 @@ public final class AggregatorRunning extends Aggregator } protected void computeValue(Raw current) { - this.aggregatedValue = current.value(); + this.output = current.value(); } - @NonNull - protected Temperature getNoneValue() { - return Temperature.ofCentiCelsius(0); - } - - protected void resetImmediate() { - aggregatedValue = getNoneValue(); - } - - public void resetAggregated() {}; - @Override protected Duration getMaxSensorAge() { return Duration.ofMinutes(1); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java index 104bf718a..7758b02f1 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java @@ -1,7 +1,11 @@ package de.dennisguse.opentracks.sensors.sensorData; +import androidx.annotation.Nullable; + public record SensorData( + + @Nullable T data, String sensorNameOrAddress From 60e2fe57f92fdbab15bf8e6466ee4fd1dd59fa7c Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 10 Feb 2026 18:11:51 +0100 Subject: [PATCH 30/30] Bugfix: SensorHandler may receive a connectionLost from BluetoothDriver without being connected first. --- .../de/dennisguse/opentracks/sensors/SensorHandler.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java index a94036425..31433932d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorHandler.java @@ -1,6 +1,7 @@ package de.dennisguse.opentracks.sensors; import android.content.Context; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -18,6 +19,8 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; public abstract class SensorHandler implements DriverObserver { + private static final String TAG = SensorHandler.class.getSimpleName(); + private final SensorManager sensorManager; @VisibleForTesting @@ -107,6 +110,11 @@ public abstract class SensorHandler implement @Override public void onConnectionLost() { + if (SensorHandler.this.aggregator == null) { + Log.d(TAG, "Connection lost, but where not connected."); + return; + } + SensorHandler.this.aggregator.resetAggregated(); }