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 4f33f7de5..e5af1422a 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 @@ -312,16 +312,16 @@ public class ExportImportTest { assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime()); assertEquals(Instant.parse("2020-02-02T02:02:23Z"), importedTrackStatistics.getStopTime()); - assertEquals(Duration.ofSeconds(20), importedTrackStatistics.getTotalTime()); - assertEquals(Duration.ofSeconds(19), importedTrackStatistics.getMovingTime()); + assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getTotalTime()); + assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime()); // Distance assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance()); // Speed assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed()); - assertEquals(Speed.of(3.0), importedTrackStatistics.getAverageSpeed()); - assertEquals(Speed.of(3.1578947368421053), importedTrackStatistics.getAverageMovingSpeed()); + assertEquals(Speed.of(15), importedTrackStatistics.getAverageSpeed()); + assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed()); // Altitude assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01); 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 ac6cebd69..6000d71ac 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 @@ -83,14 +83,14 @@ public class TrackPointAssert { try { Assert.assertEquals(expected.size(), actual.size()); } catch (AssertionError e) { - throw new AssertionError("Size difference: " + expected.size() + " vs. " + actual.size() + "\nExpected: " + expected + "\n actual: " + actual); + throw new AssertionError("Size difference; expected: " + expected.size() + "; actual: " + actual.size() + "\nExpected: " + expected + "\n actual: " + actual); } for (int i = 0; i < expected.size(); i++) { try { assertEquals(expected.get(i), actual.get(i)); } catch (AssertionError e) { - throw new AssertionError("Expected: " + expected.get(i) + "\n actual: " + actual.get(i), e); + throw new AssertionError("Expected: " + i + " to be " + expected.get(i) + "\n actual: " + actual.get(i), e); } } Assert.assertEquals(expected.size(), actual.size()); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java index 684dc8237..814f01232 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java @@ -64,8 +64,8 @@ import de.dennisguse.opentracks.content.provider.CustomContentProvider; import de.dennisguse.opentracks.io.file.importer.TrackPointAssert; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.sensors.AltitudeSumManager; -import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.stats.TrackStatistics; /** * Tests for the track recording service. @@ -451,10 +451,7 @@ public class TrackRecordingServiceTest { newTrackPoint(trackRecordingService, latitude, longitude, accuracy, speed, System.currentTimeMillis()); } - /** - * Inserts a location and waits for 200ms. - */ - private static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed, long time) { + static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed, long time) { TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(time)) .setLongitude(longitude) .setLatitude(latitude) diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java index c71711b1d..177b437b5 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java @@ -275,8 +275,8 @@ public class TrackRecordingServiceTestLocation { // when TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15); TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 2, 0); - TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 3, 0); - TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 4, 0); + TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 3, 0); // will be ignored + TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 4, 0); // will be ignored TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 0); TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 6, 15); @@ -297,6 +297,20 @@ public class TrackRecordingServiceTestLocation { .setSpeed(Speed.of(15)) .setAltitudeGain(0f) .setAltitudeLoss(0f), + new TrackPoint(TrackPoint.Type.TRACKPOINT, null) + .setLatitude(45) + .setLongitude(35) + .setHorizontalAccuracy(Distance.of(2)) + .setSpeed(Speed.of(0)) + .setAltitudeGain(0f) + .setAltitudeLoss(0f), + new TrackPoint(TrackPoint.Type.TRACKPOINT, null) + .setLatitude(45) + .setLongitude(35) + .setHorizontalAccuracy(Distance.of(5)) + .setSpeed(Speed.of(0)) + .setAltitudeGain(0f) + .setAltitudeLoss(0f), new TrackPoint(TrackPoint.Type.TRACKPOINT, null) .setLatitude(45) .setLongitude(35) diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestStatistics.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestStatistics.java new file mode 100644 index 000000000..09ec38b8f --- /dev/null +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestStatistics.java @@ -0,0 +1,191 @@ +package de.dennisguse.opentracks.services; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import android.content.ContentProvider; +import android.content.Context; +import android.content.Intent; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; +import androidx.test.rule.GrantPermissionRule; +import androidx.test.rule.ServiceTestRule; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import de.dennisguse.opentracks.content.data.TestDataUtil; +import de.dennisguse.opentracks.content.data.Track; +import de.dennisguse.opentracks.content.data.TrackPoint; +import de.dennisguse.opentracks.content.provider.ContentProviderUtils; +import de.dennisguse.opentracks.content.provider.CustomContentProvider; +import de.dennisguse.opentracks.services.sensors.AltitudeSumManager; +import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.stats.TrackStatistics; + +/** + * Tests resulting TrackStatistics. + */ +@RunWith(AndroidJUnit4.class) +public class TrackRecordingServiceTestStatistics { + + @Rule + public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS); + + @Rule + public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); + + private final Context context = ApplicationProvider.getApplicationContext(); + private ContentProviderUtils contentProviderUtils; + + private TrackRecordingService service; + + private final AltitudeSumManager altitudeSumManager = new AltitudeSumManager() { + @Override + public void fill(@NonNull TrackPoint trackPoint) { + trackPoint.setAltitudeGain(0f); + trackPoint.setAltitudeLoss(0f); + } + }; + + @BeforeClass + public static void preSetUp() { + // Prepare looper for Android's message queue + if (Looper.myLooper() == null) Looper.prepare(); + } + + @AfterClass + public static void finalTearDown() { + if (Looper.myLooper() != null) Looper.myLooper().quit(); + } + + @Before + public void setUp() throws TimeoutException { + // Set up the mock content resolver + ContentProvider customContentProvider = new CustomContentProvider() { + }; + customContentProvider.attachInfo(context, null); + + contentProviderUtils = new ContentProviderUtils(context); + tearDown(); + + // Let's use default values. + PreferencesUtils.clear(); + + service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))) + .getService(); + service.getTrackPointCreator().stopGPS(); + } + + @After + public void tearDown() throws TimeoutException { + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class))) + .getService(); + service.getTrackPointCreator().setClock(Clock.systemUTC()); + } + + /** + * Moving time should increase if the previous and current TrackPoint have speed > threshold by the timeDiff(previousTrackPoint, currentTrackPoint). + */ + @MediumTest + @Test + public void movingtime_with_pauses() { + // given + service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochMilli(0), ZoneId.systemDefault())); + Track.Id trackId = service.startNewTrack(); + service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager); + + Function assertMovingTime = expected -> { + Duration actual = contentProviderUtils.getTrack(trackId).getTrackStatistics().getMovingTime(); + assertEquals(Duration.ofSeconds(expected), actual); + return null; + }; + + Function assertTotalTime = expected -> { + Duration actual = contentProviderUtils.getTrack(trackId).getTrackStatistics().getTotalTime(); + assertEquals(Duration.ofSeconds(expected), actual); + return null; + }; + + // when / then + int movingtime_s = 0; + + TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15, 5 * 60000); + assertMovingTime.apply(movingtime_s); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0001, 35.0, 2, 15, 6 * 60000); + TrackRecordingServiceTest.newTrackPoint(service, 45.0002, 35.0, 2, 15, (long) (6.5 * 60000)); + TrackRecordingServiceTest.newTrackPoint(service, 45.0003, 35.0, 2, 15, 7 * 60000); + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 15, 8 * 60000); + movingtime_s += 3 * 60; + assertMovingTime.apply(movingtime_s); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 0, 9 * 60000); //will be ignored + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 0, 10 * 60000); //will be ignored + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 0, 11 * 60000); + assertMovingTime.apply(movingtime_s); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 15, 13 * 60000); + TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 2, 15, (long) (13.5 * 60000)); //will be ignored + TrackRecordingServiceTest.newTrackPoint(service, 45.0005, 35.0, 2, 15, 14 * 60000); + TrackRecordingServiceTest.newTrackPoint(service, 45.0006, 35.0, 2, 15, 15 * 60000); + movingtime_s += 2 * 60; + assertMovingTime.apply(movingtime_s); + assertTotalTime.apply(15 * 60); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0006, 35.0, 2, 0, 16 * 60000); //will be ignored + assertMovingTime.apply(movingtime_s); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0015, 35.0, 2, 0, 17 * 60000); + TrackRecordingServiceTest.newTrackPoint(service, 45.0016, 35.0, 2, 15, 18 * 60000); + assertMovingTime.apply(movingtime_s); + + TrackRecordingServiceTest.newTrackPoint(service, 45.0016, 35.0, 2, 0, 19 * 60000); //TODO we could ignore this TrackPoint + assertMovingTime.apply(movingtime_s); + assertTotalTime.apply(19 * 60); + + service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochSecond(40 * 60), ZoneId.systemDefault())); + assertMovingTime.apply(movingtime_s); + service.pauseCurrentTrack(); + assertTotalTime.apply(40 * 60); + + service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochSecond(41 * 60), ZoneId.systemDefault())); + service.resumeCurrentTrack(); + TrackRecordingServiceTest.newTrackPoint(service, 45.0016, 35.0, 2, 15, 42 * 60000); + assertMovingTime.apply(movingtime_s); + assertTotalTime.apply(41 * 60); + + service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochSecond(50 * 60), ZoneId.systemDefault())); + service.endCurrentTrack(); + assertMovingTime.apply(movingtime_s); + assertTotalTime.apply(49 * 60); + + // then + assertFalse(service.isRecording()); + + TrackStatistics trackStatistics = contentProviderUtils.getTrack(trackId).getTrackStatistics(); + + List trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); + assertEquals(20, trackPoints.size()); + + assertEquals(Duration.ofMinutes(49), trackStatistics.getTotalTime()); + } +} diff --git a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java index c1fb09c22..35fe9795c 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java @@ -1,5 +1,8 @@ package de.dennisguse.opentracks.stats; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Ignore; @@ -16,9 +19,6 @@ import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - @RunWith(AndroidJUnit4.class) public class TrackStatisticsUpdaterTest { @@ -81,18 +81,18 @@ public class TrackStatisticsUpdaterTest { // then TrackStatistics statistics = subject.getTrackStatistics(); - assertEquals(99.58, statistics.getTotalDistance().toM(), 0.01); - assertEquals(Duration.ofSeconds(14), statistics.getTotalTime()); - assertEquals(Duration.ofSeconds(7), statistics.getMovingTime()); + assertEquals(128.03, statistics.getTotalDistance().toM(), 0.01); + assertEquals(Duration.ofSeconds(13), statistics.getTotalTime()); + assertEquals(Duration.ofSeconds(9), statistics.getMovingTime()); assertEquals(2.5, statistics.getMinAltitude(), 0.01); - assertEquals(27.5, statistics.getMaxAltitude(), 0.01); + assertEquals(28.75, statistics.getMaxAltitude(), 0.01); assertEquals(36, statistics.getTotalAltitudeGain(), 0.01); assertEquals(36, statistics.getTotalAltitudeLoss(), 0.01); assertEquals(14.226, statistics.getMaxSpeed().toMPS(), 0.01); assertEquals(14.226, statistics.getAverageMovingSpeed().toMPS(), 0.01); - assertEquals(7.11, statistics.getAverageSpeed().toMPS(), 0.01); + assertEquals(9.84, statistics.getAverageSpeed().toMPS(), 0.01); } @Test @@ -141,9 +141,9 @@ public class TrackStatisticsUpdaterTest { TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); tp2.setSpeed(Speed.of(5f)); TrackPoint tp3 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); - tp2.setSpeed(Speed.of(5f)); + tp3.setSpeed(Speed.of(5f)); TrackPoint tp4 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); - tp2.setSpeed(Speed.of(5f)); + tp4.setSpeed(Speed.of(5f)); tp4.setSensorDistance(Distance.of(5f)); TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); tp5.setSensorDistance(Distance.of(10f)); @@ -200,9 +200,12 @@ public class TrackStatisticsUpdaterTest { TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); + tp2.setSpeed(Speed.of(5f)); TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); tp3.setSensorDistance(Distance.of(5f)); + tp3.setSpeed(Speed.of(5f)); TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); + tp4.setSpeed(Speed.of(5f)); TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); // when @@ -248,8 +251,11 @@ public class TrackStatisticsUpdaterTest { TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); + tp2.setSpeed(Speed.of(5f)); TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); + tp3.setSpeed(Speed.of(5f)); TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); + tp4.setSpeed(Speed.of(5f)); TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); subject.addTrackPoint(tp1, GPS_DISTANCE); diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java index 4f2b48265..a9d3a134b 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java @@ -171,7 +171,13 @@ class TrackRecordingManager { } } - Log.d(TAG, "Not recording TrackPoint, idle"); + if (lastStoredTrackPoint != null && trackPoint.isMoving() != lastStoredTrackPoint.isMoving()) { + // Moving from non-moving to moving or vice versa; required to compute moving time correctly. + insertTrackPoint(trackId, trackPoint); + return true; + } + + Log.d(TAG, "Not recording TrackPoint"); lastTrackPoint = trackPoint; return false; } diff --git a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java index d7af6eb5c..42680476e 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java @@ -68,8 +68,6 @@ public class TrackStatisticsUpdater { private final TrackStatistics currentSegment; // Current segment's last trackPoint private TrackPoint lastTrackPoint; - // Current segment's last moving trackPoint - private TrackPoint lastMovingTrackPoint; public TrackStatisticsUpdater() { this(new TrackStatistics()); @@ -96,7 +94,6 @@ public class TrackStatisticsUpdater { this.speedBuffer_mps = new DoubleRingBuffer(toCopy.speedBuffer_mps); this.lastTrackPoint = toCopy.lastTrackPoint; - this.lastMovingTrackPoint = toCopy.lastMovingTrackPoint; } public TrackStatistics getTrackStatistics() { @@ -116,9 +113,8 @@ public class TrackStatisticsUpdater { * @param minGPSDistance the min recording distance */ public void addTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) { - if (trackPoint.getType() == TrackPoint.Type.SEGMENT_START_MANUAL) { + if (trackPoint.isSegmentStart()) { reset(trackPoint); - return; } if (!currentSegment.isInitialized()) { @@ -129,7 +125,7 @@ public class TrackStatisticsUpdater { currentSegment.setStopTime(trackPoint.getTime()); currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), trackPoint.getTime())); - // Process sensor data + // Process sensor data: barometer if (trackPoint.hasAltitudeGain()) { currentSegment.addTotalAltitudeGain(trackPoint.getAltitudeGain()); } @@ -138,62 +134,46 @@ public class TrackStatisticsUpdater { currentSegment.addTotalAltitudeLoss(trackPoint.getAltitudeLoss()); } - if (trackPoint.hasSensorDistance()) { - currentSegment.addTotalDistance(trackPoint.getSensorDistance()); + //Update absolute (GPS-based) altitude + if (trackPoint.hasAltitude()) { + updateAbsoluteAltitude(trackPoint.getAltitude().toM()); } + // Update total distance + if (trackPoint.hasSensorDistance()) { + // Sensor-based distance/speed + currentSegment.addTotalDistance(trackPoint.getSensorDistance()); + } else if (lastTrackPoint != null && trackPoint.isMoving()) { + // GPS-based distance/speed + // Assumption: we ignore TrackPoints that are not moving as those are likely imprecise GPS measurements + Distance movingDistance = trackPoint.distanceToPrevious(lastTrackPoint); + if (movingDistance != null) { + currentSegment.addTotalDistance(movingDistance); + } + } + + + // Update moving time + if (trackPoint.isMoving() && lastTrackPoint != null && lastTrackPoint.isMoving()) { + Duration movingTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); + if (movingTime.isNegative()) { + throw new RuntimeException("Moving time cannot be negative"); + } + currentSegment.addMovingTime(movingTime); + + // Update max speed + updateSpeed(trackPoint, lastTrackPoint); + } else { + speedBuffer_mps.reset(); + } + + if (trackPoint.isSegmentEnd()) { reset(trackPoint); return; } - //Update absolute (GPS-based) altitude - if (trackPoint.hasAltitude()) { - updateAbsoluteAltitude(trackPoint.getAltitude().toM()); - } - - if (lastTrackPoint == null || lastMovingTrackPoint == null) { - lastTrackPoint = trackPoint; - lastMovingTrackPoint = trackPoint; - return; - } - - if (!trackPoint.hasSensorDistance() - && trackPoint.hasLocation() && lastMovingTrackPoint.hasLocation()) { - // GPS-based distance/speed - Distance movingDistance = trackPoint.distanceToPrevious(lastMovingTrackPoint); - if (movingDistance != null && movingDistance.lessThan(minGPSDistance) && !trackPoint.isMoving()) { - speedBuffer_mps.reset(); - lastTrackPoint = trackPoint; - return; //TOOD Why? Is there nothing to be done afterwards? - } - // Update total distance - currentSegment.addTotalDistance(movingDistance); - } - - Duration movingTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); - if (movingTime.isNegative()) { - lastTrackPoint = trackPoint; - return; - } - - // Update moving time - if (lastTrackPoint.isMoving()) { - currentSegment.addMovingTime(movingTime); - } - - // Update max speed - if (trackPoint.hasSpeed() && lastTrackPoint.hasSpeed()) { - updateSpeed(trackPoint, lastTrackPoint); - } - - if (trackPoint.getType() == TrackPoint.Type.SEGMENT_START_AUTOMATIC) { - reset(trackPoint); - return; - } - lastTrackPoint = trackPoint; - lastMovingTrackPoint = trackPoint; } private void reset(TrackPoint trackPoint) { @@ -203,7 +183,6 @@ public class TrackStatisticsUpdater { currentSegment.reset(trackPoint.getTime()); lastTrackPoint = null; - lastMovingTrackPoint = null; altitudeBuffer_m.reset(); speedBuffer_mps.reset(); }