mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
GPX: export track type
This commit is contained in:
+5
-2
@@ -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 <https://www.gnu.org/licenses/>. */
|
||||
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 {
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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");
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><gpx version="1.1" creator="Gadgetbridge Test" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 https://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd http://opentracksapp.com/xmlschemas/v1 https://raw.githubusercontent.com/OpenTracksApp/OpenTracks/main/doc/opentracks-schema-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:opentracks="http://opentracksapp.com/xmlschemas/v1"><metadata><name>Test Track</name><author><name>Test User</name></author><time>2025-10-17T21:00:00Z</time></metadata><trk><name>Test Track</name><extensions><opentracks:trackid>c5185301-d578-4e52-bb9f-c2a7afa044e2</opentracks:trackid></extensions><trkseg><trkpt lon="9.739380" lat="47.504883"><ele>-440.2</ele><time>2025-10-03T15:10:59Z</time><desc>a description</desc><hdop>1.4</hdop><vdop>3.2</vdop><pdop>1.5</pdop><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>28.299999237060547</gpxtpx:atemp><gpxtpx:depth>26.299999237060547</gpxtpx:depth><gpxtpx:hr>123</gpxtpx:hr><gpxtpx:cad>22</gpxtpx:cad><gpxtpx:speed>23.299999237060547</gpxtpx:speed></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="9.556050" lat="47.608993"><ele>8849.2</ele><time>2025-10-03T15:21:07Z</time><desc>a comment</desc><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>34.29999923706055</gpxtpx:atemp><gpxtpx:depth>10345</gpxtpx:depth></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="9.472961" lat="47.655945"><time>2025-10-03T15:30:00Z</time><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>40.400001525878906</gpxtpx:atemp><gpxtpx:depth>41.400001525878906</gpxtpx:depth><gpxtpx:hr>42</gpxtpx:hr><gpxtpx:cad>43</gpxtpx:cad><gpxtpx:speed>44.400001525878906</gpxtpx:speed></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="-19.000000" lat="-43.000000" /></trkseg></trk></gpx>
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><gpx version="1.1" creator="Gadgetbridge Test" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 https://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd http://opentracksapp.com/xmlschemas/v1 https://raw.githubusercontent.com/OpenTracksApp/OpenTracks/main/doc/opentracks-schema-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2" xmlns="http://www.topografix.com/GPX/1/1" xmlns:opentracks="http://opentracksapp.com/xmlschemas/v1"><metadata><name>Test Track</name><author><name>Test User</name></author><time>2025-10-17T21:00:00Z</time></metadata><trk><name>Test Track</name><type>TRAIL_RUN</type><extensions><opentracks:trackid>c5185301-d578-4e52-bb9f-c2a7afa044e2</opentracks:trackid></extensions><trkseg><trkpt lon="9.739380" lat="47.504883"><ele>-440.2</ele><time>2025-10-03T15:10:59Z</time><desc>a description</desc><hdop>1.4</hdop><vdop>3.2</vdop><pdop>1.5</pdop><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>28.299999237060547</gpxtpx:atemp><gpxtpx:depth>26.299999237060547</gpxtpx:depth><gpxtpx:hr>123</gpxtpx:hr><gpxtpx:cad>22</gpxtpx:cad><gpxtpx:speed>23.299999237060547</gpxtpx:speed></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="9.556050" lat="47.608993"><ele>8849.2</ele><time>2025-10-03T15:21:07Z</time><desc>a comment</desc><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>34.29999923706055</gpxtpx:atemp><gpxtpx:depth>10345</gpxtpx:depth></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="9.472961" lat="47.655945"><time>2025-10-03T15:30:00Z</time><extensions><gpxtpx:TrackPointExtension><gpxtpx:atemp>40.400001525878906</gpxtpx:atemp><gpxtpx:depth>41.400001525878906</gpxtpx:depth><gpxtpx:hr>42</gpxtpx:hr><gpxtpx:cad>43</gpxtpx:cad><gpxtpx:speed>44.400001525878906</gpxtpx:speed></gpxtpx:TrackPointExtension></extensions></trkpt><trkpt lon="-19.000000" lat="-43.000000" /></trkseg></trk></gpx>
|
||||
Reference in New Issue
Block a user