Compare commits

..

8 Commits

Author SHA1 Message Date
Dennis Guse ab8791a620 Release: v4.28.2 2026-08-22 19:20:38 +02:00
Dennis Guse 7c03085761 GPX: on import ignore TrackPoints without time.
Previous behavior: abort import.

Fixes #2384.
2026-08-19 20:45:23 +02:00
Dennis Guse 12a8686896 Cleanup. 2026-08-19 20:38:05 +02:00
Dennis Guse e12bb967e6 Cleanup. 2026-08-19 20:29:25 +02:00
Dennis Guse d56b018676 Bugfix: when stopping a recording, immediately stop the idle detection timer.
Fixes #2386.
2026-08-19 20:29:25 +02:00
CI/CD Bot by pstorch a6fd701004 chore(deps): update dependency gradle to v9.7.1 2026-08-19 15:34:29 +00:00
Dennis Guse ce26e20571 Sensor: on start register GPS only once.
Part of #2369.
2026-08-17 15:49:14 +02:00
CI/CD Bot by pstorch d3ff2061c6 chore(deps): update dependency androidx.appcompat:appcompat to v1.8.0 2026-08-12 17:34:26 +00:00
13 changed files with 119 additions and 22 deletions
+3 -3
View File
@@ -47,8 +47,8 @@ android {
defaultConfig {
applicationId 'de.dennisguse.opentracks'
versionCode 6733
versionName "v4.28.1"
versionCode 6741
versionName "v4.28.2"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -145,7 +145,7 @@ android {
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
implementation 'androidx.appcompat:appcompat:1.7.1'
implementation 'androidx.appcompat:appcompat:1.8.0'
implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.documentfile:documentfile:1.1.0'
implementation 'androidx.gridlayout:gridlayout:1.1.0'
@@ -0,0 +1,7 @@
v4.28.2: OpenTracks
Changes:
- Import: ignore GPX waypoints without time
Bugfix:
- Only start GPS once
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
@@ -120,6 +120,47 @@ public class GPXTrackImporterTest {
), importedTrackPoints);
}
@LargeTest
@Test
public void gpx_missing_time() throws IOException {
// given
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_missing_time);
// when
// 1. import
importTrackId = importer.importFile(inputStream).get(0);
// then
// 2. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("", importedTrack.activityTypeLocalized());
assertEquals("", importedTrack.description());
assertEquals("20210907_213924.gpx", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 3. trackstatistics
Statistics trackStatistics = importedTrack.statistics();
assertEquals(0, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(0), trackStatistics.movingDuration());
// 4. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
assertEquals(1, importedTrackPoints.size());
TrackPointAssert a = new TrackPointAssert();
a.assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2021-09-07T22:12:00Z"),
30.14185982, -40.3863038, null,
Altitude.WGS84.of(-5), null,
null,
null))
), importedTrackPoints);
}
@LargeTest
@Test
public void gpx_speed_no_namespace() throws IOException {
@@ -285,8 +326,8 @@ public class GPXTrackImporterTest {
public void importExportTest_timezone() throws IOException {
// given
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone)) {
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_timezone);
try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_timezone)) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// when
@@ -0,0 +1,22 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<gpx version="1.1" creator="Cruiser" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<trk>
<name>20210907_213924.gpx</name>
<trkseg>
<trkpt lat="30.14185982" lon="-40.3863038">
<ele>-5</ele>
<hdop>4</hdop>
</trkpt>
<trkpt lat="30.14184657" lon="-40.38670089">
<ele>-5</ele>
<time/>
<hdop>4</hdop>
</trkpt>
<trkpt lat="30.14185982" lon="-40.3863038">
<ele>-5</ele>
<time>2021-09-07T22:12:00Z</time>
<hdop>4</hdop>
</trkpt>
</trkseg>
</trk>
</gpx>
@@ -18,8 +18,11 @@ package de.dennisguse.opentracks.io.file.importer;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.helpers.DefaultHandler;
@@ -178,7 +181,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
zoneOffset = null;
}
case TAG_TRACK_SEGMENT -> onTrackSegmentEnd();
case TAG_TRACK_POINT -> currentSegment.add(createTrackPoint());
case TAG_TRACK_POINT -> {
TrackPoint trackPoint = createTrackPoint();
if (trackPoint != null) currentSegment.add(trackPoint);
}
case TAG_NAME -> {
if (content != null) {
name = content.trim();
@@ -284,8 +290,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
currentSegment.clear();
}
@Nullable
private TrackPoint createTrackPoint() throws ParsingException {
if (TextUtils.isEmpty(time)) return null;
OffsetDateTime parsedTime;
try {
parsedTime = StringUtils.parseTime(time);
@@ -468,7 +476,10 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac
}
TrackPoint trackPoint = createTrackPoint();
if (trackPoint == null) {
Log.w(TAG, "Marker with no TrackPoint");
return;
}
if (!trackPoint.position().hasLocation()) {
Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.position());
return;
@@ -45,8 +45,9 @@ public class GpsHandler extends SensorHandler<Location, Position> {
gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval());
}
//TODO
connect();
if (driver != null) {
driver.updateDriverParameters(getContext(), sensorManager.getHandler());
}
}
};
@@ -21,11 +21,11 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
private static final String TAG = SensorHandler.class.getSimpleName();
private final SensorManager sensorManager;
@VisibleForTesting
public Driver driver;
protected final SensorManager sensorManager;
protected Aggregator<AggregatorInput, AggregatorOutput> aggregator;
protected SensorHandler(SensorManager sensorManager) {
@@ -11,5 +11,9 @@ public interface Driver {
//TODO Remove from interface?
boolean isConnected();
default void updateDriverParameters(Context context, Handler handler) {
throw new UnsupportedOperationException();
}
void disconnect();
}
@@ -57,16 +57,11 @@ public class GpsInternal implements Driver {
return;
}
LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(PreferencesUtils.getMinSamplingInterval().toMillis())
.setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY)
.setMaxUpdateDelayMillis(0)
.build();
if (PermissionRequester.GPS.hasPermission(context)) {
try {
Log.i(TAG, "Register for location updates " + context);
Log.i(TAG, "Register for location updates");
driverObserver.onConnected(null, null);
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat);
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, createLocationRequest(), handler::post, locationListenerCompat);
return;
} catch (SecurityException e) {
Log.e(TAG, "Could not register location listener; permissions not granted.", e);
@@ -76,6 +71,16 @@ public class GpsInternal implements Driver {
driverObserver.onDisconnected();
}
@SuppressWarnings({"MissingPermission"})
@Override
public void updateDriverParameters(Context context, Handler handler) {
if (!isConnected()) return;
Log.i(TAG, "Update for location updates");
driverObserver.onConnected(null, null);
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, createLocationRequest(), handler::post, locationListenerCompat);
}
@SuppressWarnings({"MissingPermission"})
@Override
public void disconnect() {
@@ -87,9 +92,15 @@ public class GpsInternal implements Driver {
driverObserver.onDisconnected();
}
@Override
public boolean isConnected() {
return locationManager != null;
}
private LocationRequestCompat createLocationRequest() {
return new LocationRequestCompat.Builder(PreferencesUtils.getMinSamplingInterval().toMillis())
.setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY)
.setMaxUpdateDelayMillis(0)
.build();
}
}
@@ -120,6 +120,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
}
synchronized void endCurrentTrack() {
handler.removeCallbacks(ON_IDLE);
TrackPoint segmentEnd = trackPointCreator.createSegmentEnd();
insertTrackPoint(segmentEnd, true);
@@ -71,7 +71,6 @@ public class PreferencesUtils {
private static SharedPreferences sharedPreferences;
private static Resources resources;
private static final long LONG_UNSET = Long.MIN_VALUE;
/**
* Must be called during application startup.