diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/ActivityTrackExporter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/ActivityTrackExporter.java index 9548cbec57..d4f54e3a57 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/ActivityTrackExporter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/ActivityTrackExporter.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2024 Carsten Pfeiffer, Daniele Gobbetti, José Rebelo +/* Copyright (C) 2017-2026 Carsten Pfeiffer, Daniele Gobbetti, José Rebelo, Thomas Kuehne This file is part of Gadgetbridge. @@ -16,13 +16,16 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.export; +import androidx.annotation.Nullable; + import java.io.File; import java.io.IOException; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack; public interface ActivityTrackExporter { - void performExport(ActivityTrack track, File targetFile) throws IOException, GPXTrackEmptyException; + void performExport(ActivityTrack track, File targetFile, @Nullable BaseActivitySummary summary) throws IOException, GPXTrackEmptyException; class GPXTrackEmptyException extends Exception { } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/AutoGpxExporter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/AutoGpxExporter.java index 1df6529230..0cb9e51cac 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/AutoGpxExporter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/AutoGpxExporter.java @@ -98,7 +98,7 @@ public class AutoGpxExporter { try (OutputStream outputStream = context.getContentResolver().openOutputStream(targetFile.getUri()); BufferedOutputStream bos = new BufferedOutputStream(outputStream)) { final GPXExporter exporter = new GPXExporter(); - exporter.performExport(activityTrack, bos); + exporter.performExport(activityTrack, bos, summary); } LOG.info("Auto-exported GPX to: {}", targetFile.getUri()); 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 b5381c9718..61ede65667 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporter.java @@ -41,7 +41,9 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.entities.User; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint; import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack; import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; @@ -80,14 +82,14 @@ public class GPXExporter implements ActivityTrackExporter { } @Override - public void performExport(ActivityTrack track, File targetFile) throws IOException, GPXTrackEmptyException { + public void performExport(ActivityTrack track, File targetFile, @Nullable BaseActivitySummary summary) throws IOException, GPXTrackEmptyException { try (FileOutputStream outputStream = new FileOutputStream(targetFile); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { - performExport(track, bufferedOutputStream); + performExport(track, bufferedOutputStream, summary); } } - public void performExport(ActivityTrack track, OutputStream outputStream) throws IOException, GPXTrackEmptyException { + public void performExport(ActivityTrack track, OutputStream outputStream, @Nullable BaseActivitySummary summary) throws IOException, GPXTrackEmptyException { String encoding = StandardCharsets.UTF_8.name(); XmlSerializer ser = Xml.newSerializer(); @@ -111,7 +113,19 @@ public class GPXExporter implements ActivityTrackExporter { + " " + OPENTRACKS_NAMESPACE_URI + " " + OPENTRACKS_XSD); exportMetadata(ser, track); - exportTrack(ser, track); + + // don't localize trackType - it is used by importing applications + final String trackType; + if (summary != null) { + final ActivityKind activityKind = ActivityKind.fromCode(summary.getActivityKind()); + trackType = switch (activityKind) { + case NOT_MEASURED, UNKNOWN, ACTIVITY -> null; + default -> activityKind.name(); + }; + } else { + trackType = null; + } + exportTrack(ser, track, trackType); ser.endTag(NS_GPX_URI, "gpx"); ser.endDocument(); @@ -144,7 +158,7 @@ public class GPXExporter implements ActivityTrackExporter { return DateTimeUtils.formatIso8601UTC(date); } - private void exportTrack(XmlSerializer ser, ActivityTrack track) throws IOException, GPXTrackEmptyException { + private void exportTrack(XmlSerializer ser, ActivityTrack track, @Nullable String trackType) throws IOException, GPXTrackEmptyException { String uuid = ((this.uuid != null) ? this.uuid : UUID.randomUUID()).toString(); ser.startTag(NS_GPX_URI, "trk"); @@ -154,6 +168,10 @@ public class GPXExporter implements ActivityTrackExporter { ser.startTag(NS_GPX_URI, "name").text(trackName).endTag(NS_GPX_URI, "name"); } + if (trackType != null && !trackType.isBlank()) { + ser.startTag(NS_GPX_URI, "type").text(trackType).endTag(NS_GPX_URI, "type"); + } + ser.startTag(NS_GPX_URI, "extensions"); ser.startTag(NS_GPX_URI, OPENTRACKS_PREFIX + ":trackid").text(uuid).endTag(NS_GPX_URI, OPENTRACKS_PREFIX + ":trackid"); ser.endTag(NS_GPX_URI, "extensions"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/opentracks/OpenTracksController.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/opentracks/OpenTracksController.java index f50e32d305..7bc6f8795c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/opentracks/OpenTracksController.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/opentracks/OpenTracksController.java @@ -165,7 +165,7 @@ public class OpenTracksController extends Activity { gpxDir.mkdirs(); final File gpxFile = new File(gpxDir, gpxName + ".gpx"); final GPXExporter gpxExporter = new GPXExporter(); - gpxExporter.performExport(activityTrack, gpxFile); + gpxExporter.performExport(activityTrack, gpxFile, null); LOG.info("Saved GPX received from OpenTracks to {}", gpxFile.getPath()); } catch (IOException | ActivityTrackExporter.GPXTrackEmptyException e) { LOG.error("Error while writing generated GPX file", e); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ActivitySummaryUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ActivitySummaryUtils.java index 037926c3ee..7579c6d8d3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ActivitySummaryUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ActivitySummaryUtils.java @@ -74,7 +74,7 @@ public final class ActivitySummaryUtils { final File gpxFile = new File(rawCacheDir, gpxFileName); final GPXExporter gpxExporter = new GPXExporter(); - gpxExporter.performExport(activityTrack, gpxFile); + gpxExporter.performExport(activityTrack, gpxFile, summary); return gpxFile; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporterTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporterTest.java index 2cd74e85b6..ec65dcb86f 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporterTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/export/GPXExporterTest.java @@ -46,9 +46,11 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.User; import nodomain.freeyourgadget.gadgetbridge.export.ActivityTrackExporter.GPXTrackEmptyException; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint; import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack; import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate; @@ -70,7 +72,7 @@ public class GPXExporterTest extends TestBase { final File tempFile = File.createTempFile("gpx-exporter-test-track", ".gpx"); tempFile.deleteOnExit(); - gpxExporter.performExport(track, tempFile); + gpxExporter.performExport(track, tempFile, null); validateGpxFile(tempFile); } @@ -85,7 +87,7 @@ public class GPXExporterTest extends TestBase { final File tempFile = File.createTempFile("gpx-exporter-test-track", ".gpx"); tempFile.deleteOnExit(); - gpxExporter.performExport(track, tempFile); + gpxExporter.performExport(track, tempFile, null); validateGpxFile(tempFile); } @@ -192,7 +194,9 @@ public class GPXExporterTest extends TestBase { final File tempFile = File.createTempFile("gpx-exporter-test-import-export", ".gpx"); tempFile.deleteOnExit(); - gpxExporter.performExport(track, tempFile); + BaseActivitySummary summary = new BaseActivitySummary(); + summary.setActivityKind(ActivityKind.TRAIL_RUN.getCode()); + gpxExporter.performExport(track, tempFile, summary); byte[] exported = Files.readAllBytes(tempFile.toPath()); byte[] expected = readBinaryResource("/TestGpxExport.gpx"); 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 2abca82b90..fad3615800 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/HuamiActivityDetailsParserTest.java @@ -94,7 +94,7 @@ public class HuamiActivityDetailsParserTest extends TestBase { exporter.setCreator(getClass().getName()); File targetFile = File.createTempFile("gadgetbridge-track", ".gpx"); System.out.println("Writing GPX file: " + targetFile); - exporter.performExport(track, targetFile); + exporter.performExport(track, targetFile, summary); assertTrue(targetFile.length() > 1024); } diff --git a/app/src/test/resources/TestGpxExport.gpx b/app/src/test/resources/TestGpxExport.gpx index b4e7fffdd6..5abb1af9e4 100644 --- a/app/src/test/resources/TestGpxExport.gpx +++ b/app/src/test/resources/TestGpxExport.gpx @@ -1 +1 @@ -Test TrackTest UserTest Trackc5185301-d578-4e52-bb9f-c2a7afa044e2-440.2a description1.43.21.528.29999923706054726.2999992370605471232223.2999992370605478849.2a comment34.299999237060551034540.40000152587890641.400001525878906424344.400001525878906 \ No newline at end of file +Test TrackTest UserTest TrackTRAIL_RUNc5185301-d578-4e52-bb9f-c2a7afa044e2-440.2a description1.43.21.528.29999923706054726.2999992370605471232223.2999992370605478849.2a comment34.299999237060551034540.40000152587890641.400001525878906424344.400001525878906 \ No newline at end of file