From 447d1bb7a319880e7ef8b0be9d6f75d41fd80b3c Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 14 Feb 2026 23:03:40 +0100 Subject: [PATCH] Bugfix: speed and altitude were set to 0m repeatedly (UI only. Data is okay). Fixes #2258. --- .../io/file/importer/ExportImportTest.java | 6 +- .../io/file/importer/TrackPointAssert.java | 1 + .../services/TrackRecordingServiceUITest.java | 112 ++++++++++++++++++ .../opentracks/data/models/Position.java | 2 +- .../opentracks/sensors/SensorManager.java | 1 + .../services/TrackRecordingService.java | 3 +- .../services/handlers/TrackPointCreator.java | 4 +- 7 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceUITest.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index bf12ed3ab..bac727e43 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -89,12 +89,12 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; public class ExportImportTest { @Rule - public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(50, TimeUnit.SECONDS); //TODO 5s + public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS); @Rule public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule(); - //For csv_export_only() as we the timezone is hardcoded in the expectation. + //For csv_export_only() as the timezone is hardcoded in the expectation. @Rule public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin")); @@ -747,7 +747,7 @@ public class ExportImportTest { sensorManager.getAltitudeChangeHandler().setAggregator(aggregatorBarometer); } - private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { + public static void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { Location location = new Location("mock"); location.setLatitude(latitude); location.setLongitude(longitude); diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java index 2c92003f3..e399e5e28 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java @@ -26,6 +26,7 @@ public class TrackPointAssert { Assert.assertEquals("has altitude", expected.position().hasAltitude(), actual.position().hasAltitude()); if (expected.position().hasAltitude()) { + Assert.assertEquals("altitude", expected.position().altitude().getClass(), actual.position().altitude().getClass()); Assert.assertEquals("altitude", expected.position().altitude().toM(), actual.position().altitude().toM(), delta); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceUITest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceUITest.java new file mode 100644 index 000000000..c6f999260 --- /dev/null +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceUITest.java @@ -0,0 +1,112 @@ +package de.dennisguse.opentracks.services; + +import static org.junit.Assert.assertEquals; +import static de.dennisguse.opentracks.services.TrackRecordingService.RECORDING_DATA_UPDATE_INTERVAL; + +import android.content.Context; +import android.content.Intent; +import android.os.Looper; + +import androidx.core.location.LocationManagerCompat; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.GrantPermissionRule; +import androidx.test.rule.ServiceTestRule; + +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import de.dennisguse.opentracks.TestUtil; +import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Speed; +import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.io.file.importer.ExportImportTest; +import de.dennisguse.opentracks.io.file.importer.TrackPointAssert; +import de.dennisguse.opentracks.sensors.driver.GpsInternal; +import de.dennisguse.opentracks.services.handlers.TrackPointCreator; + +@RunWith(AndroidJUnit4.class) +public class TrackRecordingServiceUITest { + + @Rule + public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS); + + @Rule + public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule(); + + private static final Context context = ApplicationProvider.getApplicationContext(); + + @BeforeClass + public static void preSetUp() { + // Prepare looper for Android's message queue + if (Looper.myLooper() == null) Looper.prepare(); + } + + @Test + public void getDataForUI_gps() throws TimeoutException, InterruptedException { + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class))) + .getService(); + RecordingData recordingData; + + // given + TrackPointCreator trackPointCreator = service.getTrackPointCreator(); + + trackPointCreator.setClock("2020-02-02T02:02:02Z"); + + // when + service.startNewTrack(); + //We do not want the real GPS to interfere. + GpsInternal gpsInternal = (GpsInternal)trackPointCreator.getSensorManager().getGpsHandler().driver; + LocationManagerCompat.removeUpdates(gpsInternal.locationManager, gpsInternal.locationListenerCompat); + Thread.sleep(RECORDING_DATA_UPDATE_INTERVAL.toMillis()); + + // then + assertEquals(new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of( Instant.parse("2020-02-02T02:02:02Z")), + null, + null, + null, + null, + null, + null + ), + service.getRecordingDataObservable().getValue().latestTrackPoint()); + + + // when + // In this step, the data is saved (and Aggregator.resetAggregated called), but data should still be shown in the UI. + trackPointCreator.setClock("2020-02-02T02:02:03Z"); + ExportImportTest.sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 1f); + + // then + Thread.sleep(RECORDING_DATA_UPDATE_INTERVAL.toMillis()); + recordingData = service.getRecordingDataObservable().getValue(); + new TrackPointAssert().assertEquals(new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:02:03Z"), + 3.1234567, 14.0014567, null, + Altitude.EGM2008.of(1013.05), null, + null, + Speed.of(15)), + null, + null, + null, + null, + null, + new AltitudeGainLoss(1, 1) + ), + recordingData.latestTrackPoint()); + } +} \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/data/models/Position.java b/src/main/java/de/dennisguse/opentracks/data/models/Position.java index afe0e3eb4..7c4a5855c 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/Position.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/Position.java @@ -8,7 +8,7 @@ import androidx.annotation.Nullable; import java.time.Instant; public record Position( - @Nullable Instant time, + @Nullable Instant time, //TODO It may be a good idea to move time out of Position @Nullable Double latitude, @Nullable Double longitude, @Nullable Distance horizontalAccuracy, diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index ed58df238..40ca90e20 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -126,6 +126,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsHandler.resetAggregated(); } + @VisibleForTesting public GpsHandler getGpsHandler() { return gpsHandler; } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index 4a3e48aac..b7fc63040 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -48,7 +48,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator. private static final String TAG = TrackRecordingService.class.getSimpleName(); - private static final Duration RECORDING_DATA_UPDATE_INTERVAL = Duration.ofSeconds(1); + @VisibleForTesting + public static final Duration RECORDING_DATA_UPDATE_INTERVAL = Duration.ofSeconds(1); public static final RecordingStatus STATUS_DEFAULT = RecordingStatus.notRecording(); public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE; diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java index 59ff7a970..696379cf0 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java @@ -102,10 +102,10 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } if (lastTrackPointUISpeed != null) - position.with(lastTrackPointUISpeed.position().speed()); + position = position.with(lastTrackPointUISpeed.position().speed()); if (lastTrackPointUIAltitude != null) - position.with(lastTrackPointUIAltitude.position().altitude()); + position = position.with(lastTrackPointUIAltitude.position().altitude()); TrackPoint currentTrackPoint = new TrackPoint( null,