From 4d54472c930132902b06f4ce5cfd31cb749e2d26 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sun, 5 Nov 2023 14:15:02 +0100 Subject: [PATCH] Bluetooth: use composition instead of inheritance. Part of #1424. --- .../sensors/BluetoothUtilsTest.java | 16 +++--- ...r.java => BluetoothConnectionManager.java} | 37 +++++-------- ...etoothConnectionManagerCyclingCadence.java | 47 ---------------- ...ConnectionManagerCyclingDistanceSpeed.java | 24 +++++---- ...luetoothConnectionManagerCyclingPower.java | 23 +++++--- .../BluetoothConnectionManagerHeartRate.java | 32 ++++++++--- ...toothConnectionRunningSpeedAndCadence.java | 21 +++++--- .../BluetoothHandlerCyclingCadence.java | 53 +++++++++++++++++++ .../sensors/BluetoothRemoteSensorManager.java | 22 ++++---- .../opentracks/sensors/BluetoothUtils.java | 36 ------------- .../sensorData/SensorHandlerInterface.java | 17 ++++++ .../BluetoothLeCyclingCadencePreference.java | 4 +- .../BluetoothLeCyclingPowerPreference.java | 4 +- .../BluetoothLeCyclingSpeedPreference.java | 4 +- .../BluetoothLeHeartRatePreference.java | 4 +- ...othLeRunningSpeedAndCadencePreference.java | 4 +- 16 files changed, 185 insertions(+), 163 deletions(-) rename src/main/java/de/dennisguse/opentracks/sensors/{AbstractBluetoothConnectionManager.java => BluetoothConnectionManager.java} (80%) delete mode 100644 src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingCadence.java create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java create mode 100644 src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java index 92dc59f21..73d523249 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java @@ -21,7 +21,7 @@ public class BluetoothUtilsTest { @Test public void parseHeartRate_uint8() { // given - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerHeartRate.HEARTRATE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x02, 0x3C}); // when @@ -34,7 +34,7 @@ public class BluetoothUtilsTest { @Test public void parseHeartRate_uint16() { // given - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerHeartRate.HEARTRATE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x01, 0x01, 0x01}); // when @@ -59,7 +59,7 @@ public class BluetoothUtilsTest { @Test public void parseCyclingSpeedCadence_crankOnly() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x02, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99}); // when @@ -72,7 +72,7 @@ public class BluetoothUtilsTest { @Test public void parseCyclingSpeedCadence_wheelOnly() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, 0, 1, 0x45, (byte) 0x99}); // when @@ -85,7 +85,7 @@ public class BluetoothUtilsTest { @Test public void parseCyclingSpeedCadence_crankWheel() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerCyclingDistanceSpeed.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 @@ -98,7 +98,7 @@ public class BluetoothUtilsTest { @Test public void parseCyclingPower_power() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0, 0, 40, 0}); // when @@ -110,7 +110,7 @@ public class BluetoothUtilsTest { @Test public void parseCyclingPower_power_with_cadence() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionManagerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{0x2C, 0x00, 0x00, 0x00, (byte) 0x9F, 0x00, 0x0C, 0x00, (byte) 0xE5, 0x42}); // when @@ -125,7 +125,7 @@ public class BluetoothUtilsTest { @Test public void parseRunningSpeedAndCadence_with_distance() { - BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.RUNNING_SPEED_CADENCE.serviceUUID(), 0, 0); + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothConnectionRunningSpeedAndCadence.RUNNING_SPEED_CADENCE.serviceUUID(), 0, 0); characteristic.setValue(new byte[]{2, 0, 5, 80, (byte) 0xFF, (byte) 0xFF, 0, 1}); // when diff --git a/src/main/java/de/dennisguse/opentracks/sensors/AbstractBluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java similarity index 80% rename from src/main/java/de/dennisguse/opentracks/sensors/AbstractBluetoothConnectionManager.java rename to src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java index 97cf4147c..dd2640b72 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/AbstractBluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java @@ -30,23 +30,23 @@ 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.sensorData.SensorData; +import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; /** * Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications. */ @SuppressLint("MissingPermission") -public abstract class AbstractBluetoothConnectionManager { +public class BluetoothConnectionManager { - private static final String TAG = AbstractBluetoothConnectionManager.class.getSimpleName(); + private static final String TAG = BluetoothConnectionManager.class.getSimpleName(); private final SensorManager.SensorDataChangedObserver observer; - private final List serviceMeasurementUUIDs; + private final SensorHandlerInterface sensorHandler; private BluetoothGatt bluetoothGatt; private final BluetoothGattCallback connectCallback = new BluetoothGattCallback() { @@ -76,7 +76,7 @@ public abstract class AbstractBluetoothConnectionManager { public void onServicesDiscovered(@NonNull BluetoothGatt gatt, int status) { BluetoothGattService gattService = null; ServiceMeasurementUUID serviceMeasurement = null; - for (ServiceMeasurementUUID s : serviceMeasurementUUIDs) { + for (ServiceMeasurementUUID s : sensorHandler.getServices()) { gattService = gatt.getService(s.serviceUUID()); if (gattService != null) { serviceMeasurement = s; @@ -112,24 +112,22 @@ public abstract class AbstractBluetoothConnectionManager { public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic) { UUID serviceUUID = characteristic.getService().getUuid(); Log.d(TAG, "Received data from " + gatt.getDevice().getAddress() + " with service " + serviceUUID + " and characteristics " + characteristic.getUuid()); - Optional serviceMeasurementUUID = serviceMeasurementUUIDs.stream() - .filter(s -> s.serviceUUID().equals(characteristic.getService().getUuid())).findFirst(); + Optional serviceMeasurementUUID = sensorHandler.getServices() + .stream() + .filter(s -> s.serviceUUID().equals(characteristic.getService().getUuid())) + .findFirst(); if (serviceMeasurementUUID.isEmpty()) { Log.e(TAG, "Unknown service UUID; not supported?"); return; } - SensorData sensorData = parsePayload(serviceMeasurementUUID.get(), gatt.getDevice().getName(), gatt.getDevice().getAddress(), characteristic); - if (sensorData != null) { - Log.d(TAG, "Decoded data from " + gatt.getDevice().getAddress() + ": " + sensorData); - observer.onChange(sensorData); - } + sensorHandler.handlePayload(observer, serviceMeasurementUUID.get(), gatt.getDevice().getName(), gatt.getDevice().getAddress(), characteristic); } }; - AbstractBluetoothConnectionManager(List serviceUUUID, SensorManager.SensorDataChangedObserver observer) { - this.serviceMeasurementUUIDs = serviceUUUID; + BluetoothConnectionManager(SensorManager.SensorDataChangedObserver observer, SensorHandlerInterface sensorHandler) { this.observer = observer; + this.sensorHandler = sensorHandler; } synchronized void connect(Context context, Handler handler, @NonNull BluetoothDevice device) { @@ -142,12 +140,12 @@ public abstract class AbstractBluetoothConnectionManager { bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler); - SensorData sensorData = createEmptySensorData(bluetoothGatt.getDevice().getAddress()); + SensorData sensorData = sensorHandler.createEmptySensorData(bluetoothGatt.getDevice().getAddress()); observer.onChange(sensorData); } private synchronized void clearData() { - observer.onDisconnect(createEmptySensorData(bluetoothGatt.getDevice().getAddress())); + observer.onDisconnect(sensorHandler.createEmptySensorData(bluetoothGatt.getDevice().getAddress())); } synchronized void disconnect() { @@ -167,11 +165,4 @@ public abstract class AbstractBluetoothConnectionManager { return address.equals(bluetoothGatt.getDevice().getAddress()); } - - protected abstract SensorData createEmptySensorData(String address); - - /** - * @return null if data could not be parsed. - */ - protected abstract SensorData parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, @NonNull BluetoothGattCharacteristic characteristic); } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingCadence.java deleted file mode 100644 index 0b2353264..000000000 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingCadence.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.dennisguse.opentracks.sensors; - -import android.bluetooth.BluetoothGattCharacteristic; -import android.util.Log; - -import de.dennisguse.opentracks.data.models.Cadence; -import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence; -import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed; -import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower; - -public class BluetoothConnectionManagerCyclingCadence extends AbstractBluetoothConnectionManager { - - private static final String TAG = BluetoothConnectionManagerCyclingCadence.class.getSimpleName(); - - BluetoothConnectionManagerCyclingCadence(SensorManager.SensorDataChangedObserver observer) { - super(BluetoothUtils.CYCLING_CADENCE, observer); - } - - @Override - protected SensorDataCyclingCadence createEmptySensorData(String address) { - return new SensorDataCyclingCadence(address); - } - - @Override - protected SensorDataCyclingCadence parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - - //TODO Implement to ServiceMeasurement.parse()? - if (serviceMeasurementUUID.equals(BluetoothUtils.CYCLING_POWER)) { - SensorDataCyclingPower.Data data = BluetoothUtils.parseCyclingPower(address, sensorName, characteristic); - if (data!= null) { - return data.cadence(); - } - } else if (serviceMeasurementUUID.equals(BluetoothUtils.CYCLING_SPEED_CADENCE)) { - SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic); - if (cadenceAndSpeed == null) { - return null; - } - - if (cadenceAndSpeed.getCadence() != null) { - return cadenceAndSpeed.getCadence(); - } - } - - Log.e(TAG, "Don't know how to decode this payload."); - return null; - } -} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingDistanceSpeed.java index 8334d69a3..eb8dad423 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingDistanceSpeed.java @@ -3,32 +3,38 @@ package de.dennisguse.opentracks.sensors; import android.bluetooth.BluetoothGattCharacteristic; import java.util.List; +import java.util.UUID; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed; +import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; -public class BluetoothConnectionManagerCyclingDistanceSpeed extends AbstractBluetoothConnectionManager { +public class BluetoothConnectionManagerCyclingDistanceSpeed implements SensorHandlerInterface { - BluetoothConnectionManagerCyclingDistanceSpeed(SensorManager.SensorDataChangedObserver observer) { - super(List.of(BluetoothUtils.CYCLING_SPEED_CADENCE), observer); + public static final ServiceMeasurementUUID CYCLING_SPEED_CADENCE = new ServiceMeasurementUUID( + new UUID(0x181600001000L, 0x800000805f9b34fbL), + new UUID(0x2A5B00001000L, 0x800000805f9b34fbL) + ); + + @Override + public List getServices() { + return List.of(CYCLING_SPEED_CADENCE); } @Override - protected SensorDataCyclingDistanceSpeed createEmptySensorData(String address) { + public SensorDataCyclingDistanceSpeed createEmptySensorData(String address) { return new SensorDataCyclingDistanceSpeed(address); } @Override - protected SensorDataCyclingDistanceSpeed parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic); if (cadenceAndSpeed == null) { - return null; + return; } if (cadenceAndSpeed.getDistanceSpeed() != null) { - return cadenceAndSpeed.getDistanceSpeed(); + observer.onChange(cadenceAndSpeed.getDistanceSpeed()); } - - return null; } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingPower.java index 5ca3f089a..e5b94ccfb 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerCyclingPower.java @@ -5,25 +5,34 @@ import android.bluetooth.BluetoothGattCharacteristic; import androidx.annotation.NonNull; import java.util.List; +import java.util.UUID; -import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower; +import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; -public class BluetoothConnectionManagerCyclingPower extends AbstractBluetoothConnectionManager { +public class BluetoothConnectionManagerCyclingPower implements SensorHandlerInterface { - BluetoothConnectionManagerCyclingPower(@NonNull SensorManager.SensorDataChangedObserver observer) { - super(List.of(BluetoothUtils.CYCLING_POWER), observer); + public static final ServiceMeasurementUUID CYCLING_POWER = new ServiceMeasurementUUID( + new UUID(0x181800001000L, 0x800000805f9b34fbL), + new UUID(0x2A6300001000L, 0x800000805f9b34fbL) + ); + + @Override + public List getServices() { + return List.of(CYCLING_POWER); } @Override - protected SensorDataCyclingPower createEmptySensorData(String address) { + public SensorDataCyclingPower createEmptySensorData(String address) { return new SensorDataCyclingPower(address); } @Override - protected SensorDataCyclingPower parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { SensorDataCyclingPower.Data cyclingPower = BluetoothUtils.parseCyclingPower(address, sensorName, characteristic); - return cyclingPower != null ? cyclingPower.power() : null; + if (cyclingPower != null) { + observer.onChange(cyclingPower.power()); + } } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerHeartRate.java index de9882742..ad13326c2 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManagerHeartRate.java @@ -5,25 +5,45 @@ import android.bluetooth.BluetoothGattCharacteristic; import androidx.annotation.NonNull; import java.util.List; +import java.util.UUID; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.sensors.sensorData.SensorDataHeartRate; +import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; -public class BluetoothConnectionManagerHeartRate extends AbstractBluetoothConnectionManager { +public class BluetoothConnectionManagerHeartRate implements SensorHandlerInterface { - BluetoothConnectionManagerHeartRate(@NonNull SensorManager.SensorDataChangedObserver observer) { - super(List.of(BluetoothUtils.HEARTRATE), observer); + public static final ServiceMeasurementUUID HEARTRATE = new ServiceMeasurementUUID( + new UUID(0x180D00001000L, 0x800000805f9b34fbL), + new UUID(0x2A3700001000L, 0x800000805f9b34fbL) + ); + + // Used for device discovery in preferences + public static final List HEART_RATE_SUPPORTING_DEVICES = List.of( + HEARTRATE, + //Devices that support HEART_RATE_SERVICE_UUID, but do not announce HEART_RATE_SERVICE_UUID in there BLE announcement messages (during device discovery). + new ServiceMeasurementUUID( + UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb"), //Miband3 + HEARTRATE.measurementUUID() + ) + ); + + @Override + public List getServices() { + return HEART_RATE_SUPPORTING_DEVICES; } @Override - protected SensorDataHeartRate createEmptySensorData(String address) { + public SensorDataHeartRate createEmptySensorData(String address) { return new SensorDataHeartRate(address); } @Override - protected SensorDataHeartRate parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { HeartRate heartRate = BluetoothUtils.parseHeartRate(characteristic); - return heartRate != null ? new SensorDataHeartRate(address, sensorName, heartRate) : null; + if (heartRate != null) { + observer.onChange(new SensorDataHeartRate(address, sensorName, heartRate)); + } } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionRunningSpeedAndCadence.java index cb97166d7..68fb1ff41 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionRunningSpeedAndCadence.java @@ -5,22 +5,31 @@ import android.bluetooth.BluetoothGattCharacteristic; import androidx.annotation.NonNull; import java.util.List; +import java.util.UUID; import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning; +import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface; -public class BluetoothConnectionRunningSpeedAndCadence extends AbstractBluetoothConnectionManager { +public class BluetoothConnectionRunningSpeedAndCadence implements SensorHandlerInterface { - BluetoothConnectionRunningSpeedAndCadence(@NonNull SensorManager.SensorDataChangedObserver observer) { - super(List.of(BluetoothUtils.RUNNING_SPEED_CADENCE), observer); + + public static final ServiceMeasurementUUID RUNNING_SPEED_CADENCE = new ServiceMeasurementUUID( + new UUID(0x181400001000L, 0x800000805f9b34fbL), + new UUID(0x2A5300001000L, 0x800000805f9b34fbL) + ); + + @Override + public List getServices() { + return List.of(RUNNING_SPEED_CADENCE); } @Override - protected SensorDataRunning createEmptySensorData(String address) { + public SensorDataRunning createEmptySensorData(String address) { return new SensorDataRunning(address); } @Override - protected SensorDataRunning parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { - return BluetoothUtils.parseRunningSpeedAndCadence(address, sensorName, characteristic); + public void handlePayload(SensorManager.SensorDataChangedObserver observer, @NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + observer.onChange(BluetoothUtils.parseRunningSpeedAndCadence(address, sensorName, characteristic)); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java new file mode 100644 index 000000000..625a686cb --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothHandlerCyclingCadence.java @@ -0,0 +1,53 @@ +package de.dennisguse.opentracks.sensors; + +import android.bluetooth.BluetoothGattCharacteristic; +import android.util.Log; + +import java.util.List; + +import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence; +import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadenceAndDistanceSpeed; +import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower; +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( + BluetoothConnectionManagerCyclingPower.CYCLING_POWER, + BluetoothConnectionManagerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE + ); + + @Override + public List getServices() { + return CYCLING_CADENCE; + } + + @Override + public SensorDataCyclingCadence createEmptySensorData(String address) { + return new SensorDataCyclingCadence(address); + } + + @Override + public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + + //TODO Implement to ServiceMeasurement.parse()? + if (serviceMeasurementUUID.equals(BluetoothConnectionManagerCyclingPower.CYCLING_POWER)) { + SensorDataCyclingPower.Data data = BluetoothUtils.parseCyclingPower(address, sensorName, characteristic); + if (data!= null) { + observer.onChange(data.cadence()); + } + } else if (serviceMeasurementUUID.equals(BluetoothConnectionManagerCyclingDistanceSpeed.CYCLING_SPEED_CADENCE)) { + SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic); + if (cadenceAndSpeed == null) { + return; + } + + if (cadenceAndSpeed.getCadence() != null) { + observer.onChange(cadenceAndSpeed.getCadence()); + } + } + + Log.e(TAG, "Don't know how to decode this payload."); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java index 5dad69260..c62b3d57c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManager.java @@ -57,22 +57,22 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref private final Handler handler; private boolean started = false; - private final BluetoothConnectionManagerHeartRate heartRate; - private final BluetoothConnectionManagerCyclingCadence cyclingCadence; - private final BluetoothConnectionManagerCyclingDistanceSpeed cyclingSpeed; - private final BluetoothConnectionManagerCyclingPower cyclingPower; - private final BluetoothConnectionRunningSpeedAndCadence runningSpeedAndCadence; + private final BluetoothConnectionManager heartRate; + 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 SensorManager.SensorDataChangedObserver observer) { this.context = context; this.handler = handler; bluetoothAdapter = BluetoothUtils.getAdapter(context); - this.heartRate = new BluetoothConnectionManagerHeartRate(observer); - this.cyclingCadence = new BluetoothConnectionManagerCyclingCadence(observer); - this.cyclingSpeed = new BluetoothConnectionManagerCyclingDistanceSpeed(observer); - this.cyclingPower = new BluetoothConnectionManagerCyclingPower(observer); - this.runningSpeedAndCadence = new BluetoothConnectionRunningSpeedAndCadence(observer); + this.heartRate = new BluetoothConnectionManager(observer, new BluetoothConnectionManagerHeartRate()); + this.cyclingCadence = new BluetoothConnectionManager(observer, new BluetoothConnectionManagerCyclingDistanceSpeed()); + this.cyclingSpeed = new BluetoothConnectionManager(observer, new BluetoothConnectionManagerCyclingDistanceSpeed()); + this.cyclingPower = new BluetoothConnectionManager(observer, new BluetoothConnectionManagerCyclingPower()); + this.runningSpeedAndCadence = new BluetoothConnectionManager(observer, new BluetoothConnectionRunningSpeedAndCadence()); } @@ -99,7 +99,7 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref return bluetoothAdapter != null && bluetoothAdapter.isEnabled(); } - private synchronized void connect(AbstractBluetoothConnectionManager connectionManager, String address) { + private synchronized void connect(BluetoothConnectionManager connectionManager, String address) { if (!isEnabled()) { Log.w(TAG, "Bluetooth not enabled."); return; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java index 48e0bb296..33d0a712a 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java @@ -23,7 +23,6 @@ import android.util.Log; import androidx.annotation.NonNull; -import java.util.List; import java.util.UUID; import de.dennisguse.opentracks.data.models.AtmosphericPressure; @@ -53,47 +52,12 @@ public class BluetoothUtils { new UUID(0x2A1900001000L, 0x800000805f9b34fbL) ); - public static final ServiceMeasurementUUID HEARTRATE = new ServiceMeasurementUUID( - new UUID(0x180D00001000L, 0x800000805f9b34fbL), - new UUID(0x2A3700001000L, 0x800000805f9b34fbL) - ); - - // Used for device discovery in preferences - public static final List HEART_RATE_SUPPORTING_DEVICES = List.of( - HEARTRATE, - //Devices that support HEART_RATE_SERVICE_UUID, but do not announce HEART_RATE_SERVICE_UUID in there BLE announcement messages (during device discovery). - new ServiceMeasurementUUID( - UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb"), //Miband3 - HEARTRATE.measurementUUID() - ) - ); - private static final UUID ENVIRONMENTAL_SENSING_SERVICE = new UUID(0x181A00001000L, 0x800000805f9b34fbL); public static final ServiceMeasurementUUID BAROMETRIC_PRESSURE = new ServiceMeasurementUUID( ENVIRONMENTAL_SENSING_SERVICE, new UUID(0x2A6D00001000L, 0x800000805f9b34fbL) ); - public static final ServiceMeasurementUUID CYCLING_POWER = new ServiceMeasurementUUID( - new UUID(0x181800001000L, 0x800000805f9b34fbL), - new UUID(0x2A6300001000L, 0x800000805f9b34fbL) - ); - - public static final ServiceMeasurementUUID CYCLING_SPEED_CADENCE = new ServiceMeasurementUUID( - new UUID(0x181600001000L, 0x800000805f9b34fbL), - new UUID(0x2A5B00001000L, 0x800000805f9b34fbL) - ); - - public static final List CYCLING_CADENCE = List.of( - CYCLING_POWER, - CYCLING_SPEED_CADENCE - ); - - public static final ServiceMeasurementUUID RUNNING_SPEED_CADENCE = new ServiceMeasurementUUID( - new UUID(0x181400001000L, 0x800000805f9b34fbL), - new UUID(0x2A5300001000L, 0x800000805f9b34fbL) - ); - private static final String TAG = BluetoothUtils.class.getSimpleName(); private BluetoothUtils() { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java new file mode 100644 index 000000000..215b86dab --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorHandlerInterface.java @@ -0,0 +1,17 @@ +package de.dennisguse.opentracks.sensors.sensorData; + +import android.bluetooth.BluetoothGattCharacteristic; + +import java.util.List; + +import de.dennisguse.opentracks.sensors.SensorManager; +import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID; + +public interface SensorHandlerInterface { + + List getServices(); + + SensorData createEmptySensorData(String address); + + void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic); +} 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 bf9577621..ce0d9a2f7 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.BluetoothUtils; +import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence; public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPrefer @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.CYCLING_CADENCE); + return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothHandlerCyclingCadence.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 af020ce07..adfbcd143 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingPowerPreference.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import androidx.preference.PreferenceDialogFragmentCompat; -import de.dennisguse.opentracks.sensors.BluetoothUtils; +import de.dennisguse.opentracks.sensors.BluetoothConnectionManagerCyclingPower; public class BluetoothLeCyclingPowerPreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeCyclingPowerPreference extends BluetoothLeSensorPreferen @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.CYCLING_POWER); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothConnectionManagerCyclingPower.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 db918d97d..1938a17e9 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import androidx.preference.PreferenceDialogFragmentCompat; -import de.dennisguse.opentracks.sensors.BluetoothUtils; +import de.dennisguse.opentracks.sensors.BluetoothConnectionManagerCyclingDistanceSpeed; public class BluetoothLeCyclingSpeedPreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeCyclingSpeedPreference extends BluetoothLeSensorPreferen @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.CYCLING_SPEED_CADENCE); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothConnectionManagerCyclingDistanceSpeed.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 db6df1979..dbb88fe44 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.BluetoothUtils; +import de.dennisguse.opentracks.sensors.BluetoothConnectionManagerHeartRate; public class BluetoothLeHeartRatePreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeHeartRatePreference extends BluetoothLeSensorPreference @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.HEART_RATE_SUPPORTING_DEVICES); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothConnectionManagerHeartRate.HEART_RATE_SUPPORTING_DEVICES); } } \ 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 856c79b92..14563972e 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeRunningSpeedAndCadencePreference.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import androidx.preference.PreferenceDialogFragmentCompat; -import de.dennisguse.opentracks.sensors.BluetoothUtils; +import de.dennisguse.opentracks.sensors.BluetoothConnectionRunningSpeedAndCadence; public class BluetoothLeRunningSpeedAndCadencePreference extends BluetoothLeSensorPreference { @@ -27,6 +27,6 @@ public class BluetoothLeRunningSpeedAndCadencePreference extends BluetoothLeSens @Override public PreferenceDialogFragmentCompat createInstance() { - return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.RUNNING_SPEED_CADENCE); + return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothConnectionRunningSpeedAndCadence.RUNNING_SPEED_CADENCE); } }