mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-03 01:53:05 +02:00
Introduced value objects for heartrate, cadence, and power.
Fixes #896.
This commit is contained in:
@@ -44,13 +44,13 @@ public class ChartPoint {
|
||||
pace = smoothedSpeed.toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN;
|
||||
}
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
heartRate = (double) trackPoint.getHeartRate_bpm();
|
||||
heartRate = (double) trackPoint.getHeartRate().getBPM();
|
||||
}
|
||||
if (trackPoint.hasCadence()) {
|
||||
cadence = (double) trackPoint.getCadence_rpm();
|
||||
cadence = (double) trackPoint.getCadence().getRPM();
|
||||
}
|
||||
if (trackPoint.hasPower()) {
|
||||
power = (double) trackPoint.getPower();
|
||||
power = (double) trackPoint.getPower().getW();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,11 @@ import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.BuildConfig;
|
||||
import de.dennisguse.opentracks.data.models.Altitude;
|
||||
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.Marker;
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
@@ -577,10 +580,10 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
if (!cursor.isNull(indexes.sensorHeartRateIndex)) {
|
||||
trackPoint.setHeartRate_bpm(cursor.getFloat(indexes.sensorHeartRateIndex));
|
||||
trackPoint.setHeartRate(cursor.getFloat(indexes.sensorHeartRateIndex));
|
||||
}
|
||||
if (!cursor.isNull(indexes.sensorCadenceIndex)) {
|
||||
trackPoint.setCadence_rpm(cursor.getFloat(indexes.sensorCadenceIndex));
|
||||
trackPoint.setCadence(cursor.getFloat(indexes.sensorCadenceIndex));
|
||||
}
|
||||
if (!cursor.isNull(indexes.sensorDistanceIndex)) {
|
||||
trackPoint.setSensorDistance(Distance.of(cursor.getFloat(indexes.sensorDistanceIndex)));
|
||||
@@ -739,16 +742,16 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.getHeartRate_bpm());
|
||||
values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.getHeartRate().getBPM());
|
||||
}
|
||||
if (trackPoint.hasCadence()) {
|
||||
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCadence_rpm());
|
||||
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCadence().getRPM());
|
||||
}
|
||||
if (trackPoint.hasSensorDistance()) {
|
||||
values.put(TrackPointsColumns.SENSOR_DISTANCE, trackPoint.getSensorDistance().toM());
|
||||
}
|
||||
if (trackPoint.hasPower()) {
|
||||
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower());
|
||||
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower().getW());
|
||||
}
|
||||
|
||||
if (trackPoint.hasAltitudeGain()) {
|
||||
@@ -831,12 +834,17 @@ public class ContentProviderUtils {
|
||||
SensorStatistics sensorStatistics = null;
|
||||
try (Cursor cursor = contentResolver.query(ContentUris.withAppendedId(TracksColumns.CONTENT_URI_SENSOR_STATS, trackId.getId()), null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int MAX_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_HR);
|
||||
final int AVG_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_HR);
|
||||
final int MAX_CADENCE_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_CADENCE);
|
||||
final int AVG_CADENCE_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_CADENCE);
|
||||
final int AVG_POWER_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_POWER);
|
||||
sensorStatistics = new SensorStatistics(
|
||||
!cursor.isNull(cursor.getColumnIndexOrThrow("max_hr")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_HR)) : null,
|
||||
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_hr")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_HR)) : null,
|
||||
!cursor.isNull(cursor.getColumnIndexOrThrow("max_cadence")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_CADENCE)) : null,
|
||||
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_cadence")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_CADENCE)) : null,
|
||||
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_power")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_POWER)) : null
|
||||
!cursor.isNull(MAX_HR_INDEX) ? HeartRate.of(cursor.getFloat(MAX_HR_INDEX)) : null,
|
||||
!cursor.isNull(AVG_HR_INDEX) ? HeartRate.of(cursor.getFloat(AVG_HR_INDEX)) : null,
|
||||
!cursor.isNull(MAX_CADENCE_INDEX) ? Cadence.of(cursor.getFloat(MAX_CADENCE_INDEX)) : null,
|
||||
!cursor.isNull(AVG_CADENCE_INDEX) ? Cadence.of(cursor.getFloat(AVG_CADENCE_INDEX)) : null,
|
||||
!cursor.isNull(AVG_POWER_INDEX) ? Power.of(cursor.getFloat(AVG_POWER_INDEX)) : null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Cadence {
|
||||
|
||||
public static Cadence of(float value) {
|
||||
return new Cadence(value);
|
||||
}
|
||||
|
||||
private final float value;
|
||||
|
||||
private Cadence(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getRPM() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Cadence cadence = (Cadence) o;
|
||||
return Float.compare(cadence.value, value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Cadence{" +
|
||||
"value=" + value + " rpm" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class HeartRate {
|
||||
|
||||
public static HeartRate of(float value) {
|
||||
return new HeartRate(value);
|
||||
}
|
||||
|
||||
private final float value;
|
||||
|
||||
private HeartRate(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getBPM() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
HeartRate heartRate = (HeartRate) o;
|
||||
return Float.compare(heartRate.value, value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HeartRate{" +
|
||||
"value=" + value + " bpm" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Power {
|
||||
|
||||
public static Power of(float value) {
|
||||
return new Power(value);
|
||||
}
|
||||
|
||||
private final float value;
|
||||
|
||||
private Power(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getW() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Power power = (Power) o;
|
||||
return Float.compare(power.value, value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Power{" +
|
||||
"value=" + value + " W" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -91,9 +91,9 @@ public class TrackPoint {
|
||||
@NonNull
|
||||
private Type type;
|
||||
|
||||
private Float heartRate_bpm = null;
|
||||
private Float cadence_rpm = null;
|
||||
private Float power = null;
|
||||
private HeartRate heartRate = null;
|
||||
private Cadence cadence = null;
|
||||
private Power power = null;
|
||||
private Float altitudeGain_m = null;
|
||||
private Float altitudeLoss_m = null;
|
||||
|
||||
@@ -382,44 +382,56 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public boolean hasHeartRate() {
|
||||
return heartRate_bpm != null && heartRate_bpm > 0;
|
||||
return heartRate != null;
|
||||
}
|
||||
|
||||
public float getHeartRate_bpm() {
|
||||
return heartRate_bpm;
|
||||
public HeartRate getHeartRate() {
|
||||
return heartRate;
|
||||
}
|
||||
|
||||
public TrackPoint setHeartRate_bpm(Float heartRate_bpm) {
|
||||
this.heartRate_bpm = heartRate_bpm;
|
||||
public TrackPoint setHeartRate(HeartRate heartRate) {
|
||||
this.heartRate = heartRate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackPoint setHeartRate(float heartRate) {
|
||||
return setHeartRate(HeartRate.of(heartRate));
|
||||
}
|
||||
|
||||
public boolean hasCadence() {
|
||||
return cadence_rpm != null;
|
||||
return cadence != null;
|
||||
}
|
||||
|
||||
public float getCadence_rpm() {
|
||||
return cadence_rpm;
|
||||
public Cadence getCadence() {
|
||||
return cadence;
|
||||
}
|
||||
|
||||
public TrackPoint setCadence_rpm(Float cadence_rpm) {
|
||||
this.cadence_rpm = cadence_rpm;
|
||||
public TrackPoint setCadence(Cadence cadence) {
|
||||
this.cadence = cadence;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackPoint setCadence(float cadence) {
|
||||
return setCadence(Cadence.of(cadence));
|
||||
}
|
||||
|
||||
public boolean hasPower() {
|
||||
return power != null;
|
||||
}
|
||||
|
||||
public float getPower() {
|
||||
public Power getPower() {
|
||||
return power;
|
||||
}
|
||||
|
||||
public TrackPoint setPower(Float power) {
|
||||
public TrackPoint setPower(Power power) {
|
||||
this.power = power;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackPoint setPower(float power) {
|
||||
return setPower(Power.of(power));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -434,8 +446,8 @@ public class TrackPoint {
|
||||
", bearing=" + bearing +
|
||||
", sensorDistance=" + sensorDistance +
|
||||
", type=" + type +
|
||||
", heartRate_bpm=" + heartRate_bpm +
|
||||
", cadence_rpm=" + cadence_rpm +
|
||||
", heartRate_bpm=" + heartRate +
|
||||
", cadence_rpm=" + cadence +
|
||||
", power=" + power +
|
||||
", altitudeGain_m=" + altitudeGain_m +
|
||||
", altitudeLoss_m=" + altitudeLoss_m +
|
||||
|
||||
@@ -331,15 +331,15 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
}
|
||||
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
trackPointExtensionContent += "<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate_bpm()) + "</gpxtpx:hr>\n";
|
||||
trackPointExtensionContent += "<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate().getBPM()) + "</gpxtpx:hr>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasCadence()) {
|
||||
trackPointExtensionContent += "<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence_rpm()) + "</gpxtpx:cad>\n";
|
||||
trackPointExtensionContent += "<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence().getRPM()) + "</gpxtpx:cad>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasPower()) {
|
||||
trackPointExtensionContent += "<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>\n";
|
||||
trackPointExtensionContent += "<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower().getW()) + "</pwr:PowerInWatts>\n";
|
||||
}
|
||||
|
||||
Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGain() ? (double) tp.getAltitudeGain() : null);
|
||||
|
||||
@@ -381,9 +381,9 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
speedList.add(trackPoint.hasSpeed() ? (float) trackPoint.getSpeed().toMPS() : null);
|
||||
|
||||
distanceList.add(trackPoint.hasSensorDistance() ? (float) trackPoint.getSensorDistance().toM() : null);
|
||||
heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate_bpm() : null);
|
||||
cadenceList.add(trackPoint.hasCadence() ? trackPoint.getCadence_rpm() : null);
|
||||
powerList.add(trackPoint.hasPower() ? trackPoint.getPower() : null);
|
||||
heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate().getBPM() : null);
|
||||
cadenceList.add(trackPoint.hasCadence() ? trackPoint.getCadence().getRPM() : null);
|
||||
powerList.add(trackPoint.hasPower() ? trackPoint.getPower().getW() : null);
|
||||
|
||||
altitudeGainList.add(trackPoint.hasAltitudeGain() ? trackPoint.getAltitudeGain() : null);
|
||||
altitudeLossList.add(trackPoint.hasAltitudeLoss() ? trackPoint.getAltitudeLoss() : null);
|
||||
|
||||
@@ -299,7 +299,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
}
|
||||
if (heartrate != null) {
|
||||
try {
|
||||
trackPoint.setHeartRate_bpm(Float.parseFloat(heartrate));
|
||||
trackPoint.setHeartRate(Float.parseFloat(heartrate));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse heart rate: %s", heartrate)), e);
|
||||
}
|
||||
@@ -307,7 +307,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
|
||||
if (cadence != null) {
|
||||
try {
|
||||
trackPoint.setCadence_rpm(Float.parseFloat(cadence));
|
||||
trackPoint.setCadence(Float.parseFloat(cadence));
|
||||
} catch (Exception e) {
|
||||
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse cadence: %s", cadence)), e);
|
||||
}
|
||||
|
||||
@@ -318,13 +318,13 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
if (i < sensorDistanceList.size() && sensorDistanceList.get(i) != null) {
|
||||
trackPoint.setSensorDistance(Distance.of(sensorDistanceList.get(i)));
|
||||
}
|
||||
if (i < sensorHeartRateList.size()) {
|
||||
trackPoint.setHeartRate_bpm(sensorHeartRateList.get(i));
|
||||
if (i < sensorHeartRateList.size() && sensorHeartRateList.get(i) != null) {
|
||||
trackPoint.setHeartRate(sensorHeartRateList.get(i));
|
||||
}
|
||||
if (i < sensorCadenceList.size()) {
|
||||
trackPoint.setCadence_rpm(sensorCadenceList.get(i));
|
||||
if (i < sensorCadenceList.size() && sensorCadenceList.get(i) != null) {
|
||||
trackPoint.setCadence(sensorCadenceList.get(i));
|
||||
}
|
||||
if (i < sensorPowerList.size()) {
|
||||
if (i < sensorPowerList.size() && sensorPowerList.get(i) != null) {
|
||||
trackPoint.setPower(sensorPowerList.get(i));
|
||||
}
|
||||
if (i < altitudeGainList.size()) {
|
||||
|
||||
@@ -30,6 +30,9 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
|
||||
@@ -161,9 +164,9 @@ public abstract class BluetoothConnectionManager<DataType> {
|
||||
*/
|
||||
protected abstract SensorData<DataType> parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic);
|
||||
|
||||
public static class HeartRate extends BluetoothConnectionManager<Float> {
|
||||
public static class HeartRateConnectionManager extends BluetoothConnectionManager<HeartRate> {
|
||||
|
||||
HeartRate(@NonNull SensorDataObserver observer) {
|
||||
HeartRateConnectionManager(@NonNull SensorDataObserver observer) {
|
||||
super(BluetoothUtils.HEART_RATE_SERVICE_UUID, BluetoothUtils.HEART_RATE_MEASUREMENT_CHAR_UUID, observer);
|
||||
}
|
||||
|
||||
@@ -176,23 +179,23 @@ public abstract class BluetoothConnectionManager<DataType> {
|
||||
protected SensorDataHeartRate parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||
Integer heartRate = BluetoothUtils.parseHeartRate(characteristic);
|
||||
|
||||
return heartRate != null ? new SensorDataHeartRate(address, sensorName, heartRate) : null;
|
||||
return heartRate != null ? new SensorDataHeartRate(address, sensorName, HeartRate.of(heartRate)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CyclingCadence extends BluetoothConnectionManager<Float> {
|
||||
public static class CyclingCadence extends BluetoothConnectionManager<Cadence> {
|
||||
|
||||
CyclingCadence(SensorDataObserver observer) {
|
||||
super(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, BluetoothUtils.CYCLING_SPEED_CADENCE_MEASUREMENT_CHAR_UUID, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorDataCycling.Cadence createEmptySensorData(String address) {
|
||||
return new SensorDataCycling.Cadence(address);
|
||||
protected SensorDataCycling.CyclingCadence createEmptySensorData(String address) {
|
||||
return new SensorDataCycling.CyclingCadence(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorDataCycling.Cadence parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||
protected SensorDataCycling.CyclingCadence parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||
SensorDataCycling.CadenceAndSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
|
||||
if (cadenceAndSpeed == null) {
|
||||
return null;
|
||||
@@ -232,7 +235,7 @@ public abstract class BluetoothConnectionManager<DataType> {
|
||||
}
|
||||
}
|
||||
|
||||
public static class CyclingPower extends BluetoothConnectionManager<Float> {
|
||||
public static class CyclingPower extends BluetoothConnectionManager<Power> {
|
||||
|
||||
CyclingPower(@NonNull SensorDataObserver observer) {
|
||||
super(BluetoothUtils.CYCLING_POWER_UUID, BluetoothUtils.CYCLING_POWER_MEASUREMENT_CHAR_UUID, observer);
|
||||
@@ -247,7 +250,7 @@ public abstract class BluetoothConnectionManager<DataType> {
|
||||
protected SensorDataCyclingPower parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||
Integer cyclingPower = BluetoothUtils.parseCyclingPower(characteristic);
|
||||
|
||||
return cyclingPower != null ? new SensorDataCyclingPower(address, sensorName, cyclingPower) : null;
|
||||
return cyclingPower != null ? new SensorDataCyclingPower(address, sensorName, Power.of(cyclingPower)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
||||
|
||||
private Distance preferenceWheelCircumference;
|
||||
|
||||
private final BluetoothConnectionManager.HeartRate heartRate = new BluetoothConnectionManager.HeartRate(this);
|
||||
private final BluetoothConnectionManager.HeartRateConnectionManager heartRate = new BluetoothConnectionManager.HeartRateConnectionManager(this);
|
||||
private final BluetoothConnectionManager.CyclingCadence cyclingCadence = new BluetoothConnectionManager.CyclingCadence(this);
|
||||
private final BluetoothConnectionManager.CyclingDistanceSpeed cyclingSpeed = new BluetoothConnectionManager.CyclingDistanceSpeed(this);
|
||||
private final BluetoothConnectionManager.CyclingPower cyclingPower = new BluetoothConnectionManager.CyclingPower(this);
|
||||
@@ -180,15 +180,15 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
||||
|
||||
@Override
|
||||
public synchronized void onChanged(SensorData<?> sensorData) {
|
||||
if (sensorData instanceof SensorDataCycling.Cadence) {
|
||||
SensorDataCycling.Cadence previous = sensorDataSet.getCyclingCadence();
|
||||
if (sensorData instanceof SensorDataCycling.CyclingCadence) {
|
||||
SensorDataCycling.CyclingCadence previous = sensorDataSet.getCyclingCadence();
|
||||
Log.d(TAG, "Previous: " + previous + "; current: " + sensorData);
|
||||
|
||||
if (sensorData.equals(previous)) {
|
||||
Log.d(TAG, "onChanged: cadence data repeated.");
|
||||
return;
|
||||
}
|
||||
((SensorDataCycling.Cadence) sensorData).compute(previous);
|
||||
((SensorDataCycling.CyclingCadence) sensorData).compute(previous);
|
||||
}
|
||||
if (sensorData instanceof SensorDataCycling.DistanceSpeed) {
|
||||
SensorDataCycling.DistanceSpeed previous = sensorDataSet.getCyclingDistanceSpeed();
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
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.sensorData.SensorDataCycling;
|
||||
@@ -128,13 +129,13 @@ public class BluetoothUtils {
|
||||
index += 2;
|
||||
}
|
||||
|
||||
SensorDataCycling.Cadence cadence = null;
|
||||
SensorDataCycling.CyclingCadence cadence = 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
|
||||
cadence = new SensorDataCycling.Cadence(address, sensorName, crankCount, crankTime);
|
||||
cadence = new SensorDataCycling.CyclingCadence(address, sensorName, crankCount, crankTime);
|
||||
}
|
||||
|
||||
return new SensorDataCycling.CadenceAndSpeed(address, sensorName, cadence, speed);
|
||||
@@ -153,7 +154,7 @@ public class BluetoothUtils {
|
||||
boolean hasStatus = (flags & 0x03) > 0; // walking vs running
|
||||
|
||||
Speed speed = null;
|
||||
Float cadence = null;
|
||||
Cadence cadence = null;
|
||||
Distance totalDistance = null;
|
||||
|
||||
int index = 1;
|
||||
@@ -163,7 +164,7 @@ public class BluetoothUtils {
|
||||
|
||||
index = 3;
|
||||
if (valueLength - index >= 1) {
|
||||
cadence = Float.valueOf(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, index));
|
||||
cadence = Cadence.of(characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, index));
|
||||
}
|
||||
|
||||
index = 4;
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.core.util.Pair;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
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.data.models.UnitConversions;
|
||||
@@ -23,18 +24,18 @@ public final class SensorDataCycling {
|
||||
private SensorDataCycling() {
|
||||
}
|
||||
|
||||
public static class Cadence extends SensorData<Float> {
|
||||
public static class CyclingCadence extends SensorData<Cadence> {
|
||||
|
||||
private final Long crankRevolutionsCount; // UINT32
|
||||
private final Integer crankRevolutionsTime; // UINT16; 1/1024s
|
||||
|
||||
public Cadence(String sensorAddress) {
|
||||
public CyclingCadence(String sensorAddress) {
|
||||
super(sensorAddress);
|
||||
this.crankRevolutionsCount = null;
|
||||
this.crankRevolutionsTime = null;
|
||||
}
|
||||
|
||||
public Cadence(String sensorAddress, String sensorName, long crankRevolutionsCount, int crankRevolutionsTime) {
|
||||
public CyclingCadence(String sensorAddress, String sensorName, long crankRevolutionsCount, int crankRevolutionsTime) {
|
||||
super(sensorAddress, sensorName);
|
||||
this.crankRevolutionsCount = crankRevolutionsCount;
|
||||
this.crankRevolutionsTime = crankRevolutionsTime;
|
||||
@@ -43,7 +44,7 @@ public final class SensorDataCycling {
|
||||
/**
|
||||
* Workaround for Wahoo CADENCE: provides speed instead of cadence
|
||||
*/
|
||||
public Cadence(@NonNull DistanceSpeed speed) {
|
||||
public CyclingCadence(@NonNull DistanceSpeed speed) {
|
||||
this(speed.getSensorAddress(), speed.getSensorName(), speed.wheelRevolutionsCount, speed.wheelRevolutionsTime);
|
||||
}
|
||||
|
||||
@@ -61,11 +62,11 @@ public final class SensorDataCycling {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Float getNoneValue() {
|
||||
return 0f;
|
||||
protected Cadence getNoneValue() {
|
||||
return Cadence.of(0);
|
||||
}
|
||||
|
||||
public void compute(Cadence previous) {
|
||||
public void compute(CyclingCadence previous) {
|
||||
if (hasData() && previous != null && previous.hasData()) {
|
||||
float timeDiff_ms = UintUtils.diff(crankRevolutionsTime, previous.crankRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
|
||||
if (timeDiff_ms <= 0) {
|
||||
@@ -82,7 +83,7 @@ public final class SensorDataCycling {
|
||||
|
||||
long crankDiff = UintUtils.diff(crankRevolutionsCount, previous.crankRevolutionsCount, UintUtils.UINT32_MAX);
|
||||
float cadence_ms = crankDiff / timeDiff_ms;
|
||||
value = (float) (cadence_ms / UnitConversions.MS_TO_S / UnitConversions.S_TO_MIN);
|
||||
value = Cadence.of((float) (cadence_ms / UnitConversions.MS_TO_S / UnitConversions.S_TO_MIN));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +95,9 @@ public final class SensorDataCycling {
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (!(obj instanceof Cadence)) return false;
|
||||
if (!(obj instanceof CyclingCadence)) return false;
|
||||
|
||||
Cadence comp = (Cadence) obj;
|
||||
CyclingCadence comp = (CyclingCadence) obj;
|
||||
if (hasData() && comp.hasData() == hasData()) {
|
||||
return getCrankRevolutionsCount() == comp.getCrankRevolutionsCount() && getCrankRevolutionsTime() == comp.getCrankRevolutionsTime();
|
||||
} else {
|
||||
@@ -230,14 +231,14 @@ public final class SensorDataCycling {
|
||||
}
|
||||
}
|
||||
|
||||
public static class CadenceAndSpeed extends SensorData<Pair<Cadence, DistanceSpeed>> {
|
||||
public static class CadenceAndSpeed extends SensorData<Pair<CyclingCadence, DistanceSpeed>> {
|
||||
|
||||
public CadenceAndSpeed(String sensorAddress, String sensorName, @Nullable Cadence cadence, @Nullable DistanceSpeed distanceSpeed) {
|
||||
public CadenceAndSpeed(String sensorAddress, String sensorName, @Nullable CyclingCadence cadence, @Nullable DistanceSpeed distanceSpeed) {
|
||||
super(sensorAddress, sensorName);
|
||||
this.value = new Pair<>(cadence, distanceSpeed);
|
||||
}
|
||||
|
||||
public Cadence getCadence() {
|
||||
public CyclingCadence getCadence() {
|
||||
return this.value != null ? this.value.first : null;
|
||||
}
|
||||
|
||||
@@ -247,7 +248,7 @@ public final class SensorDataCycling {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Pair<Cadence, DistanceSpeed> getNoneValue() {
|
||||
protected Pair<CyclingCadence, DistanceSpeed> getNoneValue() {
|
||||
return new Pair<>(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -2,15 +2,17 @@ package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class SensorDataCyclingPower extends SensorData<Float> {
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
|
||||
public class SensorDataCyclingPower extends SensorData<Power> {
|
||||
|
||||
public SensorDataCyclingPower(String address) {
|
||||
super(address);
|
||||
}
|
||||
|
||||
public SensorDataCyclingPower(String name, String address, float power_w) {
|
||||
public SensorDataCyclingPower(String name, String address, Power power) {
|
||||
super(name, address);
|
||||
this.value = power_w;
|
||||
this.value = power;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -21,7 +23,7 @@ public class SensorDataCyclingPower extends SensorData<Float> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Float getNoneValue() {
|
||||
return 0f;
|
||||
protected Power getNoneValue() {
|
||||
return Power.of(0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@ package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class SensorDataHeartRate extends SensorData<Float> {
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
|
||||
public class SensorDataHeartRate extends SensorData<HeartRate> {
|
||||
|
||||
public SensorDataHeartRate(String address) {
|
||||
super(address);
|
||||
}
|
||||
|
||||
public SensorDataHeartRate(String name, String address, float heartRate_bpm) {
|
||||
public SensorDataHeartRate(String name, String address, @NonNull HeartRate heartRate) {
|
||||
super(name, address);
|
||||
this.value = heartRate_bpm;
|
||||
this.value = heartRate;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -21,7 +23,7 @@ public class SensorDataHeartRate extends SensorData<Float> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Float getNoneValue() {
|
||||
return 0f;
|
||||
protected HeartRate getNoneValue() {
|
||||
return HeartRate.of(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
|
||||
@@ -16,7 +17,7 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
|
||||
private final Speed speed;
|
||||
|
||||
private final Float cadence;
|
||||
private final Cadence cadence;
|
||||
|
||||
private final Distance totalDistance;
|
||||
|
||||
@@ -27,7 +28,7 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
this.totalDistance = null;
|
||||
}
|
||||
|
||||
public SensorDataRunning(String sensorAddress, String sensorName, Speed speed, Float cadence, Distance totalDistance) {
|
||||
public SensorDataRunning(String sensorAddress, String sensorName, Speed speed, Cadence cadence, Distance totalDistance) {
|
||||
super(sensorAddress, sensorName);
|
||||
this.speed = speed;
|
||||
this.cadence = cadence;
|
||||
@@ -39,7 +40,7 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
}
|
||||
|
||||
|
||||
public Float getCadence() {
|
||||
public Cadence getCadence() {
|
||||
return cadence;
|
||||
}
|
||||
|
||||
@@ -56,9 +57,9 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
@Override
|
||||
protected Data getNoneValue() {
|
||||
if (value != null) {
|
||||
return new Data(Speed.zero(), 0f, value.distance);
|
||||
return new Data(Speed.zero(), Cadence.of(0f), value.distance);
|
||||
} else {
|
||||
return new Data(Speed.zero(), 0f, Distance.of(0));
|
||||
return new Data(Speed.zero(), Cadence.of(0f), Distance.of(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +86,12 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
|
||||
public static class Data {
|
||||
private final Speed speed;
|
||||
private final Float cadence;
|
||||
private final Cadence cadence;
|
||||
|
||||
@Nullable
|
||||
private final Distance distance;
|
||||
|
||||
public Data(Speed speed, Float cadence, @Nullable Distance distance) {
|
||||
public Data(Speed speed, Cadence cadence, @Nullable Distance distance) {
|
||||
this.speed = speed;
|
||||
this.cadence = cadence;
|
||||
this.distance = distance;
|
||||
@@ -100,7 +101,7 @@ public final class SensorDataRunning extends SensorData<SensorDataRunning.Data>
|
||||
return speed;
|
||||
}
|
||||
|
||||
public Float getCadence() {
|
||||
public Cadence getCadence() {
|
||||
return cadence;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
|
||||
@@ -11,7 +13,7 @@ public final class SensorDataSet {
|
||||
|
||||
private SensorDataHeartRate heartRate;
|
||||
|
||||
private SensorDataCycling.Cadence cyclingCadence;
|
||||
private SensorDataCycling.CyclingCadence cyclingCadence;
|
||||
|
||||
private SensorDataCycling.DistanceSpeed cyclingDistanceSpeed;
|
||||
|
||||
@@ -30,7 +32,7 @@ public final class SensorDataSet {
|
||||
this.runningDistanceSpeedCadence = toCopy.runningDistanceSpeedCadence;
|
||||
}
|
||||
|
||||
public Pair<Float, String> getHeartRate() {
|
||||
public Pair<HeartRate, String> getHeartRate() {
|
||||
if (heartRate != null) {
|
||||
return new Pair<>(heartRate.getValue(), heartRate.getSensorNameOrAddress());
|
||||
}
|
||||
@@ -38,7 +40,7 @@ public final class SensorDataSet {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Pair<Float, String> getCadence() {
|
||||
public Pair<Cadence, String> getCadence() {
|
||||
if (cyclingCadence != null) {
|
||||
return new Pair<>(cyclingCadence.getValue(), cyclingCadence.getSensorNameOrAddress());
|
||||
}
|
||||
@@ -62,7 +64,7 @@ public final class SensorDataSet {
|
||||
return null;
|
||||
}
|
||||
|
||||
public SensorDataCycling.Cadence getCyclingCadence() {
|
||||
public SensorDataCycling.CyclingCadence getCyclingCadence() {
|
||||
return cyclingCadence;
|
||||
}
|
||||
|
||||
@@ -96,11 +98,11 @@ public final class SensorDataSet {
|
||||
|
||||
public void fillTrackPoint(TrackPoint trackPoint) {
|
||||
if (getHeartRate() != null) {
|
||||
trackPoint.setHeartRate_bpm(getHeartRate().first);
|
||||
trackPoint.setHeartRate(getHeartRate().first);
|
||||
}
|
||||
|
||||
if (getCadence() != null) {
|
||||
trackPoint.setCadence_rpm(getCadence().first);
|
||||
trackPoint.setCadence(getCadence().first);
|
||||
}
|
||||
|
||||
if (getSpeed() != null) {
|
||||
@@ -144,8 +146,8 @@ public final class SensorDataSet {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type instanceof SensorDataCycling.Cadence) {
|
||||
this.cyclingCadence = (SensorDataCycling.Cadence) data;
|
||||
if (type instanceof SensorDataCycling.CyclingCadence) {
|
||||
this.cyclingCadence = (SensorDataCycling.CyclingCadence) data;
|
||||
return;
|
||||
}
|
||||
if (type instanceof SensorDataCycling.DistanceSpeed) {
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package de.dennisguse.opentracks.stats;
|
||||
|
||||
public class SensorStatistics {
|
||||
private final Float maxHr;
|
||||
private final Float avgHr;
|
||||
private final Float maxCadence;
|
||||
private final Float avgCadence;
|
||||
private final Float avgPower;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
|
||||
public SensorStatistics(Float maxHr, Float avgHr, Float maxCadence, Float avgCadence, Float avgPower) {
|
||||
public class SensorStatistics {
|
||||
private final HeartRate maxHr;
|
||||
private final HeartRate avgHr;
|
||||
private final Cadence maxCadence;
|
||||
private final Cadence avgCadence;
|
||||
private final Power avgPower;
|
||||
|
||||
public SensorStatistics(HeartRate maxHr, HeartRate avgHr, Cadence maxCadence, Cadence avgCadence, Power avgPower) {
|
||||
this.maxHr = maxHr;
|
||||
this.avgHr = avgHr;
|
||||
this.maxCadence = maxCadence;
|
||||
@@ -19,11 +23,11 @@ public class SensorStatistics {
|
||||
return avgHr != null && maxHr != null;
|
||||
}
|
||||
|
||||
public float getMaxHeartRate() {
|
||||
public HeartRate getMaxHeartRate() {
|
||||
return maxHr;
|
||||
}
|
||||
|
||||
public float getAvgHeartRate() {
|
||||
public HeartRate getAvgHeartRate() {
|
||||
return avgHr;
|
||||
}
|
||||
|
||||
@@ -31,11 +35,11 @@ public class SensorStatistics {
|
||||
return avgCadence != null && maxCadence != null;
|
||||
}
|
||||
|
||||
public float getMaxCadence() {
|
||||
public Cadence getMaxCadence() {
|
||||
return maxCadence;
|
||||
}
|
||||
|
||||
public float getAvgCadence() {
|
||||
public Cadence getAvgCadence() {
|
||||
return avgCadence;
|
||||
}
|
||||
|
||||
@@ -43,7 +47,7 @@ public class SensorStatistics {
|
||||
return avgPower != null;
|
||||
}
|
||||
|
||||
public float getAvgPower() {
|
||||
public Power getAvgPower() {
|
||||
return avgPower;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,10 @@ import java.time.format.FormatStyle;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
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;
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
|
||||
/**
|
||||
@@ -245,28 +248,28 @@ public class StringUtils {
|
||||
return new Pair<>(context.getString(R.string.time, minutes, seconds), unitString);
|
||||
}
|
||||
|
||||
public static Pair<String, String> getHeartRateParts(Context context, Float heartrate_bpm) {
|
||||
public static Pair<String, String> getHeartRateParts(Context context, HeartRate heartrate) {
|
||||
String value = context.getString(R.string.value_unknown);
|
||||
if (heartrate_bpm != null) {
|
||||
value = StringUtils.formatDecimal(heartrate_bpm, 0);
|
||||
if (heartrate != null) {
|
||||
value = StringUtils.formatDecimal(heartrate.getBPM(), 0);
|
||||
}
|
||||
|
||||
return new Pair<>(value, context.getString(R.string.sensor_unit_beats_per_minute));
|
||||
}
|
||||
|
||||
public static Pair<String, String> getCadenceParts(Context context, Float cadence_rpm) {
|
||||
public static Pair<String, String> getCadenceParts(Context context, Cadence cadence) {
|
||||
String value = context.getString(R.string.value_unknown);
|
||||
if (cadence_rpm != null) {
|
||||
value = StringUtils.formatDecimal(cadence_rpm, 0);
|
||||
if (cadence != null) {
|
||||
value = StringUtils.formatDecimal(cadence.getRPM(), 0);
|
||||
}
|
||||
|
||||
return new Pair<>(value, context.getString(R.string.sensor_unit_rounds_per_minute));
|
||||
}
|
||||
|
||||
public static Pair<String, String> getPowerParts(Context context, Float power_w) {
|
||||
public static Pair<String, String> getPowerParts(Context context, Power power) {
|
||||
String value = context.getString(R.string.value_unknown);
|
||||
if (power_w != null) {
|
||||
value = StringUtils.formatDecimal(power_w, 0);
|
||||
if (power != null) {
|
||||
value = StringUtils.formatDecimal(power.getW(), 0);
|
||||
}
|
||||
|
||||
return new Pair<>(value, context.getString(R.string.sensor_unit_power));
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||
@@ -115,9 +116,9 @@ public class StatisticDataBuilder {
|
||||
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_cadence_key))) {
|
||||
title = context.getString(R.string.stats_sensors_cadence);
|
||||
|
||||
Float cadence = null;
|
||||
Cadence cadence = null;
|
||||
if (sensorDataSet != null) {
|
||||
Pair<Float, String> cadenceData = sensorDataSet.getCadence();
|
||||
Pair<Cadence, String> cadenceData = sensorDataSet.getCadence();
|
||||
if (cadenceData != null) {
|
||||
cadence = cadenceData.first;
|
||||
description = cadenceData.second;
|
||||
|
||||
Reference in New Issue
Block a user