diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java index 87991dccc..67c0667c0 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java @@ -238,6 +238,81 @@ public class GPXTrackImporterTest { ), importedTrackPoints); } + /** + * until v4.18.0: some extensions where incorrectly added to gpxtpx:TrackPointExtension + * We only need to check the trackpoints. + */ + @LargeTest + @Test + public void gpx_legacy_trackpointextension() throws IOException { + // given + XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter)); + InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.legacy_gpx_trackpointextensions_incorrect); + + // when + // 1. import + importTrackId = importer.importFile(inputStream).get(0); + + // then: We only need to check the trackpoints. + + List actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); + + TrackPointAssert a = new TrackPointAssert() + .setDelta(0.05); // speed is not fully + a.assertEquals(List.of( + new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new Position( + Instant.parse("2020-02-02T02:02:03Z"), + 3d, 14d, Distance.of(10), + Altitude.WGS84.of(10), null, + null, + Speed.of(15))) + .setAltitudeLoss(1f) + .setAltitudeGain(1f), + new TrackPoint(TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:02:17Z"), + 3d, 14.001, Distance.of(10), + Altitude.WGS84.of(10), null, + null, + Speed.of(5))) + .setAltitudeLoss(1f) + .setAltitudeGain(1f) + .setSensorDistance(Distance.of(12)) + .setHeartRate(69) + .setPower(50f) + .setCadence(3f), + new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new Position( + Instant.parse("2020-02-02T02:03:21Z"), + 3d, 14.002, Distance.of(10), + Altitude.WGS84.of(10), null, + null, + Speed.of(15))) + .setAltitudeLoss(0f) + .setAltitudeGain(0f), + new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new Position( + Instant.parse("2020-02-02T02:03:22Z"), + 3d, 16d, Distance.of(10), + Altitude.WGS84.of(10), null, + null, + Speed.of(15))) + .setAltitudeLoss(0f) + .setAltitudeGain(0f), + new TrackPoint(TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:03:50Z"), + 3d, 16.001, Distance.of(10), + Altitude.WGS84.of(10), null, + null, + Speed.of(10))) + .setAltitudeLoss(0f) + .setAltitudeGain(0f) + .setSpeed(Speed.of(15)) + ), actual); + } + @LargeTest @Test public void importExportTest_timezone() throws IOException { diff --git a/src/androidTest/res/raw/legacy_gpx_trackpointextensions_incorrect.gpx b/src/androidTest/res/raw/legacy_gpx_trackpointextensions_incorrect.gpx new file mode 100644 index 000000000..ea701f1ce --- /dev/null +++ b/src/androidTest/res/raw/legacy_gpx_trackpointextensions_incorrect.gpx @@ -0,0 +1,103 @@ + + + +10 + + + + + + +10 + + + + + + + + + + +c0c0c0 +75c581d0-eef5-4aa2-91a3-66d2c6de4f6d + + +222125.53125 +56 +26 +30 +8543.2900390625 +2.0 +2.0 + + + + +10 + + +15 +1 +1 +10 + + +10 + + +5 +69 +3 +50 +1 +1 +1012 +12 + + + + + +10 + + +15 +0 +0 +10 + + + + +10 + + +15 +0 +0 +10 + + +10 + + +15 +0 +0 +10 + + + + \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java index e2f0975f1..769c73c77 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java @@ -321,51 +321,62 @@ public class GPXTrackExporter implements TrackExporter { printWriter.println(""); { - String trackPointExtensionContent = ""; - - if (trackPoint.hasSpeed()) { - trackPointExtensionContent += "" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "\n"; - } + String trackPointExtensionV2Content = ""; if (trackPoint.hasHeartRate()) { - trackPointExtensionContent += "" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate().getBPM()) + "\n"; + trackPointExtensionV2Content += "" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate().getBPM()) + "\n"; } if (trackPoint.hasCadence()) { - trackPointExtensionContent += "" + CADENCE_FORMAT.format(trackPoint.getCadence().getRPM()) + "\n"; + trackPointExtensionV2Content += "" + CADENCE_FORMAT.format(trackPoint.getCadence().getRPM()) + "\n"; } + if (trackPoint.hasSpeed()) { + trackPointExtensionV2Content += "" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "\n"; + } + + String extensionContent = ""; if (trackPoint.hasPower()) { - trackPointExtensionContent += "" + POWER_FORMAT.format(trackPoint.getPower().getW()) + "\n"; + extensionContent += "" + POWER_FORMAT.format(trackPoint.getPower().getW()) + "\n"; } Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGain() ? (double) tp.getAltitudeGain() : null); if (cumulativeGain != null) { - trackPointExtensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeGain) + "\n"); + extensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeGain) + "\n"); } Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeLoss() ? (double) tp.getAltitudeLoss() : null); if (cumulativeLoss != null) { - trackPointExtensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeLoss) + "\n"); + extensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeLoss) + "\n"); } if (trackPoint.hasHorizontalAccuracy()) { - trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + ""); + extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + ""); } if (trackPoint.hasVerticalAccuracy()) { - trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getVerticalAccuracy().toM()) + ""); + extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getVerticalAccuracy().toM()) + ""); } cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null)); if (cumulativeDistance != null) { - trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(cumulativeDistance.toM()) + "\n"); - trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(trackDistance.plus(cumulativeDistance).toM()) + "\n"); + extensionContent += ("" + DISTANCE_FORMAT.format(cumulativeDistance.toM()) + "\n"); + extensionContent += ("" + DISTANCE_FORMAT.format(trackDistance.plus(cumulativeDistance).toM()) + "\n"); } - if (!trackPointExtensionContent.isEmpty()) { - printWriter.println(""); - printWriter.print(trackPointExtensionContent); - printWriter.println(""); + if (!extensionContent.isEmpty() || !trackPointExtensionV2Content.isEmpty()) { + printWriter.println(""); + + if (!trackPointExtensionV2Content.isEmpty()) { + printWriter.println(""); + printWriter.print(trackPointExtensionV2Content); + printWriter.println(""); + } + + if (!extensionContent.isEmpty()) { + printWriter.print(extensionContent); + } + + printWriter.println(""); } }