From fc6dcc793b09216671c73cd8f130279831015c7b Mon Sep 17 00:00:00 2001 From: Thomas Kuehne Date: Wed, 1 Apr 2026 22:46:07 +0000 Subject: [PATCH] Garmin: export FIT laps as GPX track segments --- .../model/FitActivityTrackProvider.java | 48 +++++++++++++++---- .../devices/garmin/fit/NativeFITMessage.java | 2 +- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/FitActivityTrackProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/FitActivityTrackProvider.java index a19ccd40ce..4fbc54a1e6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/FitActivityTrackProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/FitActivityTrackProvider.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2026 José Rebelo +/* Copyright (C) 2026 José Rebelo, Thomas Kuehne This file is part of Gadgetbridge. @@ -24,12 +24,13 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Iterator; +import java.util.Objects; import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.exception.FitParseException; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitLap; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRecord; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -58,14 +59,43 @@ public class FitActivityTrackProvider implements ActivityTrackProvider { return null; } - final List activityPoints = fitFile.getRecords().stream() - .filter(r -> r instanceof FitRecord) - .map(r -> ((FitRecord) r).toActivityPoint()) - .collect(Collectors.toList()); - final ActivityTrack activityTrack = new ActivityTrack(); activityTrack.setName(summary.getName()); - activityTrack.addTrackPoints(activityPoints); + + final Iterator records = fitFile.getRecords().stream() + .filter(r -> r instanceof FitRecord) + .map(r -> (FitRecord) r) + .iterator(); + + final Iterator lapStarts = fitFile.getRecords().stream() + .filter(record -> record instanceof FitLap) + .map(record -> (FitLap) record) + .filter(lap -> { + Integer event = lap.getEvent(); + if (event != null && event != 9) { + return false; + } + Integer eventType = lap.getEventType(); + return (eventType == null || eventType == 1); + }) + .map(FitLap::getStartTime) + .filter(Objects::nonNull) + .iterator(); + + // skip first lap start + if(lapStarts.hasNext()){ + lapStarts.next(); + } + + long nextLapStart = (lapStarts.hasNext() ? lapStarts.next() : Long.MAX_VALUE); + while (records.hasNext()) { + FitRecord record = records.next(); + if (record.getComputedTimestamp() >= nextLapStart) { + activityTrack.startNewSegment(); + nextLapStart = (lapStarts.hasNext() ? lapStarts.next() : Long.MAX_VALUE); + } + activityTrack.addTrackPoint(record.toActivityPoint()); + } return activityTrack; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/NativeFITMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/NativeFITMessage.java index 610e25ddbd..6ca0c3ef9c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/NativeFITMessage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/NativeFITMessage.java @@ -389,7 +389,7 @@ public class NativeFITMessage { public static NativeFITMessage LAP = new NativeFITMessage(19, "LAP", Arrays.asList( new FieldDefinitionPrimitive(0, BaseType.ENUM, "event"), // 9 lap new FieldDefinitionPrimitive(1, BaseType.ENUM, "event_type"), // 1 stop - new FieldDefinitionPrimitive(2, BaseType.UINT32, "start_time"), + new FieldDefinitionPrimitive(2, BaseType.UINT32, "start_time", FieldDefinitionFactory.FIELD.TIMESTAMP), new FieldDefinitionPrimitive(3, BaseType.SINT32, "start_lat", FieldDefinitionFactory.FIELD.COORDINATE), new FieldDefinitionPrimitive(4, BaseType.SINT32, "start_long", FieldDefinitionFactory.FIELD.COORDINATE), new FieldDefinitionPrimitive(5, BaseType.SINT32, "end_lat", FieldDefinitionFactory.FIELD.COORDINATE),