diff --git a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java index 4cad4a8d9..fd0f00014 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/sensors/BluetoothUtilsTest.java @@ -87,10 +87,10 @@ public class BluetoothUtilsTest { characteristic.setValue(new byte[]{0, 0, 40, 0}); // when - SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower(characteristic); + SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower("", "", characteristic); // then - assertEquals(40, powerCadence.getPower().getW(), 0.01); + assertEquals(40, powerCadence.getPower().getValue().getW(), 0.01); } @Test @@ -99,10 +99,10 @@ public class BluetoothUtilsTest { characteristic.setValue(new byte[]{0x2C, 0x00, 0x00, 0x00, (byte) 0x9F, 0x00, 0x0C, 0x00, (byte) 0xE5, 0x42}); // when - SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower(characteristic); + SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower("", "", characteristic); // then - assertEquals(0, powerCadence.getPower().getW(), 0.01); + assertEquals(0, powerCadence.getPower().getValue().getW(), 0.01); assertEquals(12, powerCadence.getCadence().getCrankRevolutionsCount()); assertEquals(17125, powerCadence.getCadence().getCrankRevolutionsTime()); diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java index 20138971c..dc1d55541 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothConnectionManager.java @@ -31,10 +31,10 @@ import android.util.Log; import androidx.annotation.NonNull; import java.util.List; +import java.util.Optional; +import java.util.UUID; -import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.sensors.sensorData.SensorData; -import de.dennisguse.opentracks.sensors.sensorData.SensorDataHeartRate; /** * Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications. @@ -111,8 +111,16 @@ public abstract class BluetoothConnectionManager { @Override public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic) { - Log.d(TAG, "Received data from " + gatt.getDevice().getAddress()); - SensorData sensorData = parsePayload(gatt.getDevice().getName(), gatt.getDevice().getAddress(), 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.getServiceUUID().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); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -180,26 +188,7 @@ public abstract class BluetoothConnectionManager { /** * @return null if data could not be parsed. */ - protected abstract SensorData parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic); - - public static class HeartRateConnectionManager extends BluetoothConnectionManager { - - HeartRateConnectionManager(@NonNull SensorDataObserver observer) { - super(BluetoothUtils.HEART_RATE_SUPPORTING_DEVICES, observer); - } - - @Override - protected SensorDataHeartRate createEmptySensorData(String address) { - return new SensorDataHeartRate(address); - } - - @Override - protected SensorDataHeartRate parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { - Integer heartRate = BluetoothUtils.parseHeartRate(characteristic); - - return heartRate != null ? new SensorDataHeartRate(address, sensorName, HeartRate.of(heartRate)) : null; - } - } + protected abstract SensorData parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, @NonNull BluetoothGattCharacteristic characteristic); interface SensorDataObserver { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingCadence.java index baf29226c..b6a2cb9af 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingCadence.java @@ -1,15 +1,19 @@ 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 BluetoothRemoteSensorManagerCyclingCadence extends BluetoothConnectionManager { + private static final String TAG = BluetoothRemoteSensorManagerCyclingCadence.class.getSimpleName(); + BluetoothRemoteSensorManagerCyclingCadence(SensorDataObserver observer) { - super(BluetoothUtils.CYCLING_SPEED_CADENCE, observer); + super(BluetoothUtils.CYCLING_CADENCE, observer); } @Override @@ -18,16 +22,26 @@ public class BluetoothRemoteSensorManagerCyclingCadence extends BluetoothConnect } @Override - protected SensorDataCyclingCadence parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { - SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic); - if (cadenceAndSpeed == null) { - return null; - } - - if (cadenceAndSpeed.getCadence() != null) { - return cadenceAndSpeed.getCadence(); + 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.getCadence(); + } + } 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/BluetoothRemoteSensorManagerCyclingDistanceSpeed.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingDistanceSpeed.java index 3abd42bee..e6bfba003 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingDistanceSpeed.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingDistanceSpeed.java @@ -17,7 +17,7 @@ public class BluetoothRemoteSensorManagerCyclingDistanceSpeed extends BluetoothC } @Override - protected SensorDataCyclingDistanceSpeed parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { + protected SensorDataCyclingDistanceSpeed parsePayload(ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { SensorDataCyclingCadenceAndDistanceSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic); if (cadenceAndSpeed == null) { return null; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingPower.java index 6efda9ade..f94b8bf76 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerCyclingPower.java @@ -19,9 +19,9 @@ public class BluetoothRemoteSensorManagerCyclingPower extends BluetoothConnectio } @Override - protected SensorDataCyclingPower parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { - SensorDataCyclingPower.Data cyclingPower = BluetoothUtils.parseCyclingPower(characteristic); + protected SensorDataCyclingPower parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { + SensorDataCyclingPower.Data cyclingPower = BluetoothUtils.parseCyclingPower(address, sensorName, characteristic); - return cyclingPower != null ? new SensorDataCyclingPower(address, sensorName, cyclingPower.getPower()) : null; + return cyclingPower != null ? cyclingPower.getPower() : null; } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerHeartRate.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerHeartRate.java index 2aef346d9..54b2b317c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerHeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerHeartRate.java @@ -19,7 +19,7 @@ public class BluetoothRemoteSensorManagerHeartRate extends BluetoothConnectionMa } @Override - protected SensorDataHeartRate parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { + protected SensorDataHeartRate parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { Integer heartRate = BluetoothUtils.parseHeartRate(characteristic); return heartRate != null ? new SensorDataHeartRate(address, sensorName, HeartRate.of(heartRate)) : null; diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerRunningSpeedAndCadence.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerRunningSpeedAndCadence.java index 20d5e063d..73b11b38c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerRunningSpeedAndCadence.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothRemoteSensorManagerRunningSpeedAndCadence.java @@ -18,7 +18,7 @@ public class BluetoothRemoteSensorManagerRunningSpeedAndCadence extends Bluetoot } @Override - protected SensorDataRunning parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) { + protected SensorDataRunning parsePayload(@NonNull ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) { return BluetoothUtils.parseRunningSpeedAndCadence(address, sensorName, characteristic); } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java index d94fd0cc4..41c99b2af 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/BluetoothUtils.java @@ -119,7 +119,7 @@ public class BluetoothUtils { return null; } - public static SensorDataCyclingPower.Data parseCyclingPower(BluetoothGattCharacteristic characteristic) { + public static SensorDataCyclingPower.Data parseCyclingPower(String address, String sensorName, BluetoothGattCharacteristic characteristic) { // DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.cycling_power_measurement.xml int valueLength = characteristic.getValue().length; if (valueLength == 0) { @@ -154,10 +154,11 @@ public class BluetoothUtils { int crankTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s - cadence = new SensorDataCyclingCadence("", "", crankCount, crankTime); + cadence = new SensorDataCyclingCadence(address, sensorName, crankCount, crankTime); } - return new SensorDataCyclingPower.Data(Power.of(instantaneousPower), cadence); + + return new SensorDataCyclingPower.Data(new SensorDataCyclingPower(sensorName, address, Power.of(instantaneousPower)), cadence); } public static SensorDataCyclingCadenceAndDistanceSpeed parseCyclingCrankAndWheel(String address, String sensorName, @NonNull BluetoothGattCharacteristic characteristic) { diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingPower.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingPower.java index ba81d789d..7f0a512f0 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingPower.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataCyclingPower.java @@ -29,15 +29,15 @@ public class SensorDataCyclingPower extends SensorData { } public static class Data { - private final Power power; + private final SensorDataCyclingPower power; private final SensorDataCyclingCadence cadence; - public Data(Power power, @Nullable SensorDataCyclingCadence cadence) { + public Data(SensorDataCyclingPower power, @Nullable SensorDataCyclingCadence cadence) { this.power = power; this.cadence = cadence; } - public Power getPower() { + public SensorDataCyclingPower getPower() { return power; } diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java new file mode 100644 index 000000000..bf9577621 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadencePreference.java @@ -0,0 +1,32 @@ +package de.dennisguse.opentracks.settings.bluetooth; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.preference.PreferenceDialogFragmentCompat; + +import de.dennisguse.opentracks.sensors.BluetoothUtils; + +public class BluetoothLeCyclingCadencePreference extends BluetoothLeSensorPreference { + + public BluetoothLeCyclingCadencePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public BluetoothLeCyclingCadencePreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public BluetoothLeCyclingCadencePreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public BluetoothLeCyclingCadencePreference(Context context) { + super(context); + } + + @Override + public PreferenceDialogFragmentCompat createInstance() { + return BluetoothLeSensorPreferenceDialog.newInstance(getKey(), BluetoothUtils.CYCLING_CADENCE); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadenceAndSpeedPreference.java b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java similarity index 56% rename from src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadenceAndSpeedPreference.java rename to src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java index a4e234ead..db918d97d 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingCadenceAndSpeedPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/bluetooth/BluetoothLeCyclingSpeedPreference.java @@ -7,21 +7,21 @@ import androidx.preference.PreferenceDialogFragmentCompat; import de.dennisguse.opentracks.sensors.BluetoothUtils; -public class BluetoothLeCyclingCadenceAndSpeedPreference extends BluetoothLeSensorPreference { +public class BluetoothLeCyclingSpeedPreference extends BluetoothLeSensorPreference { - public BluetoothLeCyclingCadenceAndSpeedPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public BluetoothLeCyclingSpeedPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - public BluetoothLeCyclingCadenceAndSpeedPreference(Context context, AttributeSet attrs, int defStyleAttr) { + public BluetoothLeCyclingSpeedPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public BluetoothLeCyclingCadenceAndSpeedPreference(Context context, AttributeSet attrs) { + public BluetoothLeCyclingSpeedPreference(Context context, AttributeSet attrs) { super(context, attrs); } - public BluetoothLeCyclingCadenceAndSpeedPreference(Context context) { + public BluetoothLeCyclingSpeedPreference(Context context) { super(context); } diff --git a/src/main/res/xml/settings_sensors.xml b/src/main/res/xml/settings_sensors.xml index 4d40b595c..23a4be516 100644 --- a/src/main/res/xml/settings_sensors.xml +++ b/src/main/res/xml/settings_sensors.xml @@ -12,7 +12,7 @@ - @@ -20,7 +20,7 @@ android:defaultValue="@string/sensor_type_value_none" android:key="@string/settings_sensor_bluetooth_cycling_power_key" android:title="@string/sensor_state_power" /> -