Statistics: used when only the data is needed (instead of passing SegmentStatisticUpdater).

This commit is contained in:
Dennis Guse
2025-10-27 19:26:22 +01:00
parent 920ad5129a
commit e3460d94ed
21 changed files with 197 additions and 150 deletions
@@ -75,7 +75,7 @@ import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
/** /**
* Export a track to {@link TrackFileFormat} and verify that the import is identical. * Export a track to {@link TrackFileFormat} and verify that the import is identical.
@@ -203,20 +203,20 @@ public class ExportImportTest {
setUp(); setUp();
Track track = contentProviderUtils.getTrack(trackId); Track track = contentProviderUtils.getTrack(trackId);
SegmentStatisticUpdater trackStatistics = track.getTrackStatistics(); Statistics trackStatistics = track.getStatistics();
assertEquals(ZoneOffset.of("+01:00"), track.getZoneOffset()); assertEquals(ZoneOffset.of("+01:00"), track.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), trackStatistics.getStartTime()); assertEquals(Instant.parse("2020-02-02T02:02:02Z"), trackStatistics.startTime());
assertEquals(Instant.parse("2020-02-02T02:04:00Z"), trackStatistics.getStopTime()); assertEquals(Instant.parse("2020-02-02T02:04:00Z"), trackStatistics.stopTime());
assertEquals(Duration.ofSeconds(56), trackStatistics.getTotalTime()); assertEquals(Duration.ofSeconds(56), trackStatistics.totalTime());
assertEquals(Duration.ofSeconds(26), trackStatistics.getMovingTime()); //TODO Likely too low assertEquals(Duration.ofSeconds(26), trackStatistics.movingTime()); //TODO Likely too low
// Distance // Distance
assertEquals(222049.34375, trackStatistics.getTotalDistance().toM(), 0.01); //TODO Too low assertEquals(222049.34375, trackStatistics.totalDistance().toM(), 0.01); //TODO Too low
// Speed // Speed
assertEquals(8540.359, trackStatistics.getMaxSpeed().toMPS(), 0.01); assertEquals(8540.359, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(3965.166, trackStatistics.getAverageSpeed().toMPS(), 0.01); assertEquals(3965.166, trackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(8540.359, trackStatistics.getAverageMovingSpeed().toMPS(), 0.01); assertEquals(8540.359, trackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
@@ -224,8 +224,8 @@ public class ExportImportTest {
assertEquals(999.122, trackStatistics.getMinAltitude(), 0.01); assertEquals(999.122, trackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.25, trackStatistics.getMaxAltitude(), 0.01); assertEquals(1020.25, trackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, trackStatistics.getTotalAltitudeGain(), 0.01); assertEquals(2, trackStatistics.altitudeGainLoss().gain_m(), 0.01);
assertEquals(2, trackStatistics.getTotalAltitudeLoss(), 0.01); assertEquals(2, trackStatistics.altitudeGainLoss().loss_m(), 0.01);
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
new TrackPointAssert().assertEquals(List.of( new TrackPointAssert().assertEquals(List.of(
@@ -334,29 +334,29 @@ public class ExportImportTest {
a.assertEquals(trackPoints, actual); a.assertEquals(trackPoints, actual);
// 3. trackstatistics // 3. trackstatistics
SegmentStatisticUpdater importedTrackStatistics = importedTrack.getTrackStatistics(); Statistics importedTrackStatistics = importedTrack.getStatistics();
// Time // Time
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset()); assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime()); assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.startTime());
assertEquals(Instant.parse("2020-02-02T02:04:00Z"), importedTrackStatistics.getStopTime()); assertEquals(Instant.parse("2020-02-02T02:04:00Z"), importedTrackStatistics.stopTime());
assertEquals(Duration.ofSeconds(56), importedTrackStatistics.getTotalTime()); assertEquals(Duration.ofSeconds(56), importedTrackStatistics.totalTime());
assertEquals(Duration.ofSeconds(26), importedTrackStatistics.getMovingTime()); assertEquals(Duration.ofSeconds(26), importedTrackStatistics.movingTime());
// Distance // Distance
assertEquals(222049.421, importedTrackStatistics.getTotalDistance().toM(), 0.01); assertEquals(222049.421, importedTrackStatistics.totalDistance().toM(), 0.01);
// Speed // Speed
assertEquals(8540.362, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01); assertEquals(8540.362, importedTrackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(3965.168, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01); assertEquals(3965.168, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(8540.362, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01); assertEquals(8540.362, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
// Altitude // Altitude
assertEquals(999.122, importedTrackStatistics.getMinAltitude(), 0.01); assertEquals(999.122, importedTrackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.25, importedTrackStatistics.getMaxAltitude(), 0.01); assertEquals(1020.25, importedTrackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01); assertEquals(2, importedTrackStatistics.altitudeGainLoss().gain_m(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01); assertEquals(2, importedTrackStatistics.altitudeGainLoss().loss_m(), 0.01);
// 4. markers // 4. markers
@@ -479,29 +479,29 @@ public class ExportImportTest {
), actual); ), actual);
// 3. trackstatistics // 3. trackstatistics
SegmentStatisticUpdater importedTrackStatistics = importedTrack.getTrackStatistics(); Statistics importedTrackStatistics = importedTrack.getStatistics();
// Time // Time
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset()); assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime()); assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.startTime());
assertEquals(Instant.parse("2020-02-02T02:03:50Z"), importedTrackStatistics.getStopTime()); assertEquals(Instant.parse("2020-02-02T02:03:50Z"), importedTrackStatistics.stopTime());
assertEquals(Duration.ofSeconds(107), importedTrackStatistics.getTotalTime()); assertEquals(Duration.ofSeconds(107), importedTrackStatistics.totalTime());
assertEquals(Duration.ofSeconds(107), importedTrackStatistics.getMovingTime()); assertEquals(Duration.ofSeconds(107), importedTrackStatistics.movingTime());
// Distance // Distance
assertEquals(222271.734, importedTrackStatistics.getTotalDistance().toM(), 0.01); assertEquals(222271.734, importedTrackStatistics.totalDistance().toM(), 0.01);
// Speed // Speed
assertEquals(2077.305, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01); assertEquals(2077.305, importedTrackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(2077.305, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01); assertEquals(2077.305, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(2077.305, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01); assertEquals(2077.305, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
// Altitude // Altitude
assertEquals(999.099, importedTrackStatistics.getMinAltitude(), 0.01); assertEquals(999.099, importedTrackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.2, importedTrackStatistics.getMaxAltitude(), 0.01); assertEquals(1020.2, importedTrackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01); assertEquals(2, importedTrackStatistics.altitudeGainLoss().gain_m(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01); assertEquals(2, importedTrackStatistics.altitudeGainLoss().loss_m(), 0.01);
// 4. markers // 4. markers
assertMarkers(); assertMarkers();
@@ -34,7 +34,7 @@ import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter; import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
/** /**
* Test that legacy KML/GPX formats can still be imported. * Test that legacy KML/GPX formats can still be imported.
@@ -149,9 +149,9 @@ public class GPXTrackImporterTest {
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType()); assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
// 3. trackstatistics // 3. trackstatistics
SegmentStatisticUpdater trackStatistics = importedTrack.getTrackStatistics(); Statistics trackStatistics = importedTrack.getStatistics();
assertEquals(0.75, trackStatistics.getMaxSpeed().toMPS(), 0.01); assertEquals(0.75, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.getMovingTime()); assertEquals(Duration.ofSeconds(101), trackStatistics.movingTime());
// 4. trackpoints // 4. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -204,9 +204,9 @@ public class GPXTrackImporterTest {
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType()); assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
// 3. trackstatistics // 3. trackstatistics
SegmentStatisticUpdater trackStatistics = importedTrack.getTrackStatistics(); Statistics trackStatistics = importedTrack.getStatistics();
assertEquals(5.0, trackStatistics.getMaxSpeed().toMPS(), 0.01); assertEquals(5.0, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.getMovingTime()); assertEquals(Duration.ofSeconds(101), trackStatistics.movingTime());
// 4. trackpoints // 4. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -22,6 +22,7 @@ import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
import de.dennisguse.opentracks.stats.Statistics;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class TrackRecordingServiceNotificationManagerTest { public class TrackRecordingServiceNotificationManagerTest {
@@ -29,10 +30,10 @@ public class TrackRecordingServiceNotificationManagerTest {
private final Context context = ApplicationProvider.getApplicationContext(); private final Context context = ApplicationProvider.getApplicationContext();
@Mock @Mock
private TrackPoint trackPointMock; private TrackPoint trackPointMock; //TODO No mock
@Mock @Mock
private SegmentStatisticUpdater trackStatisticsMock; private SegmentStatisticUpdater trackStatisticsMock; //TODO only use Statistic (not mock)
@Mock @Mock
private NotificationCompat.Builder notificationCompatBuilder; private NotificationCompat.Builder notificationCompatBuilder;
@@ -45,7 +46,20 @@ public class TrackRecordingServiceNotificationManagerTest {
when(trackPointMock.hasHorizontalAccuracy()).thenReturn(true); when(trackPointMock.hasHorizontalAccuracy()).thenReturn(true);
when(trackPointMock.getHorizontalAccuracy()).thenReturn(Distance.of(999f)); when(trackPointMock.getHorizontalAccuracy()).thenReturn(Distance.of(999f));
when(trackPointMock.getSpeed()).thenReturn(Speed.of(0)); when(trackPointMock.getSpeed()).thenReturn(Speed.of(0));
when(trackStatisticsMock.getTotalDistance()).thenReturn(Distance.of(0)); when(trackStatisticsMock.getStatistics()).thenReturn(new Statistics(
null,
null,
null,
null,
Distance.of(0),
false,
null,
null,
null,
null,
null,
null
));
when(notificationCompatBuilder.setOnlyAlertOnce(anyBoolean())) when(notificationCompatBuilder.setOnlyAlertOnce(anyBoolean()))
.thenReturn(notificationCompatBuilder); .thenReturn(notificationCompatBuilder);
@@ -192,8 +192,8 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack(); service.endCurrentTrack();
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, pauseTime, 0, 1, 1, 0, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, pauseTime, 0, 1, 1, 0, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
new TrackPointAssert().assertEquals(List.of( new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
@@ -208,8 +208,8 @@ public class TrackRecordingServiceRecordingTest {
service.resumeTrack(trackId); service.resumeTrack(trackId);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, resumeTime, 0, 1, 1, 0, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, resumeTime, 0, 1, 1, 0, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
new TrackPointAssert().assertEquals(List.of( new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
@@ -341,24 +341,24 @@ public class TrackRecordingServiceRecordingTest {
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String gps2 = "2020-02-02T02:02:06Z"; String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 15);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, gps2, 11.113178253173828f, 4, 4, 15, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, gps2, 11.113178253173828f, 4, 4, 15, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String gps3 = "2020-02-02T02:02:08Z"; String gps3 = "2020-02-02T02:02:08Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 15);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, gps3, 22.226356506347656, 6, 6, 15, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, gps3, 22.226356506347656, 6, 6, 15, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
@@ -367,8 +367,8 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack(); service.endCurrentTrack();
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 22.226356506347656, 10, 10, 15, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 22.226356506347656, 10, 10, 15, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
new TrackPointAssert().assertEquals(List.of( new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
@@ -421,21 +421,21 @@ public class TrackRecordingServiceRecordingTest {
// then // then
SegmentStatisticUpdater gps1Statistics = new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f); SegmentStatisticUpdater gps1Statistics = new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f);
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics()); assertEquals(gps1Statistics.getStatistics(), contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String gps2 = "2020-02-02T02:02:06Z"; String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.00001, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.00001, 35.0, 1, 15);
// then // then
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics()); assertEquals(gps1Statistics.getStatistics(), contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String gps3 = "2020-02-02T02:02:08Z"; String gps3 = "2020-02-02T02:02:08Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.00002, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.00002, 35.0, 1, 15);
// then // then
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics()); assertEquals(gps1Statistics.getStatistics(), contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String stopTime = "2020-02-02T02:02:12Z"; String stopTime = "2020-02-02T02:02:12Z";
@@ -443,8 +443,8 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack(); service.endCurrentTrack();
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 2.222635507583618, 10, 10, 15, 0f, 0f) assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 2.222635507583618, 10, 10, 15, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getTrackStatistics()); , contentProviderUtils.getTrack(trackId).getStatistics());
new TrackPointAssert().assertEquals(List.of( new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
@@ -594,14 +594,16 @@ public class TrackRecordingServiceRecordingTest {
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f), contentProviderUtils.getTrack(trackId).getTrackStatistics()); assertEquals(new SegmentStatisticUpdater(startTime, gps1, 0, 1, 1, 15, 0f, 0f).getStatistics(),
contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
String gps2 = "2020-02-02T02:02:06Z"; String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15); TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15);
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, gps2, 11113.275390625, 4, 4, 2778.31884765625f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString()); assertEquals(new SegmentStatisticUpdater(startTime, gps2, 11113.275390625, 4, 4, 2778.31884765625f, 0f, 0f).getStatistics(),
contentProviderUtils.getTrack(trackId).getStatistics());
// when // when
@@ -610,7 +612,8 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack(); service.endCurrentTrack();
// then // then
assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 11113.275390625, 10, 10, 1111.3275390625f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString()); assertEquals(new SegmentStatisticUpdater(startTime, stopTime, 11113.275390625, 10, 10, 1111.3275390625f, 0f, 0f).getStatistics()
, contentProviderUtils.getTrack(trackId).getStatistics());
// then // then
@@ -56,11 +56,11 @@ public class VoiceAnnouncementManagerTest {
// when // when
SegmentStatisticUpdater statistics = new SegmentStatisticUpdater(); SegmentStatisticUpdater statistics = new SegmentStatisticUpdater();
statistics.setTotalDistance(Distance.ofKilometer(13)); statistics.setTotalDistance(Distance.ofKilometer(13));
voiceAnnouncementManager.start(statistics); voiceAnnouncementManager.start(statistics.getStatistics());
assertEquals(Distance.of(15000), voiceAnnouncementManager.getNextTotalDistance()); assertEquals(Distance.of(15000), voiceAnnouncementManager.getNextTotalDistance());
statistics.setTotalDistance(Distance.of(15100)); statistics.setTotalDistance(Distance.of(15100));
voiceAnnouncementManager.start(statistics); voiceAnnouncementManager.start(statistics.getStatistics());
assertEquals(Distance.of(20000), voiceAnnouncementManager.getNextTotalDistance()); assertEquals(Distance.of(20000), voiceAnnouncementManager.getNextTotalDistance());
} }
@@ -76,11 +76,11 @@ public class VoiceAnnouncementManagerTest {
// when // when
SegmentStatisticUpdater statistics = new SegmentStatisticUpdater(); SegmentStatisticUpdater statistics = new SegmentStatisticUpdater();
statistics.setTotalTime(Duration.ofSeconds(91)); statistics.setTotalTime(Duration.ofSeconds(91));
voiceAnnouncementManager.start(statistics); voiceAnnouncementManager.start(statistics.getStatistics());
assertEquals(Duration.ofSeconds(95), voiceAnnouncementManager.getNextTotalTime()); assertEquals(Duration.ofSeconds(95), voiceAnnouncementManager.getNextTotalTime());
statistics.setTotalTime(Duration.ofSeconds(95)); statistics.setTotalTime(Duration.ofSeconds(95));
voiceAnnouncementManager.start(statistics); voiceAnnouncementManager.start(statistics.getStatistics());
assertEquals(Duration.ofSeconds(100), voiceAnnouncementManager.getNextTotalTime()); assertEquals(Duration.ofSeconds(100), voiceAnnouncementManager.getNextTotalTime());
} }
@@ -68,14 +68,14 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
viewBinding.trackEditDescription.setText(track.getDescription()); viewBinding.trackEditDescription.setText(track.getDescription());
viewBinding.time.setText(StringUtils.formatElapsedTime(track.getTrackStatistics().getMovingTime())); viewBinding.time.setText(StringUtils.formatElapsedTime(track.getStatistics().movingTime()));
{ {
Pair<String, String> parts = SpeedFormatter.Builder() Pair<String, String> parts = SpeedFormatter.Builder()
.setUnit(PreferencesUtils.getUnitSystem()) .setUnit(PreferencesUtils.getUnitSystem())
.setReportSpeedOrPace(PreferencesUtils.isReportSpeed(track)) .setReportSpeedOrPace(PreferencesUtils.isReportSpeed(track))
.build(this) .build(this)
.getSpeedParts(track.getTrackStatistics().getAverageMovingSpeed()); .getSpeedParts(track.getStatistics().getAverageMovingSpeed());
viewBinding.speed.setText(parts.first); viewBinding.speed.setText(parts.first);
viewBinding.speedUnit.setText(parts.second); viewBinding.speedUnit.setText(parts.second);
} }
@@ -84,7 +84,7 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
Pair<String, String> parts = DistanceFormatter.Builder() Pair<String, String> parts = DistanceFormatter.Builder()
.setUnit(PreferencesUtils.getUnitSystem()) .setUnit(PreferencesUtils.getUnitSystem())
.build(this) .build(this)
.getDistanceParts(track.getTrackStatistics().getTotalDistance()); .getDistanceParts(track.getStatistics().totalDistance());
viewBinding.distance.setText(parts.first); viewBinding.distance.setText(parts.first);
viewBinding.distanceUnit.setText(parts.second); viewBinding.distanceUnit.setText(parts.second);
} }
@@ -53,8 +53,9 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns; import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns; import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.SegmentStatisticUpdater;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.ui.markers.MarkerUtils; import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.FileUtils; import de.dennisguse.opentracks.util.FileUtils;
@@ -314,7 +315,7 @@ public class ContentProviderUtils {
private ContentValues createContentValues(Track track) { private ContentValues createContentValues(Track track) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
SegmentStatisticUpdater trackStatistics = track.getTrackStatistics(); Statistics trackStatistics = track.getStatistics();
if (track.getId() != null) { if (track.getId() != null) {
values.put(TracksColumns._ID, track.getId().id()); values.put(TracksColumns._ID, track.getId().id());
@@ -325,30 +326,38 @@ public class ContentProviderUtils {
values.put(TracksColumns.ACTIVITY_TYPE, track.getActivityType() != null ? track.getActivityType().getId() : null); values.put(TracksColumns.ACTIVITY_TYPE, track.getActivityType() != null ? track.getActivityType().getId() : null);
values.put(TracksColumns.ACTIVITY_TYPE_LOCALIZED, track.getActivityTypeLocalized()); values.put(TracksColumns.ACTIVITY_TYPE_LOCALIZED, track.getActivityTypeLocalized());
values.put(TracksColumns.STARTTIME_OFFSET, track.getZoneOffset().getTotalSeconds()); values.put(TracksColumns.STARTTIME_OFFSET, track.getZoneOffset().getTotalSeconds());
if (trackStatistics.getStartTime() != null) { if (trackStatistics.startTime() != null) {
values.put(TracksColumns.STARTTIME, trackStatistics.getStartTime().toEpochMilli()); values.put(TracksColumns.STARTTIME, trackStatistics.startTime().toEpochMilli());
} }
if (trackStatistics.getStopTime() != null) { if (trackStatistics.stopTime() != null) {
values.put(TracksColumns.STOPTIME, trackStatistics.getStopTime().toEpochMilli()); values.put(TracksColumns.STOPTIME, trackStatistics.stopTime().toEpochMilli());
} }
values.put(TracksColumns.TOTALDISTANCE, trackStatistics.getTotalDistance().toM()); values.put(TracksColumns.TOTALDISTANCE, trackStatistics.totalDistance().toM());
values.put(TracksColumns.TOTALTIME, trackStatistics.getTotalTime().toMillis()); values.put(TracksColumns.TOTALTIME, trackStatistics.totalTime().toMillis());
values.put(TracksColumns.MOVINGTIME, trackStatistics.getMovingTime().toMillis()); values.put(TracksColumns.MOVINGTIME, trackStatistics.movingTime().toMillis());
values.put(TracksColumns.AVGSPEED, trackStatistics.getAverageSpeed().toMPS()); values.put(TracksColumns.AVGSPEED, trackStatistics.getAverageSpeed().toMPS());
values.put(TracksColumns.AVGMOVINGSPEED, trackStatistics.getAverageMovingSpeed().toMPS()); values.put(TracksColumns.AVGMOVINGSPEED, trackStatistics.getAverageMovingSpeed().toMPS());
values.put(TracksColumns.MAXSPEED, trackStatistics.getMaxSpeed().toMPS()); values.put(TracksColumns.MAXSPEED, trackStatistics.maxSpeed().toMPS());
values.put(TracksColumns.MIN_ALTITUDE, trackStatistics.getMinAltitude());
values.put(TracksColumns.MAX_ALTITUDE, trackStatistics.getMaxAltitude()); if (track.getTrackStatistics().hasAltitudeExtremities()) {
values.put(TracksColumns.ALTITUDE_GAIN, trackStatistics.getTotalAltitudeGain()); values.put(TracksColumns.MIN_ALTITUDE, trackStatistics.getMinAltitude());
values.put(TracksColumns.ALTITUDE_LOSS, trackStatistics.getTotalAltitudeLoss()); values.put(TracksColumns.MAX_ALTITUDE, trackStatistics.getMaxAltitude());
}
if (trackStatistics.altitudeGainLoss() != null) {
values.put(TracksColumns.ALTITUDE_GAIN, trackStatistics.altitudeGainLoss().gain_m());
values.put(TracksColumns.ALTITUDE_LOSS, trackStatistics.altitudeGainLoss().loss_m());
}
return values; return values;
} }
//TODO Use Statistics
public void updateTrackStatistics(@NonNull Track.Id trackId, @NonNull SegmentStatisticUpdater trackStatistics) { public void updateTrackStatistics(@NonNull Track.Id trackId, @NonNull SegmentStatisticUpdater trackStatistics) {
contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(trackStatistics), TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())}); contentResolver.update(TracksColumns.CONTENT_URI, createContentValues(trackStatistics), TracksColumns._ID + "=?", new String[]{Long.toString(trackId.id())});
} }
//TODO Use Statistics
private ContentValues createContentValues(SegmentStatisticUpdater trackStatistics) { private ContentValues createContentValues(SegmentStatisticUpdater trackStatistics) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
if (trackStatistics.getStartTime() != null) { if (trackStatistics.getStartTime() != null) {
@@ -26,6 +26,7 @@ public record Speed(double speed_mps) {
return of(Distance.ofKilometer(speed_kmh), Duration.ofHours(1)); return of(Distance.ofKilometer(speed_kmh), Duration.ofHours(1));
} }
//TODO Like Duration.ZERO
public static Speed zero() { public static Speed zero() {
return of(0.0); return of(0.0);
} }
@@ -39,7 +39,7 @@ import de.dennisguse.opentracks.databinding.StatisticsRecordedBinding;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
/** /**
@@ -171,12 +171,12 @@ public class StatisticsRecordedFragment extends Fragment {
} }
private void updateUI() { private void updateUI() {
SegmentStatisticUpdater trackStatistics = track.getTrackStatistics(); Statistics trackStatistics = track.getStatistics();
// Set total distance // Set total distance
{ {
Pair<String, String> parts = DistanceFormatter.Builder() Pair<String, String> parts = DistanceFormatter.Builder()
.setUnit(unitSystem) .setUnit(unitSystem)
.build(getContext()).getDistanceParts(trackStatistics.getTotalDistance()); .build(getContext()).getDistanceParts(trackStatistics.totalDistance());
viewBinding.statsDistanceValue.setText(parts.first); viewBinding.statsDistanceValue.setText(parts.first);
viewBinding.statsDistanceUnit.setText(parts.second); viewBinding.statsDistanceUnit.setText(parts.second);
@@ -187,8 +187,8 @@ public class StatisticsRecordedFragment extends Fragment {
// Set time and start datetime // Set time and start datetime
{ {
viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getMovingTime())); viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.movingTime()));
viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getTotalTime())); viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.totalTime()));
} }
SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(preferenceReportSpeed).build(getContext()); SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(preferenceReportSpeed).build(getContext());
@@ -205,7 +205,7 @@ public class StatisticsRecordedFragment extends Fragment {
{ {
viewBinding.statsMaxSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace); viewBinding.statsMaxSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace);
Pair<String, String> parts = formatter.getSpeedParts(trackStatistics.getMaxSpeed()); Pair<String, String> parts = formatter.getSpeedParts(trackStatistics.maxSpeed());
viewBinding.statsMaxSpeedValue.setText(parts.first); viewBinding.statsMaxSpeedValue.setText(parts.first);
viewBinding.statsMaxSpeedUnit.setText(parts.second); viewBinding.statsMaxSpeedUnit.setText(parts.second);
} }
@@ -221,8 +221,8 @@ public class StatisticsRecordedFragment extends Fragment {
// Set altitude gain and loss // Set altitude gain and loss
{ {
Float altitudeGain_m = trackStatistics.getTotalAltitudeGain(); Float altitudeGain_m = trackStatistics.altitudeGainLoss() != null ? trackStatistics.altitudeGainLoss().gain_m() : null;
Float altitudeLoss_m = trackStatistics.getTotalAltitudeLoss(); Float altitudeLoss_m = trackStatistics.altitudeGainLoss() != null ? trackStatistics.altitudeGainLoss().loss_m() : null;
Pair<String, String> parts; Pair<String, String> parts;
@@ -39,7 +39,7 @@ import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Position; import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
/** /**
@@ -279,18 +279,16 @@ public class GPXTrackExporter implements TrackExporter {
printWriter.println("<opentracks:typeTranslated>" + StringUtils.formatCData(track.getActivityTypeLocalized()) + "</opentracks:typeTranslated>"); printWriter.println("<opentracks:typeTranslated>" + StringUtils.formatCData(track.getActivityTypeLocalized()) + "</opentracks:typeTranslated>");
} }
SegmentStatisticUpdater trackStatistics = track.getTrackStatistics(); Statistics trackStatistics = track.getStatistics();
printWriter.println("<gpxtrkx:TrackStatsExtension>"); printWriter.println("<gpxtrkx:TrackStatsExtension>");
printWriter.println("<gpxtrkx:Distance>" + trackStatistics.getTotalDistance().toM() + "</gpxtrkx:Distance>"); printWriter.println("<gpxtrkx:Distance>" + trackStatistics.totalDistance().toM() + "</gpxtrkx:Distance>");
printWriter.println("<gpxtrkx:TimerTime>" + trackStatistics.getTotalTime().getSeconds() + "</gpxtrkx:TimerTime>"); printWriter.println("<gpxtrkx:TimerTime>" + trackStatistics.totalTime().getSeconds() + "</gpxtrkx:TimerTime>");
printWriter.println("<gpxtrkx:MovingTime>" + trackStatistics.getMovingTime().getSeconds() + "</gpxtrkx:MovingTime>"); printWriter.println("<gpxtrkx:MovingTime>" + trackStatistics.movingTime().getSeconds() + "</gpxtrkx:MovingTime>");
printWriter.println("<gpxtrkx:StoppedTime>" + trackStatistics.getStoppedTime().getSeconds() + "</gpxtrkx:StoppedTime>"); printWriter.println("<gpxtrkx:StoppedTime>" + trackStatistics.getStoppedTime().getSeconds() + "</gpxtrkx:StoppedTime>");
printWriter.println("<gpxtrkx:MaxSpeed>" + trackStatistics.getMaxSpeed().toMPS() + "</gpxtrkx:MaxSpeed>"); printWriter.println("<gpxtrkx:MaxSpeed>" + trackStatistics.maxSpeed().toMPS() + "</gpxtrkx:MaxSpeed>");
if (trackStatistics.hasTotalAltitudeGain()) { if (trackStatistics.altitudeGainLoss() != null) {
printWriter.println("<gpxtrkx:Ascent>" + trackStatistics.getTotalAltitudeGain() + "</gpxtrkx:Ascent>"); printWriter.println("<gpxtrkx:Ascent>" + trackStatistics.altitudeGainLoss().gain_m() + "</gpxtrkx:Ascent>");
} printWriter.println("<gpxtrkx:Descent>" + trackStatistics.altitudeGainLoss().loss_m() + "</gpxtrkx:Descent>");
if (trackStatistics.hasTotalAltitudeLoss()) {
printWriter.println("<gpxtrkx:Descent>" + trackStatistics.getTotalAltitudeLoss() + "</gpxtrkx:Descent>");
} }
printWriter.println("</gpxtrkx:TrackStatsExtension>"); printWriter.println("</gpxtrkx:TrackStatsExtension>");
@@ -20,12 +20,13 @@ public record RecordingData(Track track, TrackPoint latestTrackPoint, SensorData
return track.getActivityTypeLocalized(); return track.getActivityTypeLocalized();
} }
@Deprecated
@NonNull @NonNull
public SegmentStatisticUpdater getStatisticsTrack() { public Statistics getStatisticsTrack() {
if (track == null) { if (track == null) {
return new SegmentStatisticUpdater(); return new SegmentStatisticUpdater().getStatistics();
} }
return track.getTrackStatistics(); return track.getTrackStatistics().getStatistics();
} }
} }
@@ -124,7 +124,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
ALTITUDE_CORRECTION_MANAGER.correctAltitude(context, current.first); ALTITUDE_CORRECTION_MANAGER.correctAltitude(context, current.first);
Track track = contentProviderUtils.getTrack(trackId); //Get copy Track track = contentProviderUtils.getTrack(trackId); //Get copy TODO: Avoid re-loading data from DB
if (track == null) { if (track == null) {
Log.w(TAG, "Requesting data if not recording is taking place, should not be done."); Log.w(TAG, "Requesting data if not recording is taking place, should not be done.");
return null; return null;
@@ -194,7 +194,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
startSensors(); startSensors();
voiceAnnouncementManager.start(trackRecordingManager.getTrackStatistics()); voiceAnnouncementManager.start(trackRecordingManager.getTrackStatistics().getStatistics());
notificationManager.onRecordingStarted(this, recordingStatus.trackId()); notificationManager.onRecordingStarted(this, recordingStatus.trackId());
} }
@@ -118,7 +118,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
previousLocationWasAccurate = currentLocationWasAccurate; previousLocationWasAccurate = currentLocationWasAccurate;
} }
notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(recordingData.getStatisticsTrack().getTotalDistance()))); notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(recordingData.getStatisticsTrack().totalDistance())));
String formattedSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context).formatSpeed(recordingData.latestTrackPoint().getSpeed()); String formattedSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context).formatSpeed(recordingData.latestTrackPoint().getSpeed());
notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, formattedSpeed)); notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, formattedSpeed));
notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy)); notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy));
@@ -37,7 +37,7 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.ui.intervals.IntervalStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatistics;
/** /**
@@ -53,7 +53,7 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
private TTSManager voiceAnnouncement; private TTSManager voiceAnnouncement;
private SegmentStatisticUpdater trackStatistics; private Statistics trackStatistics;
private static final Distance DISTANCE_OFF = Distance.of(Double.MAX_VALUE); private static final Distance DISTANCE_OFF = Distance.of(Double.MAX_VALUE);
private Distance distanceFrequency = DISTANCE_OFF; private Distance distanceFrequency = DISTANCE_OFF;
@@ -79,13 +79,13 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
intervalStatistics = new IntervalStatistics(intervalDistance); intervalStatistics = new IntervalStatistics(intervalDistance);
} }
public void start(@Nullable SegmentStatisticUpdater trackStatistics) { public void start(@Nullable Statistics trackStatistics) {
voiceAnnouncement = new TTSManager(context); voiceAnnouncement = new TTSManager(context);
voiceAnnouncement.start(); voiceAnnouncement.start();
update(trackStatistics); update(trackStatistics);
} }
void update(@Nullable SegmentStatisticUpdater trackStatistics) { void update(@Nullable Statistics trackStatistics) {
this.trackStatistics = trackStatistics; this.trackStatistics = trackStatistics;
updateNextDuration(); updateNextDuration();
updateNextTaskDistance(); updateNextTaskDistance();
@@ -126,12 +126,12 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
} }
boolean announce = false; boolean announce = false;
this.trackStatistics = track.getTrackStatistics(); this.trackStatistics = track.getStatistics();
if (trackStatistics.getTotalDistance().greaterThan(nextTotalDistance)) { if (trackStatistics.totalDistance().greaterThan(nextTotalDistance)) {
updateNextTaskDistance(); updateNextTaskDistance();
announce = true; announce = true;
} }
if (!trackStatistics.getTotalTime().minus(nextTotalTime).isNegative()) { if (!trackStatistics.totalTime().minus(nextTotalTime).isNegative()) {
updateNextDuration(); updateNextDuration();
announce = true; announce = true;
} }
@@ -182,7 +182,7 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
nextTotalDistance = DISTANCE_OFF; nextTotalDistance = DISTANCE_OFF;
} else { } else {
Distance distance = trackStatistics.getTotalDistance(); Distance distance = trackStatistics.totalDistance();
int index = (int) (distance.dividedBy(distanceFrequency)); int index = (int) (distance.dividedBy(distanceFrequency));
nextTotalDistance = distanceFrequency.multipliedBy(index + 1); nextTotalDistance = distanceFrequency.multipliedBy(index + 1);
@@ -195,10 +195,9 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
nextTotalTime = TOTALTIME_OFF; nextTotalTime = TOTALTIME_OFF;
} else { } else {
Duration totalTime = trackStatistics.getTotalTime(); Duration intervalMod = Duration.ofMillis(trackStatistics.totalTime().toMillis() % totalTimeFrequency.toMillis());
Duration intervalMod = Duration.ofMillis(trackStatistics.getTotalTime().toMillis() % totalTimeFrequency.toMillis());
nextTotalTime = totalTime.plus(totalTimeFrequency.minus(intervalMod)); nextTotalTime = trackStatistics.totalTime().plus(totalTimeFrequency.minus(intervalMod));
} }
} }
@@ -37,7 +37,7 @@ import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.ui.intervals.IntervalStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatistics;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
@@ -52,7 +52,7 @@ class VoiceAnnouncementUtils {
} }
static Spannable createStatistics(Context context, Track track, SensorDataSet sensorDataSet, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) { static Spannable createStatistics(Context context, Track track, SensorDataSet sensorDataSet, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) {
SegmentStatisticUpdater trackStatistics = track.getTrackStatistics(); Statistics trackStatistics = track.getStatistics();
SpannableStringBuilder builder = new SpannableStringBuilder(); SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -60,7 +60,7 @@ class VoiceAnnouncementUtils {
appendTime(builder, track.getStopTime()); appendTime(builder, track.getStopTime());
} }
Distance totalDistance = trackStatistics.getTotalDistance(); Distance totalDistance = trackStatistics.totalDistance();
Speed averageMovingSpeed = trackStatistics.getAverageMovingSpeed(); Speed averageMovingSpeed = trackStatistics.getAverageMovingSpeed();
Speed currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed() : null; Speed currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed() : null;
@@ -112,7 +112,7 @@ class VoiceAnnouncementUtils {
boolean hasTravelledDistance = !totalDistance.isZero(); boolean hasTravelledDistance = !totalDistance.isZero();
// Announce time // Announce time
Duration movingTime = trackStatistics.getMovingTime(); Duration movingTime = trackStatistics.movingTime();
if (shouldVoiceAnnounceMovingTime() && hasTravelledDistance && !movingTime.isZero()) { if (shouldVoiceAnnounceMovingTime() && hasTravelledDistance && !movingTime.isZero()) {
appendDuration(context, builder, movingTime); appendDuration(context, builder, movingTime);
builder.append("."); builder.append(".");
@@ -31,7 +31,7 @@ import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.SpeedFormatter;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SegmentStatisticUpdater; import de.dennisguse.opentracks.stats.Statistics;
import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.StringUtils;
/** /**
@@ -65,7 +65,7 @@ public class TrackShareSummaryGenerator {
writeString(track.getName(), builder, R.string.generic_name_line); writeString(track.getName(), builder, R.string.generic_name_line);
writeString(track.getActivityTypeLocalized(), builder, R.string.description_activity_type); writeString(track.getActivityTypeLocalized(), builder, R.string.description_activity_type);
writeString(track.getDescription(), builder, R.string.generic_description_line); writeString(track.getDescription(), builder, R.string.generic_description_line);
builder.append(generateTrackStatisticsDescription(track.getTrackStatistics())); builder.append(generateTrackStatisticsDescription(track.getStatistics()));
return builder.toString(); return builder.toString();
} }
@@ -78,17 +78,17 @@ public class TrackShareSummaryGenerator {
builder.append(TrackShareSummaryGenerator.TEXT_LINE_BREAK); builder.append(TrackShareSummaryGenerator.TEXT_LINE_BREAK);
} }
private String generateTrackStatisticsDescription(SegmentStatisticUpdater stats) { private String generateTrackStatisticsDescription(Statistics stats) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
// Total distance // Total distance
writeDistance(stats.getTotalDistance(), builder, R.string.description_total_distance); writeDistance(stats.totalDistance(), builder, R.string.description_total_distance);
// Total time // Total time
writeTime(stats.getTotalTime(), builder, R.string.description_total_time); writeTime(stats.totalTime(), builder, R.string.description_total_time);
// Moving time // Moving time
writeTime(stats.getMovingTime(), builder, R.string.description_moving_time); writeTime(stats.movingTime(), builder, R.string.description_moving_time);
// Average speed // Average speed
writeSpeed(stats.getAverageSpeed(), builder, R.string.description_average_speed); writeSpeed(stats.getAverageSpeed(), builder, R.string.description_average_speed);
@@ -97,7 +97,7 @@ public class TrackShareSummaryGenerator {
writeSpeed(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_speed); writeSpeed(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_speed);
// Max speed // Max speed
writeSpeed(stats.getMaxSpeed(), builder, R.string.description_max_speed); writeSpeed(stats.maxSpeed(), builder, R.string.description_max_speed);
// Average pace // Average pace
writePace(stats.getAverageSpeed(), builder, R.string.description_average_pace_in_minute); writePace(stats.getAverageSpeed(), builder, R.string.description_average_pace_in_minute);
@@ -106,26 +106,22 @@ public class TrackShareSummaryGenerator {
writePace(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_pace_in_minute); writePace(stats.getAverageMovingSpeed(), builder, R.string.description_average_moving_pace_in_minute);
// Fastest pace // Fastest pace
writePace(stats.getMaxSpeed(), builder, R.string.description_fastest_pace_in_minute); writePace(stats.maxSpeed(), builder, R.string.description_fastest_pace_in_minute);
// Min and Max altitude // Min and Max altitude
if (stats.hasAltitudeExtremities()) { if (stats.altitudeMax_m() != null & stats.altitudeMin_m() != null) {
writeAltitude(stats.getMaxAltitude(), builder, R.string.description_max_altitude); writeAltitude(stats.altitudeMax_m(), builder, R.string.description_max_altitude);
writeAltitude(stats.getMinAltitude(), builder, R.string.description_min_altitude); writeAltitude(stats.altitudeMin_m(), builder, R.string.description_min_altitude);
} }
// Altitude gain // Altitude gain & loss
if (stats.hasTotalAltitudeGain()) { if (stats.altitudeGainLoss() != null) {
writeAltitude(stats.getTotalAltitudeGain(), builder, R.string.description_altitude_gain); writeAltitude(stats.altitudeGainLoss().gain_m(), builder, R.string.description_altitude_gain);
} writeAltitude(stats.altitudeGainLoss().loss_m(), builder, R.string.description_altitude_loss);
// Altitude loss
if (stats.hasTotalAltitudeLoss()) {
writeAltitude(stats.getTotalAltitudeLoss(), builder, R.string.description_altitude_loss);
} }
// Recorded time // Recorded time
builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTimeWithOffset(OffsetDateTime.ofInstant(stats.getStartTime(), ZoneId.systemDefault())))); builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTimeWithOffset(OffsetDateTime.ofInstant(stats.startTime(), ZoneId.systemDefault()))));
builder.append(TEXT_LINE_BREAK); builder.append(TEXT_LINE_BREAK);
return builder.toString(); return builder.toString();
@@ -89,6 +89,7 @@ public class SegmentStatisticUpdater {
isIdle = other.isIdle; isIdle = other.isIdle;
} }
@Deprecated //TODO Remove
@VisibleForTesting @VisibleForTesting
public SegmentStatisticUpdater(String startTime, String stopTime, double totalDistance_m, int totalTime_s, int movingTime_s, float maxSpeed_mps, Float totalAltitudeGain_m, Float totalAltitudeLoss_m) { public SegmentStatisticUpdater(String startTime, String stopTime, double totalDistance_m, int totalTime_s, int movingTime_s, float maxSpeed_mps, Float totalAltitudeGain_m, Float totalAltitudeLoss_m) {
this.startTime = Instant.parse(startTime); this.startTime = Instant.parse(startTime);
@@ -286,10 +287,6 @@ public class SegmentStatisticUpdater {
movingTime = movingTime.plus(time); movingTime = movingTime.plus(time);
} }
public Duration getStoppedTime() {
return totalTime.minus(movingTime);
}
public boolean isIdle() { public boolean isIdle() {
return isIdle; return isIdle;
} }
@@ -423,6 +420,7 @@ public class SegmentStatisticUpdater {
totalAltitudeLoss_m += loss_m; totalAltitudeLoss_m += loss_m;
} }
@Deprecated //TODO Remove as it should (a) not be necessary and (b) toString is not complete?
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@@ -37,7 +37,32 @@ public record Statistics(
Power avgPower Power avgPower
) { ) {
public Duration getStoppedTime() {
return totalTime.minus(movingTime);
}
public Speed getAverageSpeed() {
if (totalTime.isZero()) {
return Speed.of(0);
}
return Speed.of(totalDistance, totalTime);
}
public Speed getAverageMovingSpeed() { public Speed getAverageMovingSpeed() {
return Speed.of(totalDistance, movingTime); return Speed.of(totalDistance, movingTime);
} }
@Deprecated
//TODO null should be return (need adjusting ContentPtoviderUtils.createContentValues()
public double getMinAltitude() {
if (altitudeMin_m == null) return 0;
return altitudeMin_m;
}
@Deprecated
//TODO null should be return (need adjusting ContentPtoviderUtils.createContentValues()
public double getMaxAltitude() {
if (altitudeMax_m == null) return 0;
return altitudeMax_m;
}
} }
@@ -72,6 +72,7 @@ public class TrackStatisticsUpdater {
resetAverageHeartRate(); resetAverageHeartRate();
} }
//TODO Return Statistic?
public SegmentStatisticUpdater getTrackStatistics() { public SegmentStatisticUpdater getTrackStatistics() {
// Take a snapshot - we don't want anyone messing with our trackStatistics // Take a snapshot - we don't want anyone messing with our trackStatistics
SegmentStatisticUpdater stats = new SegmentStatisticUpdater(segmentStatisticUpdater); SegmentStatisticUpdater stats = new SegmentStatisticUpdater(segmentStatisticUpdater);
@@ -34,7 +34,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
public void onChanged(UnitSystem unitSystem, RecordingData data) { public void onChanged(UnitSystem unitSystem, RecordingData data) {
Pair<String, String> valueAndUnit = DistanceFormatter.Builder() Pair<String, String> valueAndUnit = DistanceFormatter.Builder()
.setUnit(unitSystem) .setUnit(unitSystem)
.build(getContext()).getDistanceParts(data.getStatisticsTrack().getTotalDistance()); .build(getContext()).getDistanceParts(data.getStatisticsTrack().totalDistance());
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);
@@ -46,7 +46,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
@Override @Override
public void onChanged(UnitSystem unitSystem, RecordingData data) { public void onChanged(UnitSystem unitSystem, RecordingData data) {
Pair<String, String> valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(data.getStatisticsTrack().getTotalTime()), null); Pair<String, String> valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(data.getStatisticsTrack().totalTime()), null);
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);
@@ -58,7 +58,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
@Override @Override
public void onChanged(UnitSystem unitSystem, RecordingData data) { public void onChanged(UnitSystem unitSystem, RecordingData data) {
String value = StringUtils.formatElapsedTime(data.getStatisticsTrack().getMovingTime()); String value = StringUtils.formatElapsedTime(data.getStatisticsTrack().movingTime());
getBinding().statsValue.setText(value); getBinding().statsValue.setText(value);
getBinding().statsDescriptionMain.setText(getContext().getString(R.string.stats_moving_time)); getBinding().statsDescriptionMain.setText(getContext().getString(R.string.stats_moving_time));
@@ -157,7 +157,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
.setReportSpeedOrPace(true) .setReportSpeedOrPace(true)
.build(getContext()); .build(getContext());
Pair<String, String> valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsTrack().getMaxSpeed()); Pair<String, String> valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsTrack().maxSpeed());
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);
@@ -236,7 +236,7 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
.setReportSpeedOrPace(false) .setReportSpeedOrPace(false)
.build(getContext()); .build(getContext());
Pair<String, String> valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsTrack().getMaxSpeed()); Pair<String, String> valueAndUnit = speedFormatterSpeed.getSpeedParts(data.getStatisticsTrack().maxSpeed());
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);
@@ -264,8 +264,9 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
@Override @Override
public void onChanged(UnitSystem unitSystem, RecordingData data) { public void onChanged(UnitSystem unitSystem, RecordingData data) {
Float gain = data.getStatisticsTrack().altitudeGainLoss() != null ? data.getStatisticsTrack().altitudeGainLoss().gain_m() : null;
Pair<String, String> valueAndUnit = StringUtils.getAltitudeParts(getContext(), data.getStatisticsTrack().getTotalAltitudeGain(), unitSystem); Pair<String, String> valueAndUnit = StringUtils.getAltitudeParts(getContext(), gain, unitSystem);
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);
@@ -277,8 +278,9 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
@Override @Override
public void onChanged(UnitSystem unitSystem, RecordingData data) { public void onChanged(UnitSystem unitSystem, RecordingData data) {
Float loss = data.getStatisticsTrack().altitudeGainLoss() != null ? data.getStatisticsTrack().altitudeGainLoss().loss_m() : null;
Pair<String, String> valueAndUnit = StringUtils.getAltitudeParts(getContext(), data.getStatisticsTrack().getTotalAltitudeLoss(), unitSystem); Pair<String, String> valueAndUnit = StringUtils.getAltitudeParts(getContext(), loss, unitSystem);
getBinding().statsValue.setText(valueAndUnit.first); getBinding().statsValue.setText(valueAndUnit.first);
getBinding().statsUnit.setText(valueAndUnit.second); getBinding().statsUnit.setText(valueAndUnit.second);