diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java index 620d5d037..806433dde 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java @@ -45,12 +45,11 @@ public class GPXExporter implements ActivityTrackExporter { private static final String NS_GPX_URI = "http://www.topografix.com/GPX/1/1"; private static final String NS_GPX_PREFIX = ""; private static final String NS_TRACKPOINT_EXTENSION = "gpxtpx"; - private static final String NS_TRACKPOINT_EXTENSION_URI = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1"; + private static final String NS_TRACKPOINT_EXTENSION_URI = "https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd"; private static final String NS_XSI_URI = "http://www.w3.org/2001/XMLSchema-instance"; private static final String TOPOGRAFIX_NAMESPACE_XSD = "http://www.topografix.com/GPX/1/1/gpx.xsd"; private static final String OPENTRACKS_PREFIX = "opentracks"; private static final String OPENTRACKS_NAMESPACE_URI = "http://opentracksapp.com/xmlschemas/v1"; - private static final String OPENTRACKS_NAMESPACE_XSD = "http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd"; private String creator; private boolean includeHeartRate = true; @@ -75,9 +74,7 @@ public class GPXExporter implements ActivityTrackExporter { } else { ser.attribute(null, "creator", GBApplication.app().getNameAndVersion()); } - ser.attribute(NS_XSI_URI, "schemaLocation", NS_GPX_URI + " " - + TOPOGRAFIX_NAMESPACE_XSD + " " - + OPENTRACKS_NAMESPACE_URI + " " + OPENTRACKS_NAMESPACE_XSD); + ser.attribute(NS_XSI_URI, "schemaLocation",NS_GPX_URI + " " + TOPOGRAFIX_NAMESPACE_XSD); exportMetadata(ser, track); exportTrack(ser, track); @@ -146,10 +143,10 @@ public class GPXExporter implements ActivityTrackExporter { } ser.startTag(NS_GPX_URI, "trkpt"); // lon and lat attributes do not have an explicit namespace - ser.attribute(null, "lon", formatLocation(location.getLongitude())); - ser.attribute(null, "lat", formatLocation(location.getLatitude())); + ser.attribute(null, "lon", formatDouble(location.getLongitude())); + ser.attribute(null, "lat", formatDouble(location.getLatitude())); if (location.getAltitude() != GPSCoordinate.UNKNOWN_ALTITUDE) { - ser.startTag(NS_GPX_URI, "ele").text(formatLocation(location.getAltitude())).endTag(NS_GPX_URI, "ele"); + ser.startTag(NS_GPX_URI, "ele").text(formatDouble(location.getAltitude())).endTag(NS_GPX_URI, "ele"); } ser.startTag(NS_GPX_URI, "time").text(DateTimeUtils.formatIso8601UTC(point.getTime())).endTag(NS_GPX_URI, "time"); String description = point.getDescription(); @@ -170,27 +167,37 @@ public class GPXExporter implements ActivityTrackExporter { return; } + float speed = point.getSpeed(); + int cadence = point.getCadence(); int hr = point.getHeartRate(); - if (!HeartRateUtils.getInstance().isValidHeartRateValue(hr)) { - if (!includeHeartRateOfNearestSample) { - return; - } + if (!HeartRateUtils.getInstance().isValidHeartRateValue(hr) && includeHeartRateOfNearestSample) { ActivityPoint closestPointItem = findClosestSensibleActivityPoint(point.getTime(), trackPoints); - if(closestPointItem == null) { - return; + if (closestPointItem != null) { + hr = closestPointItem.getHeartRate(); } - hr = closestPointItem.getHeartRate(); - if (!HeartRateUtils.getInstance().isValidHeartRateValue(hr)) { - return; - } + } + + boolean exportHr = HeartRateUtils.getInstance().isValidHeartRateValue(hr) && includeHeartRate; + + if (!exportHr && speed < 0 && cadence < 0) { + // No valid data to export in extensions + return; } ser.startTag(NS_GPX_URI, "extensions"); ser.setPrefix(NS_TRACKPOINT_EXTENSION, NS_TRACKPOINT_EXTENSION_URI); ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "TrackPointExtension"); - ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "hr").text(String.valueOf(hr)).endTag(NS_TRACKPOINT_EXTENSION_URI, "hr"); + if (exportHr) { + ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "hr").text(String.valueOf(hr)).endTag(NS_TRACKPOINT_EXTENSION_URI, "hr"); + } + if (cadence >= 0) { + ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "cad").text(String.valueOf(cadence)).endTag(NS_TRACKPOINT_EXTENSION_URI, "cad"); + } + if (speed >= 0) { + ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "speed").text(formatDouble(speed)).endTag(NS_TRACKPOINT_EXTENSION_URI, "speed"); + } ser.endTag(NS_TRACKPOINT_EXTENSION_URI, "TrackPointExtension"); ser.endTag(NS_GPX_URI, "extensions"); } @@ -217,7 +224,7 @@ public class GPXExporter implements ActivityTrackExporter { return closestPointItem; } - private String formatLocation(double value) { + private String formatDouble(double value) { return new BigDecimal(value).setScale(GPSCoordinate.GPS_DECIMAL_DEGREES_SCALE, RoundingMode.HALF_UP).toPlainString(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityPoint.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityPoint.java index e36a5cfd4..3767e9fbc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityPoint.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityPoint.java @@ -26,11 +26,12 @@ import androidx.annotation.Nullable; 29.2 - - 11 - 92 - 0 - + + 11 + 92 + 0 + 0.5 + */ @@ -39,6 +40,7 @@ public class ActivityPoint { private GPSCoordinate location; private int heartRate; private float speed = -1; + private int cadence = -1; // e.g. to describe a pause during the activity private @Nullable String description; @@ -90,4 +92,12 @@ public class ActivityPoint { public void setSpeed(float speed) { this.speed = speed; } + + public int getCadence() { + return cadence; + } + + public void setCadence(final int cadence) { + this.cadence = cadence; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecord.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecord.java index 17a165d68..823e52bfa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecord.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecord.java @@ -138,6 +138,9 @@ public class FitRecord extends RecordData { if (getEnhancedSpeed() != null) { activityPoint.setSpeed(getEnhancedSpeed().floatValue()); } + if (getCadence() != null) { + activityPoint.setCadence(getCadence()); + } return activityPoint; } } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java index f0595de8b..2abca82b9 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java @@ -104,6 +104,4 @@ public class HuamiActivityDetailsParserTest extends TestBase { private InputStream getContents(URL hexFile) throws IOException { return new HexToBinaryInputStream(hexFile.openStream()); } - - }