From e990b413cd7a216554d246663cff439cb6b91ca9 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sat, 9 Jan 2021 13:27:14 +0100 Subject: [PATCH] Replace `long time_ms` with Instant and Duration, respectively. Fixes #561. --- .../content/DescriptionGeneratorTest.java | 21 +++-- .../opentracks/content/data/TestDataUtil.java | 11 ++- .../CustomContentProviderUtilsTest.java | 14 +-- .../fragments/ChartFragmentTest.java | 19 ++-- .../opentracks/fragments/TrackStubUtils.java | 2 +- .../io/file/importer/ExportImportTest.java | 6 +- .../AdaptiveLocationListenerPolicyTest.java | 16 ++-- .../TrackRecordingServiceTestLooper.java | 5 +- .../opentracks/stats/TrackStatisticsTest.java | 33 ++++--- .../stats/TrackStatisticsUpdaterTest.java | 38 ++++++++ .../util/AnnouncementUtilsTest.java | 9 +- .../opentracks/util/StringUtilsTest.java | 80 ++++------------ .../opentracks/util/TrackNameUtilsTest.java | 6 +- .../viewmodels/AggregatedStatisticsTest.java | 30 +++--- .../viewmodels/IntervalStatisticsTest.java | 6 +- .../opentracks/TrackController.java | 16 ++-- .../opentracks/TrackListActivity.java | 4 +- .../opentracks/chart/ChartPoint.java | 2 +- .../opentracks/chart/ChartView.java | 3 +- .../content/DescriptionGenerator.java | 6 +- .../opentracks/content/data/Marker.java | 7 +- .../opentracks/content/data/TrackPoint.java | 35 +++---- .../provider/ContentProviderUtils.java | 22 +++-- .../opentracks/fragments/ChartFragment.java | 2 +- .../StatisticsRecordingFragment.java | 8 +- .../io/file/exporter/FileTrackExporter.java | 12 ++- .../io/file/exporter/GpxTrackWriter.java | 3 +- .../io/file/exporter/KmlTrackWriter.java | 5 +- .../importer/AbstractFileTrackImporter.java | 22 ++--- .../services/TrackRecordingService.java | 16 ++-- .../services/TrackRecordingServiceBinder.java | 4 +- .../TrackRecordingServiceInterface.java | 5 +- .../AbsoluteLocationListenerPolicy.java | 10 +- .../AdaptiveLocationListenerPolicy.java | 38 +++++--- .../services/handlers/GpsStatus.java | 27 +++--- .../services/handlers/LocationHandler.java | 23 ++--- .../handlers/LocationListenerPolicy.java | 6 +- .../services/tasks/PeriodicTaskExecutor.java | 4 +- .../services/tasks/TimerTaskExecutor.java | 17 ++-- .../opentracks/stats/TrackStatistics.java | 94 +++++++++---------- .../stats/TrackStatisticsUpdater.java | 23 +++-- .../opentracks/util/AnnouncementUtils.java | 43 +++++---- .../opentracks/util/LocationUtils.java | 10 +- .../opentracks/util/StringUtils.java | 63 ++++--------- .../opentracks/util/TrackNameUtils.java | 12 +-- .../opentracks/util/TrackPointUtils.java | 16 ---- .../viewmodels/IntervalStatistics.java | 22 ++--- 47 files changed, 442 insertions(+), 434 deletions(-) create mode 100644 src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/DescriptionGeneratorTest.java b/src/androidTest/java/de/dennisguse/opentracks/content/DescriptionGeneratorTest.java index 38011251c..c654f911b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/DescriptionGeneratorTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/DescriptionGeneratorTest.java @@ -25,6 +25,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Duration; +import java.time.Instant; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.stats.TrackStatistics; @@ -40,7 +43,7 @@ import static org.junit.Assert.assertEquals; @RunWith(AndroidJUnit4.class) public class DescriptionGeneratorTest { - private static final long START_TIME = 1288721514000L; + private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L); private DescriptionGenerator descriptionGenerator; private final Context context = ApplicationProvider.getApplicationContext(); @@ -58,14 +61,14 @@ public class DescriptionGeneratorTest { Track track = new Track(); TrackStatistics stats = new TrackStatistics(); stats.setTotalDistance(20000); - stats.setTotalTime(600000); - stats.setMovingTime(300000); + stats.setTotalTime(Duration.ofMillis(600000)); + stats.setMovingTime(Duration.ofMillis(300000)); stats.setMaxSpeed(100); stats.setMaxElevation(550); stats.setMinElevation(-500); stats.setTotalElevationGain(6000f); stats.setTotalElevationLoss(6000); - stats.setStartTime_ms(START_TIME); + stats.setStartTime(START_TIME); track.setTrackStatistics(stats); track.setCategory("hiking"); String expected = //"Created by" @@ -96,14 +99,14 @@ public class DescriptionGeneratorTest { Track track = new Track(); TrackStatistics stats = new TrackStatistics(); stats.setTotalDistance(20000); - stats.setTotalTime(600000); - stats.setMovingTime(300000); + stats.setTotalTime(Duration.ofMillis(600000)); + stats.setMovingTime(Duration.ofMillis(300000)); stats.setMaxSpeed(100); stats.setMaxElevation(Double.POSITIVE_INFINITY); stats.setMinElevation(Double.NEGATIVE_INFINITY); stats.setTotalElevationGain(6000f); stats.setTotalElevationLoss(6000); - stats.setStartTime_ms(START_TIME); + stats.setStartTime(START_TIME); track.setTrackStatistics(stats); track.setCategory("hiking"); String expected = //"Created by" @@ -139,12 +142,12 @@ public class DescriptionGeneratorTest { } /** - * Tests {@link DescriptionGenerator#writeTime(long, StringBuilder, int, String)}. + * Tests {@link DescriptionGenerator#writeTime(Duration, StringBuilder, int, String)}. */ @Test public void testWriteTime() { StringBuilder builder = new StringBuilder(); - descriptionGenerator.writeTime(1000, builder, R.string.description_total_time, "
"); + descriptionGenerator.writeTime(Duration.ofMillis(1000), builder, R.string.description_total_time, "
"); assertEquals("Total time: 00:01
", builder.toString()); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java index 4eb7abb14..7709c20db 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java @@ -7,6 +7,7 @@ import android.util.Pair; import java.io.File; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -56,7 +57,7 @@ public class TestDataUtil { int i = 0; List trackPoints = List.of( - TrackPoint.createSegmentStartManualWithTime(i++ + 1), + TrackPoint.createSegmentStartManualWithTime(Instant.ofEpochMilli(i++ + 1)), createTrackPoint(i++), createTrackPoint(i++), createTrackPoint(i++), @@ -64,13 +65,13 @@ public class TestDataUtil { createTrackPoint(i++), createTrackPoint(i++), createTrackPoint(i++), - TrackPoint.createSegmentEndWithTime(i++ + 1), + TrackPoint.createSegmentEndWithTime(Instant.ofEpochSecond(i++ + 1)), - TrackPoint.createSegmentStartManualWithTime(i++), + TrackPoint.createSegmentStartManualWithTime(Instant.ofEpochSecond(i++)), createTrackPoint(i++), createTrackPoint(i++), createTrackPoint(i++), - TrackPoint.createSegmentEndWithTime(i++ + 1) + TrackPoint.createSegmentEndWithTime(Instant.ofEpochSecond(i++ + 1)) ); List markers = List.of( @@ -114,7 +115,7 @@ public class TestDataUtil { trackPoint.setLongitude(INITIAL_LONGITUDE - (double) i / 10000.0); trackPoint.setAccuracy((float) i / 100.0f); trackPoint.setAltitude(i * ALTITUDE_INTERVAL); - trackPoint.setTime(i + 1); + trackPoint.setTime(Instant.ofEpochSecond(i + 1)); trackPoint.setSpeed(5f + (i / 10f)); trackPoint.setHeartRate_bpm(100f + i); diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java index 0f5990e4e..ea6085017 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java @@ -33,6 +33,8 @@ import org.mockito.junit.MockitoJUnitRunner; import java.io.File; import java.io.IOException; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -423,14 +425,12 @@ public class CustomContentProviderUtilsTest { Track.Id trackId = new Track.Id(System.currentTimeMillis()); Pair> track = TestDataUtil.createTrack(trackId, 10); - // Bottom - long startTime = 1000L; // AverageSpeed TrackStatistics statistics = new TrackStatistics(); - statistics.setStartTime_ms(startTime); - statistics.setStopTime_ms(2500L); - statistics.setTotalTime(1500L); - statistics.setMovingTime(700L); + statistics.setStartTime(Instant.ofEpochMilli(1000)); + statistics.setStopTime(Instant.ofEpochMilli(2500)); + statistics.setTotalTime(Duration.ofMillis(1500)); + statistics.setMovingTime(Duration.ofMillis(700)); statistics.setTotalDistance(750.0); statistics.setTotalElevationGain(50.0f); statistics.setMaxSpeed(60.0); @@ -809,7 +809,7 @@ public class CustomContentProviderUtilsTest { // then assertEquals(longitude, trackPoint.getLongitude(), 0.01); assertEquals(latitude, trackPoint.getLatitude(), 0.01); - assertEquals(time, trackPoint.getTime(), 0.01); + assertEquals(time, trackPoint.getTime().toEpochMilli()); assertEquals(speed, trackPoint.getSpeed(), 0.01); assertFalse(trackPoint.hasHeartRate()); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java b/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java index 0351c4da4..36a67f86a 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java @@ -28,6 +28,9 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Duration; +import java.time.Instant; + import de.dennisguse.opentracks.chart.ChartPoint; import de.dennisguse.opentracks.chart.ChartView; import de.dennisguse.opentracks.content.data.TrackPoint; @@ -61,7 +64,7 @@ public class ChartFragmentTest { @Before public void setUp() { boolean chartByDistance = false; - chartFragment = (ChartFragment) ChartFragment.newInstance(chartByDistance); + chartFragment = ChartFragment.newInstance(chartByDistance); chartFragment.setChartView(new ChartView(ApplicationProvider.getApplicationContext(), chartByDistance)); } @@ -193,18 +196,18 @@ public class ChartFragmentTest { // given chartFragment.setChartByDistance(false); TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint(); - trackPoint1.setTime(TrackStubUtils.INITIAL_TIME); //Keep old TrackPoint behavior of having time=0 for this test + trackPoint1.setTime(Instant.ofEpochMilli(TrackStubUtils.INITIAL_TIME)); //Keep old TrackPoint behavior of having time=0 for this test // when ChartPoint point = chartFragment.createPendingPoint(trackPoint1); // then assertEquals(0.0, point.getTimeOrDistance(), 0.01); - long timeSpan = 222; + Duration timeSpan = Duration.ofMillis(222); TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint(); - trackPoint2.setTime(trackPoint1.getTime() + timeSpan); + trackPoint2.setTime(Instant.ofEpochMilli(TrackStubUtils.INITIAL_TIME).plus(timeSpan)); point = chartFragment.createPendingPoint(trackPoint2); - assertEquals((double) timeSpan, point.getTimeOrDistance(), 0.01); + assertEquals(timeSpan, Duration.ofMillis((long) point.getTimeOrDistance())); } /** @@ -255,7 +258,7 @@ public class ChartFragmentTest { /* * Add a time span here to make sure the second point is valid, the value 222 here is doesn't matter. */ - trackPoint2.setTime(trackPoint1.getTime() + 222); + trackPoint2.setTime(trackPoint1.getTime().plusMillis(222)); trackPoint2.setSpeed(130f); point = chartFragment.createPendingPoint(trackPoint2); assertEquals(130.0 * UnitConversions.MPS_TO_KMH, point.getSpeed(), 0.01); @@ -280,7 +283,7 @@ public class ChartFragmentTest { * Add a time span here to make sure the second point and the speed is valid. * Speed is valid if: speedDifference > Constants.MAX_ACCELERATION * timeDifference speedDifference = 102 -100 timeDifference = 222 */ - trackPoint2.setTime(trackPoint2.getTime() + 222); + trackPoint2.setTime(trackPoint2.getTime().plusMillis(222)); trackPoint2.setSpeed(102f); point = chartFragment.createPendingPoint(trackPoint2); assertEquals(102.0 * UnitConversions.MPS_TO_KMH * UnitConversions.KM_TO_MI, point.getSpeed(), 0.01); @@ -305,7 +308,7 @@ public class ChartFragmentTest { * Add a time span here to make sure the second point and the speed is valid. * Speed is valid if: speedDifference > Constants.MAX_ACCELERATION * timeDifference speedDifference = 102 -100 timeDifference = 222 */ - trackPoint2.setTime(trackPoint2.getTime() + 222); + trackPoint2.setTime(trackPoint2.getTime().plusMillis(222)); trackPoint2.setSpeed(102f); point = chartFragment.createPendingPoint(trackPoint2); assertEquals(HOURS_PER_UNIT / (102.0 * UnitConversions.MPS_TO_KMH), point.getPace(), 0.01); diff --git a/src/androidTest/java/de/dennisguse/opentracks/fragments/TrackStubUtils.java b/src/androidTest/java/de/dennisguse/opentracks/fragments/TrackStubUtils.java index 41a5f5667..c2bc4c89a 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/fragments/TrackStubUtils.java +++ b/src/androidTest/java/de/dennisguse/opentracks/fragments/TrackStubUtils.java @@ -57,7 +57,7 @@ public class TrackStubUtils { location.setAltitude(altitude); location.setAccuracy(INITIAL_ACCURACY); location.setSpeed(INITIAL_SPEED); - location.setTime(INITIAL_TIME); + location.setTime(INITIAL_TIME); //TODO This is nowadays ignored as the constructor will replace the time. location.setBearing(INITIAL_BEARING); return new TrackPoint(location); 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 4d9aa756f..7399b696b 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 @@ -357,7 +357,7 @@ public class ExportImportTest { TrackPoint trackPoint = trackPoints.get(i); TrackPoint importedTrackPoint = importedTrackPoints.get(i); - assertEquals(trackPoint.getTime(), importedTrackPoint.getTime(), 0.01); + assertEquals(trackPoint.getTime(), importedTrackPoint.getTime()); TrackPoint.Type type = trackPoint.getType(); assertEquals("" + i, trackPoint.getType(), importedTrackPoint.getType()); @@ -410,8 +410,8 @@ public class ExportImportTest { TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics(); // Time - assertEquals(trackStatistics.getStartTime_ms(), trackStatistics.getStartTime_ms(), 0.01); - assertEquals(trackStatistics.getStopTime_ms(), trackStatistics.getStopTime_ms()); + assertEquals(trackStatistics.getStartTime(), trackStatistics.getStartTime()); + assertEquals(trackStatistics.getStopTime(), trackStatistics.getStopTime()); assertEquals(trackStatistics.getTotalTime(), trackStatistics.getTotalTime()); assertEquals(trackStatistics.getMovingTime(), trackStatistics.getMovingTime()); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/AdaptiveLocationListenerPolicyTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/AdaptiveLocationListenerPolicyTest.java index e06058212..648c5beef 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/AdaptiveLocationListenerPolicyTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/AdaptiveLocationListenerPolicyTest.java @@ -20,6 +20,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.time.Duration; + import de.dennisguse.opentracks.services.handlers.AdaptiveLocationListenerPolicy; import static org.junit.Assert.assertEquals; @@ -32,13 +34,13 @@ import static org.junit.Assert.assertEquals; @RunWith(JUnit4.class) public class AdaptiveLocationListenerPolicyTest { - private static final long MIN = 1000; - private static final long MAX = 3000; + private static final Duration MIN = Duration.ofMillis(1000); + private static final Duration MAX = Duration.ofMillis(3000); private static final int MIN_DISTANCE = 10; - private static final long NEW_IDLE_TIME_BIG = 10000; - private static final long NEW_IDLE_TIME_NORMAL = 5000; - private static final long NEW_IDLE_TIME_SMALL = 2000; - private static final long NEW_IDLE_TIME_LESS_THAN_MIN = 500; + private static final Duration NEW_IDLE_TIME_BIG = Duration.ofMillis(10000); + private static final Duration NEW_IDLE_TIME_NORMAL = Duration.ofMillis(5000); + private static final Duration NEW_IDLE_TIME_SMALL = Duration.ofMillis(2000); + private static final Duration NEW_IDLE_TIME_LESS_THAN_MIN = Duration.ofMillis(500); private AdaptiveLocationListenerPolicy adaptiveLocationListenerPolicy; @Before @@ -62,7 +64,7 @@ public class AdaptiveLocationListenerPolicyTest { adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_NORMAL); // First get the half of NEW_IDLE_TIME_NORMAL, and then round it to the nearest second. - assertEquals((NEW_IDLE_TIME_NORMAL / 2 / 1000) * 1000, adaptiveLocationListenerPolicy.getDesiredPollingInterval()); + assertEquals(NEW_IDLE_TIME_NORMAL.dividedBy(2).getSeconds(), adaptiveLocationListenerPolicy.getDesiredPollingInterval().getSeconds()); adaptiveLocationListenerPolicy.updateIdleTime(NEW_IDLE_TIME_SMALL); assertEquals(MIN, adaptiveLocationListenerPolicy.getDesiredPollingInterval()); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java index 515765dbc..55a81e8c8 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java @@ -19,6 +19,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Instant; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -239,7 +240,7 @@ public class TrackRecordingServiceTestLooper { assertEquals(trackId, track.getId()); TrackStatistics trackStatistics = track.getTrackStatistics(); assertNotNull(trackStatistics); - assertTrue(trackStatistics.getStartTime_ms() > 0); - assertTrue(trackStatistics.getStopTime_ms() >= trackStatistics.getStartTime_ms()); + assertTrue(trackStatistics.getStartTime().isAfter(Instant.ofEpochMilli(0))); + assertTrue(trackStatistics.getStopTime().isAfter(trackStatistics.getStartTime())); } } diff --git a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsTest.java b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsTest.java index a7fb3727a..4024e8e66 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsTest.java @@ -20,6 +20,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.time.Duration; +import java.time.Instant; + import static org.junit.Assert.assertEquals; /** @@ -41,14 +44,14 @@ public class TrackStatisticsTest { @Test public void testMerge() { TrackStatistics statistics2 = new TrackStatistics(); - statistics.setStartTime_ms(1000L); // Resulting start time - statistics.setStopTime_ms(2500L); - statistics2.setStartTime_ms(3000L); - statistics2.setStopTime_ms(4000L); // Resulting stop time - statistics.setTotalTime(1500L); - statistics2.setTotalTime(1000L); // Result: 1500+1000 - statistics.setMovingTime(700L); - statistics2.setMovingTime(600L); // Result: 700+600 + statistics.setStartTime(Instant.ofEpochMilli(1000)); // Resulting start time + statistics.setStopTime(Instant.ofEpochMilli(2500)); + statistics2.setStartTime(Instant.ofEpochMilli(3000)); + statistics2.setStopTime(Instant.ofEpochMilli(4000)); // Resulting stop time + statistics.setTotalTime(Duration.ofMillis(1500)); + statistics2.setTotalTime(Duration.ofMillis(1000)); // Result: 1500+1000 + statistics.setMovingTime(Duration.ofMillis(700)); + statistics2.setMovingTime(Duration.ofMillis(600)); // Result: 700+600 statistics.setTotalDistance(750.0); statistics2.setTotalDistance(350.0); // Result: 750+350 statistics.setTotalElevationGain(50.0f); @@ -62,13 +65,13 @@ public class TrackStatisticsTest { statistics.merge(statistics2); - assertEquals(1000L, statistics.getStartTime_ms()); - assertEquals(4000L, statistics.getStopTime_ms()); - assertEquals(2500L, statistics.getTotalTime()); - assertEquals(1300L, statistics.getMovingTime()); + assertEquals(Instant.ofEpochMilli(1000), statistics.getStartTime()); + assertEquals(Instant.ofEpochMilli(4000), statistics.getStopTime()); + assertEquals(Duration.ofMillis(2500), statistics.getTotalTime()); + assertEquals(Duration.ofMillis(1300), statistics.getMovingTime()); assertEquals(1100.0, statistics.getTotalDistance(), 0.001); assertEquals(900.0, statistics.getTotalElevationGain(), 0.001); - assertEquals(statistics.getTotalDistance() / (statistics.getMovingTime() / 1000.0), statistics.getMaxSpeed(), 0.001); + assertEquals(statistics.getTotalDistance() / statistics.getMovingTime().getSeconds(), statistics.getMaxSpeed(), 0.001); assertEquals(1200.0, statistics.getMinElevation(), 0.001); assertEquals(3575.0, statistics.getMaxElevation(), 0.001); } @@ -76,14 +79,14 @@ public class TrackStatisticsTest { @Test public void testGetAverageSpeed() { statistics.setTotalDistance(1000.0); - statistics.setTotalTime(50000); // in milliseconds + statistics.setTotalTime(Duration.ofMillis(50000)); assertEquals(20.0, statistics.getAverageSpeed(), 0.001); } @Test public void testGetAverageMovingSpeed() { statistics.setTotalDistance(1000.0); - statistics.setMovingTime(20000); // in milliseconds + statistics.setMovingTime(Duration.ofMillis(20000)); assertEquals(50.0, statistics.getAverageMovingSpeed(), 0.001); } } diff --git a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java new file mode 100644 index 000000000..3c721f46d --- /dev/null +++ b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java @@ -0,0 +1,38 @@ +package de.dennisguse.opentracks.stats; + +import org.junit.Test; + +import java.time.Duration; + +import de.dennisguse.opentracks.content.data.TestDataUtil; +import de.dennisguse.opentracks.content.data.Track; + +import static org.junit.Assert.assertEquals; + +public class TrackStatisticsUpdaterTest { + + @Test + public void addTrackPoint() { + // given + TestDataUtil.TrackData data = TestDataUtil.createTestingTrack(new Track.Id(1)); + + // when + TrackStatisticsUpdater updater = new TrackStatisticsUpdater(); + data.trackPoints.forEach(it -> updater.addTrackPoint(it, 50)); + + // then + TrackStatistics statistics = updater.getTrackStatistics(); + assertEquals(56.90, statistics.getTotalDistance(), 0.01); + assertEquals(Duration.ofSeconds(9), statistics.getTotalTime()); + assertEquals(Duration.ofSeconds(4), statistics.getMovingTime()); + + assertEquals(2.5, statistics.getMinElevation(), 0.01); + assertEquals(27.5, statistics.getMaxElevation(), 0.01); + assertEquals(18.0, statistics.getTotalElevationGain(), 0.01); + assertEquals(72.0, statistics.getTotalElevationLoss(), 0.01); + + assertEquals(14.226, statistics.getMaxSpeed(), 0.01); + assertEquals(14.226, statistics.getAverageMovingSpeed(), 0.01); + assertEquals(6.322, statistics.getAverageSpeed(), 0.01); + } +} \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java index b124100bc..f301775a9 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java @@ -8,6 +8,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Duration; import java.util.List; import de.dennisguse.opentracks.R; @@ -28,8 +29,8 @@ public class AnnouncementUtilsTest { public void getAnnouncement() { TrackStatistics stats = new TrackStatistics(); stats.setTotalDistance(20000); - stats.setTotalTime(600000); - stats.setMovingTime(300000); + stats.setTotalTime(Duration.ofMillis(600000)); + stats.setMovingTime(Duration.ofMillis(300000)); stats.setMaxSpeed(100); stats.setTotalElevationGain(6000f); @@ -44,8 +45,8 @@ public class AnnouncementUtilsTest { public void getAnnouncement_withInterval() { TrackStatistics stats = new TrackStatistics(); stats.setTotalDistance(20000); - stats.setTotalTime(600000); - stats.setMovingTime(300000); + stats.setTotalTime(Duration.ofMillis(600000)); + stats.setMovingTime(Duration.ofMillis(300000)); stats.setMaxSpeed(100); stats.setTotalElevationGain(6000f); diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java index 21a57ca6d..01e60cf76 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java @@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Duration; import java.util.GregorianCalendar; import java.util.TimeZone; @@ -40,55 +41,32 @@ public class StringUtilsTest { private final Context context = ApplicationProvider.getApplicationContext(); - /** - * Tests {@link StringUtils#formatDateTimeIso8601(long)}. - */ - @Test - public void testFormatDateTimeIso8601() { - assertEquals("1970-01-01T00:00:12.345Z", StringUtils.formatDateTimeIso8601(12345)); - } - - /** - * Tests {@link StringUtils#formatElapsedTime(long)}. + * Tests {@link StringUtils#formatElapsedTime(Duration)}. */ @Test public void testformatElapsedTime() { - // 1 second - assertEquals("00:01", StringUtils.formatElapsedTime(1000)); - // 10 seconds - assertEquals("00:10", StringUtils.formatElapsedTime(10000)); - // 1 minute - assertEquals("01:00", StringUtils.formatElapsedTime(60000)); - // 10 minutes - assertEquals("10:00", StringUtils.formatElapsedTime(600000)); - // 1 hour - assertEquals("1:00:00", StringUtils.formatElapsedTime(3600000)); - // 10 hours - assertEquals("10:00:00", StringUtils.formatElapsedTime(36000000)); - // 100 hours - assertEquals("100:00:00", StringUtils.formatElapsedTime(360000000)); + assertEquals("00:01", StringUtils.formatElapsedTime(Duration.ofMillis(1000))); + assertEquals("00:10", StringUtils.formatElapsedTime(Duration.ofMillis(10000))); + assertEquals("01:00", StringUtils.formatElapsedTime(Duration.ofMillis(60000))); + assertEquals("10:00", StringUtils.formatElapsedTime(Duration.ofMillis(600000))); + assertEquals("1:00:00", StringUtils.formatElapsedTime(Duration.ofMillis(3600000))); + assertEquals("10:00:00", StringUtils.formatElapsedTime(Duration.ofMillis(36000000))); + assertEquals("100:00:00", StringUtils.formatElapsedTime(Duration.ofMillis(360000000))); } /** - * Tests {@link StringUtils#formatElapsedTimeWithHour(long)}. + * Tests {@link StringUtils#formatElapsedTimeWithHour(Duration)}. */ @Test public void testformatElapsedTimeWithHour() { - // 1 second - assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(1000)); - // 10 seconds - assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(10000)); - // 1 minute - assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(60000)); - // 10 minutes - assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(600000)); - // 1 hour - assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(3600000)); - // 10 hours - assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(36000000)); - // 100 hours - assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(360000000)); + assertEquals("0:00:01", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(1000))); + assertEquals("0:00:10", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(10000))); + assertEquals("0:01:00", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(60000))); + assertEquals("0:10:00", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(600000))); + assertEquals("1:00:00", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(3600000))); + assertEquals("10:00:00", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(36000000))); + assertEquals("100:00:00", StringUtils.formatElapsedTimeWithHour(Duration.ofMillis(360000000))); } /** @@ -170,29 +148,7 @@ public class StringUtilsTest { // This comparision tends to be flaky (difference of 1ms) // Assert.assertEquals(calendar.getTimeInMillis(), StringUtils.parseTime(xmlDateTime)); - assertTrue(calendar.getTimeInMillis() + " vs. " + StringUtils.parseTime(xmlDateTime), Math.abs(calendar.getTimeInMillis() - StringUtils.parseTime(xmlDateTime)) <= 1); - } - - /** - * Tests {@link StringUtils#getTimeParts(long)} with a positive number. - */ - @Test - public void testGetTimeParts_positive() { - int[] parts = StringUtils.getTimeParts(61000); - assertEquals(1, parts[0]); - assertEquals(1, parts[1]); - assertEquals(0, parts[2]); - } - - /** - * Tests {@link StringUtils#getTimeParts(long)} with a negative number. - */ - @Test - public void testGetTimeParts_negative() { - int[] parts = StringUtils.getTimeParts(-61000); - assertEquals(-1, parts[0]); - assertEquals(-1, parts[1]); - assertEquals(0, parts[2]); + assertTrue(calendar.getTimeInMillis() + " vs. " + StringUtils.parseTime(xmlDateTime), Math.abs(calendar.getTimeInMillis() - StringUtils.parseTime(xmlDateTime).toEpochMilli()) <= 1); } @Test diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/TrackNameUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/TrackNameUtilsTest.java index d9ba10020..a51bc4c7b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/util/TrackNameUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/util/TrackNameUtilsTest.java @@ -25,7 +25,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; import java.util.Locale; import de.dennisguse.opentracks.R; @@ -42,7 +42,7 @@ import static org.junit.Assert.assertEquals; public class TrackNameUtilsTest { private static final Track.Id TRACK_ID = new Track.Id(1L); - private static final long START_TIME = 1288213406000L; + private static final Instant START_TIME = Instant.ofEpochMilli(1288213406000L); private static final Context CONTEXT = ApplicationProvider.getApplicationContext(); @@ -62,7 +62,7 @@ public class TrackNameUtilsTest { public void testTrackName_date_iso_8601() { PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value)); SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TrackNameUtils.ISO_8601_FORMAT, Locale.US); - assertEquals(simpleDateFormat.format(new Date(START_TIME)), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME)); + assertEquals(simpleDateFormat.format(START_TIME.toEpochMilli()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME)); } /** diff --git a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/AggregatedStatisticsTest.java b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/AggregatedStatisticsTest.java index c168f4cd3..e43596290 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/AggregatedStatisticsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/AggregatedStatisticsTest.java @@ -8,6 +8,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.time.Duration; +import java.time.Instant; import java.util.List; import de.dennisguse.opentracks.R; @@ -27,15 +29,15 @@ public class AggregatedStatisticsTest { * Create a TrackStatistics object. * * @param totalDistance distance in meters. - * @param totalTime total time in milliseconds. + * @param totalTime total time in milliseconds. //TODO Duration * @return TrackStatistics object. */ private static Track createTrack(Context context, long totalDistance, long totalTime, String category) { TrackStatistics statistics = new TrackStatistics(); - statistics.setStartTime_ms(1000L); // Resulting start time - statistics.setStopTime_ms(1000L + totalTime); - statistics.setTotalTime(totalTime); - statistics.setMovingTime(totalTime); + statistics.setStartTime(Instant.ofEpochMilli(1000L)); // Resulting start time + statistics.setStopTime(Instant.ofEpochMilli(1000L + totalTime)); + statistics.setTotalTime(Duration.ofMillis(totalTime)); + statistics.setMovingTime(Duration.ofMillis(totalTime)); statistics.setTotalDistance(totalDistance); statistics.setTotalElevationGain(50.0f); statistics.setMaxSpeed(50.0); // Resulting max speed @@ -68,7 +70,7 @@ public class AggregatedStatisticsTest { TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics(); assertEquals(totalDistance, statistics2.getTotalDistance(), 0); - assertEquals(totalTime, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime), statistics2.getMovingTime()); } @Test @@ -122,7 +124,7 @@ public class AggregatedStatisticsTest { TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics(); assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0); - assertEquals(totalTime * 2L, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime * 2), statistics2.getMovingTime()); } @Test @@ -156,19 +158,19 @@ public class AggregatedStatisticsTest { { TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics(); assertEquals(totalDistance, statistics2.getTotalDistance(), 0); - assertEquals(totalTime, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime), statistics2.getMovingTime()); } { TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics(); assertEquals(totalDistance, statistics2.getTotalDistance(), 0); - assertEquals(totalTime, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime), statistics2.getMovingTime()); } { TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics(); assertEquals(totalDistance, statistics2.getTotalDistance(), 0); - assertEquals(totalTime, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime), statistics2.getMovingTime()); } } @@ -219,28 +221,28 @@ public class AggregatedStatisticsTest { { TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics(); assertEquals(totalDistance * 5, statistics2.getTotalDistance(), 0); - assertEquals(totalTime * 5, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime * 5), statistics2.getMovingTime()); } // Running. { TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics(); assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0); - assertEquals(totalTime * 2, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime * 2), statistics2.getMovingTime()); } // Walking. { TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics(); assertEquals(totalDistance * 2, statistics2.getTotalDistance(), 0); - assertEquals(totalTime * 2, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime * 2), statistics2.getMovingTime()); } // Driving. { TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics(); assertEquals(totalDistance, statistics2.getTotalDistance(), 0); - assertEquals(totalTime, statistics2.getMovingTime()); + assertEquals(Duration.ofMillis(totalTime), statistics2.getMovingTime()); } // Check order diff --git a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java index 976aad1db..192cfec2d 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java @@ -116,17 +116,17 @@ public class IntervalStatisticsTest { IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, distanceInterval); List intervalList = intervalStatistics.getIntervalList(); double totalDistance = 0d; - long totalTime = 0L; + float totalTime = 0L; float totalGain = 0f; for (IntervalStatistics.Interval i : intervalList) { totalDistance += i.getDistance_m(); - totalTime += ((i.getDistance_m() / i.getSpeed_ms()) * UnitConversions.S_TO_MS); + totalTime += i.getDistance_m() / i.getSpeed_ms(); totalGain += i.getGain_m(); } // then assertEquals(trackStatistics.getTotalDistance(), totalDistance, 0.01); - assertEquals(trackStatistics.getTotalTime() * UnitConversions.MS_TO_S, totalTime * UnitConversions.MS_TO_S, 0.1); + assertEquals(trackStatistics.getTotalTime().toMillis(), totalTime * UnitConversions.S_TO_MS, 1); assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance() / distanceInterval)); assertEquals(totalGain, trackPoints.size() * TestDataUtil.ELEVATION_GAIN, 0.1); for (int i = 0; i < intervalList.size() - 1; i++) { diff --git a/src/main/java/de/dennisguse/opentracks/TrackController.java b/src/main/java/de/dennisguse/opentracks/TrackController.java index 4f584024c..9d8834224 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackController.java +++ b/src/main/java/de/dennisguse/opentracks/TrackController.java @@ -24,6 +24,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import java.time.Duration; + import de.dennisguse.opentracks.databinding.TrackControllerBinding; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.services.TrackRecordingServiceInterface; @@ -53,8 +55,7 @@ public class TrackController implements View.OnTouchListener { private boolean isRecording; private boolean isPaused; - private long totalTime = 0; - private long totalTimeTimestamp = 0; + private Duration totalTime; private boolean isResumed = false; private final Callback callback; @@ -63,7 +64,7 @@ public class TrackController implements View.OnTouchListener { private final Runnable updateTotalTimeRunnable = new Runnable() { public void run() { if (isResumed && isRecording && !isPaused) { - viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(System.currentTimeMillis() - totalTimeTimestamp + totalTime)); + viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); handlerUpdateTotalTime.postDelayed(this, UnitConversions.ONE_SECOND_MS); } } @@ -191,9 +192,10 @@ public class TrackController implements View.OnTouchListener { viewBinding.trackControllerTotalTime.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE); if (isRecording) { totalTime = getTotalTime(); - viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); + if (totalTime != null) { + viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); + } if (!isPaused) { - totalTimeTimestamp = System.currentTimeMillis(); handlerUpdateTotalTime.postDelayed(updateTotalTimeRunnable, UnitConversions.ONE_SECOND_MS); } } @@ -220,9 +222,9 @@ public class TrackController implements View.OnTouchListener { /** * Gets the total time for the current recording track. */ - private long getTotalTime() { + private Duration getTotalTime() { TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound(); - return trackRecordingService != null ? trackRecordingService.getTotalTime() : 0L; + return trackRecordingService != null ? trackRecordingService.getTotalTime() : null; } private void showStatusSetDefaultText() { diff --git a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java index 7573c220b..53ae3b4e1 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java @@ -44,6 +44,8 @@ import androidx.loader.app.LoaderManager; import androidx.loader.content.CursorLoader; import androidx.loader.content.Loader; +import java.time.Duration; + import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TracksColumns; import de.dennisguse.opentracks.databinding.TrackListBinding; @@ -224,7 +226,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe String icon = cursor.getString(iconIndex); int iconId = TrackIconUtils.getIconDrawable(icon); String name = cursor.getString(nameIndex); - String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex)); + String totalTime = StringUtils.formatElapsedTime(Duration.ofMillis(cursor.getLong(totalTimeIndex))); String totalDistance = StringUtils.formatDistance(TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits); int markerCount = cursor.getInt(markerCountIndex); long startTime = cursor.getLong(startTimeIndex); diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java index 5780cda27..4f0d872cf 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java @@ -35,7 +35,7 @@ public class ChartPoint { } timeOrDistance = distance; } else { - timeOrDistance = trackStatistics.getTotalTime(); + timeOrDistance = trackStatistics.getTotalTime().toMillis(); } elevation = trackStatisticsUpdater.getSmoothedElevation(); diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java index 1ae960a46..b2c255d67 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java @@ -38,6 +38,7 @@ import androidx.core.content.ContextCompat; import androidx.core.view.GestureDetectorCompat; import java.text.NumberFormat; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -740,7 +741,7 @@ public class ChartView extends View { * @param spacing the spacing between x axis and marker */ private void drawXAxisMarker(Canvas canvas, double value, NumberFormat numberFormat, int spacing) { - String marker = chartByDistance ? numberFormat.format(value) : StringUtils.formatElapsedTime((long) value); + String marker = chartByDistance ? numberFormat.format(value) : StringUtils.formatElapsedTime((Duration.ofMillis((long) value))); Rect rect = getRect(xAxisMarkerPaint, marker); canvas.drawText(marker, getX(value), topBorder + effectiveHeight + spacing + rect.height(), xAxisMarkerPaint); } diff --git a/src/main/java/de/dennisguse/opentracks/content/DescriptionGenerator.java b/src/main/java/de/dennisguse/opentracks/content/DescriptionGenerator.java index b6f38d6a2..66a1e04a5 100644 --- a/src/main/java/de/dennisguse/opentracks/content/DescriptionGenerator.java +++ b/src/main/java/de/dennisguse/opentracks/content/DescriptionGenerator.java @@ -21,6 +21,8 @@ import android.util.Pair; import androidx.annotation.VisibleForTesting; +import java.time.Duration; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.stats.TrackStatistics; @@ -146,7 +148,7 @@ public class DescriptionGenerator { } // Recorded time - builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTime(context, stats.getStartTime_ms()))); + builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTime(context, stats.getStartTime()))); builder.append(lineBreak); return builder.toString(); @@ -177,7 +179,7 @@ public class DescriptionGenerator { * @param lineBreak line break string */ @VisibleForTesting - void writeTime(long time, StringBuilder builder, int resId, String lineBreak) { + void writeTime(Duration time, StringBuilder builder, int resId, String lineBreak) { builder.append(context.getString(resId, StringUtils.formatElapsedTime(time))); builder.append(lineBreak); } diff --git a/src/main/java/de/dennisguse/opentracks/content/data/Marker.java b/src/main/java/de/dennisguse/opentracks/content/data/Marker.java index 6944763a3..de7f1f273 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/Marker.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/Marker.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import java.time.Instant; import java.util.Objects; /** @@ -43,7 +44,7 @@ public final class Marker { private final Track.Id trackId; //TODO It is the distance from the track starting point; rename to something more meaningful private double length = 0.0; - private long duration = 0; + private long duration = 0; //TODO Duration @Deprecated //TODO Replace by storing latitude/longitude directly. private final Location location; @@ -95,6 +96,10 @@ public final class Marker { this.id = id; } + public Instant getTime() { + return Instant.ofEpochMilli(location.getTime()); + } + public String getName() { return name; } diff --git a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java index 0c738f284..960593c18 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java @@ -21,6 +21,7 @@ import android.os.Parcel; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.time.Instant; import java.util.Objects; /** @@ -43,7 +44,7 @@ public class TrackPoint { private TrackPoint.Id id; - private long time_ms; + private Instant time; private Double latitude; private Double longitude; private Float accuracy; @@ -101,49 +102,49 @@ public class TrackPoint { this.speed_mps = location.getSpeed(); this.accuracy = location.getAccuracy(); - setTime(System.currentTimeMillis()); + setTime(Instant.now()); } - public TrackPoint(@NonNull Type type, long time_ms) { + public TrackPoint(@NonNull Type type, Instant time) { this(type); - this.time_ms = time_ms; + this.time = time; } - public TrackPoint(double latitude, double longitude, Double altitude, long time) { + public TrackPoint(double latitude, double longitude, Double altitude, Instant time) { this(Type.TRACKPOINT); this.latitude = latitude; this.longitude = longitude; this.altitude_m = altitude; - this.time_ms = time; + this.time = time; } @Deprecated //See #316 public static TrackPoint createSegmentStartManual() { - return createSegmentStartManualWithTime(System.currentTimeMillis()); + return createSegmentStartManualWithTime(Instant.now()); } - public static TrackPoint createSegmentStartManualWithTime(long time) { + public static TrackPoint createSegmentStartManualWithTime(Instant time) { return new TrackPoint(Type.SEGMENT_START_MANUAL, time); } @Deprecated //See #316 public static TrackPoint createSegmentStartAutomatic() { - return createSegmentStartAutomaticWithTime(System.currentTimeMillis()); + return createSegmentStartAutomaticWithTime(Instant.now()); } - public static TrackPoint createSegmentStartAutomaticWithTime(long time) { + public static TrackPoint createSegmentStartAutomaticWithTime(Instant time) { return new TrackPoint(Type.SEGMENT_START_AUTOMATIC, time); } public static TrackPoint createSegmentEnd() { - return createSegmentEndWithTime(System.currentTimeMillis()); + return createSegmentEndWithTime(Instant.now()); } public static TrackPoint createSegmentEndWithTime(@NonNull TrackPoint trackPoint) { return createSegmentEndWithTime(trackPoint.getTime()); } - public static TrackPoint createSegmentEndWithTime(long time) { + public static TrackPoint createSegmentEndWithTime(Instant time) { return new TrackPoint(Type.SEGMENT_END_MANUAL, time); } @@ -183,7 +184,7 @@ public class TrackPoint { @Nullable public Location getLocation() { Location location = new Location(""); - location.setTime(time_ms); + location.setTime(time.toEpochMilli()); if (hasLocation()) { location.setLatitude(latitude); location.setLongitude(longitude); @@ -241,12 +242,12 @@ public class TrackPoint { this.longitude = longitude; } - public long getTime() { - return time_ms; + public Instant getTime() { + return time; } - public void setTime(long time) { - this.time_ms = time; + public void setTime(Instant time) { + this.time = time; } public boolean hasAltitude() { diff --git a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java index f939259bc..65f50df96 100644 --- a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java +++ b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java @@ -29,6 +29,8 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import java.io.File; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -118,19 +120,19 @@ public class ContentProviderUtils { track.setCategory(cursor.getString(categoryIndex)); } if (!cursor.isNull(startTimeIndex)) { - trackStatistics.setStartTime_ms(cursor.getLong(startTimeIndex)); + trackStatistics.setStartTime(Instant.ofEpochMilli(cursor.getLong(startTimeIndex))); } if (!cursor.isNull(stopTimeIndex)) { - trackStatistics.setStopTime_ms(cursor.getLong(stopTimeIndex)); + trackStatistics.setStopTime(Instant.ofEpochMilli(cursor.getLong(stopTimeIndex))); } if (!cursor.isNull(totalDistanceIndex)) { trackStatistics.setTotalDistance(cursor.getFloat(totalDistanceIndex)); } if (!cursor.isNull(totalTimeIndex)) { - trackStatistics.setTotalTime(cursor.getLong(totalTimeIndex)); + trackStatistics.setTotalTime(Duration.ofMillis(cursor.getLong(totalTimeIndex))); } if (!cursor.isNull(movingTimeIndex)) { - trackStatistics.setMovingTime(cursor.getLong(movingTimeIndex)); + trackStatistics.setMovingTime(Duration.ofMillis(cursor.getLong(movingTimeIndex))); } if (!cursor.isNull(maxSpeedIndex)) { trackStatistics.setMaxSpeed(cursor.getFloat(maxSpeedIndex)); @@ -270,11 +272,11 @@ public class ContentProviderUtils { values.put(TracksColumns.NAME, track.getName()); values.put(TracksColumns.DESCRIPTION, track.getDescription()); values.put(TracksColumns.CATEGORY, track.getCategory()); - values.put(TracksColumns.STARTTIME, trackStatistics.getStartTime_ms()); - values.put(TracksColumns.STOPTIME, trackStatistics.getStopTime_ms()); + values.put(TracksColumns.STARTTIME, trackStatistics.getStartTime().toEpochMilli()); + values.put(TracksColumns.STOPTIME, trackStatistics.getStopTime().toEpochMilli()); values.put(TracksColumns.TOTALDISTANCE, trackStatistics.getTotalDistance()); - values.put(TracksColumns.TOTALTIME, trackStatistics.getTotalTime()); - values.put(TracksColumns.MOVINGTIME, trackStatistics.getMovingTime()); + values.put(TracksColumns.TOTALTIME, trackStatistics.getTotalTime().toMillis()); + values.put(TracksColumns.MOVINGTIME, trackStatistics.getMovingTime().toMillis()); values.put(TracksColumns.AVGSPEED, trackStatistics.getAverageSpeed()); values.put(TracksColumns.AVGMOVINGSPEED, trackStatistics.getAverageMovingSpeed()); values.put(TracksColumns.MAXSPEED, trackStatistics.getMaxSpeed()); @@ -533,7 +535,7 @@ public class ContentProviderUtils { trackPoint.setLatitude(((double) cursor.getInt(indexes.latitudeIndex)) / 1E6); } if (!cursor.isNull(indexes.timeIndex)) { - trackPoint.setTime(cursor.getLong(indexes.timeIndex)); + trackPoint.setTime(Instant.ofEpochMilli(cursor.getLong(indexes.timeIndex))); } if (!cursor.isNull(indexes.altitudeIndex)) { trackPoint.setAltitude(cursor.getFloat(indexes.altitudeIndex)); @@ -704,7 +706,7 @@ public class ContentProviderUtils { values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getLongitude() * 1E6)); values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getLatitude() * 1E6)); } - values.put(TrackPointsColumns.TIME, trackPoint.getTime()); + values.put(TrackPointsColumns.TIME, trackPoint.getTime().toEpochMilli()); if (trackPoint.hasAltitude()) { values.put(TrackPointsColumns.ALTITUDE, trackPoint.getAltitude()); } diff --git a/src/main/java/de/dennisguse/opentracks/fragments/ChartFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/ChartFragment.java index 455a68d25..ebc5434f4 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/ChartFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/ChartFragment.java @@ -56,7 +56,7 @@ public class ChartFragment extends Fragment implements TrackDataListener { private static final String KEY_CHART_VIEW_BY_DISTANCE_KEY = "chartViewByDistance"; - public static Fragment newInstance(boolean chartByDistance) { + public static ChartFragment newInstance(boolean chartByDistance) { Bundle bundle = new Bundle(); bundle.putBoolean(KEY_CHART_VIEW_BY_DISTANCE_KEY, chartByDistance); diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index 7e9d88c0e..b9e8720c3 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -14,6 +14,8 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -407,7 +409,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi } private void updateTotalTime() { - long totalTime; + Duration totalTime; if (isSelectedTrackRecording()) { totalTime = calculateTotalTime(); } else { @@ -420,12 +422,12 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi * Return time from service. * If service isn't bound then use lastTrackStatistics for calculate it. */ - private long calculateTotalTime() { + private Duration calculateTotalTime() { TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound(); if (trackRecordingService != null) { return trackRecordingService.getTotalTime(); } else { - return System.currentTimeMillis() - lastTrackStatistics.getStopTime_ms() + lastTrackStatistics.getTotalTime(); + return Duration.between(lastTrackStatistics.getStopTime().plus(lastTrackStatistics.getTotalTime()), Instant.now()); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/FileTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/FileTrackExporter.java index 1b57174bd..42581efa6 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/FileTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/FileTrackExporter.java @@ -22,6 +22,8 @@ import android.util.Log; import androidx.annotation.NonNull; import java.io.OutputStream; +import java.time.Duration; +import java.time.Instant; import de.dennisguse.opentracks.content.data.Marker; import de.dennisguse.opentracks.content.data.Track; @@ -71,9 +73,9 @@ public class FileTrackExporter implements TrackExporter { trackWriter.writeMultiTrackBegin(); } //TODO Why use startTime of first track for the others? - long startTime = tracks[0].getTrackStatistics().getStartTime_ms(); + Instant startTime = tracks[0].getTrackStatistics().getStartTime(); for (Track track : tracks) { - long offset = track.getTrackStatistics().getStartTime_ms() - startTime; + Duration offset = Duration.between(track.getTrackStatistics().getStartTime(), startTime); writeLocations(track, offset); } if (hasMultipleTracks) { @@ -120,7 +122,7 @@ public class FileTrackExporter implements TrackExporter { /** * Writes the locations. */ - private void writeLocations(Track track, long offset) throws InterruptedException { + private void writeLocations(Track track, Duration offset) throws InterruptedException { boolean wroteTrack = false; boolean wroteSegment = false; @@ -180,9 +182,9 @@ public class FileTrackExporter implements TrackExporter { * @param offset the time offset */ //TODO Why? - private void setLocationTime(TrackPoint trackPoint, long offset) { + private void setLocationTime(TrackPoint trackPoint, Duration offset) { if (trackPoint != null) { - trackPoint.setTime(trackPoint.getTime() - offset); + trackPoint.setTime(trackPoint.getTime().minus(offset)); } } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java index 74b0d6a26..c01c2ad02 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java @@ -21,6 +21,7 @@ import android.location.Location; import java.io.OutputStream; import java.io.PrintWriter; import java.text.NumberFormat; +import java.time.Instant; import java.util.Locale; import de.dennisguse.opentracks.content.data.Marker; @@ -137,7 +138,7 @@ public class GpxTrackWriter implements TrackWriter { if (location.hasAltitude()) { printWriter.println("" + ELEVATION_FORMAT.format(location.getAltitude()) + ""); } - printWriter.println(""); + printWriter.println(""); printWriter.println("" + StringUtils.formatCData(marker.getName()) + ""); printWriter.println("" + StringUtils.formatCData(marker.getDescription()) + ""); printWriter.println("" + StringUtils.formatCData(marker.getCategory()) + ""); diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackWriter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackWriter.java index 9db9f3765..d564bf8ac 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackWriter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackWriter.java @@ -20,6 +20,7 @@ import android.location.Location; import java.io.OutputStream; import java.io.PrintWriter; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -385,9 +386,9 @@ public class KmlTrackWriter implements TrackWriter { */ private String getTime(Location location) { if (exportTrackDetail) { - return StringUtils.formatDateTimeIso8601(location.getTime()); + return StringUtils.formatDateTimeIso8601(Instant.ofEpochMilli(location.getTime())); } else { - return StringUtils.formatDateTimeIso8601(location.getTime() - startTrackPoint.getTime()); + return StringUtils.formatDateTimeIso8601(Instant.ofEpochMilli(location.getTime() - startTrackPoint.getTime().toEpochMilli())); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java index c9bf1cc0b..f4bae0212 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java @@ -28,8 +28,9 @@ import org.xml.sax.helpers.DefaultHandler; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -50,7 +51,6 @@ import de.dennisguse.opentracks.util.LocationUtils; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.TrackIconUtils; -import de.dennisguse.opentracks.util.UnitConversions; /** * Abstract class for file track importers. @@ -185,9 +185,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval); } - if (marker.getLocation().getTime() > trackPoint.getTime()) { + if ((marker.getTime()).isAfter(trackPoint.getTime())) { trackPoint = null; - } else if (marker.getLocation().getTime() < trackPoint.getTime()) { + } else if (marker.getTime().isBefore(trackPoint.getTime())) { Log.w(TAG, "Ignoring marker: current trackPoint was after marker."); marker = null; } else { @@ -203,7 +203,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track String markerDescription = marker.getDescription(); String icon = context.getString(R.string.marker_icon_url); double length = trackStatisticsUpdater.getTrackStatistics().getTotalDistance(); - long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime(); + long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime().toMillis(); // Insert marker Marker newMarker = new Marker(marker.getName(), markerDescription, marker.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), marker.getPhotoUrl()); @@ -338,8 +338,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track TrackPoint trackPoint = createTrackPoint(); if (trackPoint.hasLocation()) { - long time = trackPoint.getTime(); - Date d = new Date(time); + Instant time = trackPoint.getTime(); if (trackPoint.getLatitude() == 100) { //TODO Remove by 31st December 2021. trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL); @@ -355,12 +354,12 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track } // Calculate derived attributes from the previous point - if (trackData.lastLocationInCurrentSegment != null && trackData.lastLocationInCurrentSegment.getTime() != 0) { + if (trackData.lastLocationInCurrentSegment != null && trackData.lastLocationInCurrentSegment.getTime() == null) { if (!trackPoint.hasSpeed()) { - long timeDifference = trackPoint.getTime() - trackData.lastLocationInCurrentSegment.getTime(); + Duration timeDifference = Duration.between(trackData.lastLocationInCurrentSegment.getTime(), trackPoint.getTime()); // Check for negative time change - if (timeDifference <= 0) { + if (timeDifference.isNegative()) { Log.w(TAG, "Time difference not positive."); } else { @@ -368,9 +367,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track * We don't have a speed and bearing in GPX, make something up from the last two points. * GPS points tend to have some inherent imprecision, speed and bearing will likely be off, so the statistics for things like max speed will also be off. */ - double duration = timeDifference * UnitConversions.MS_TO_S; if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) { - double speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / duration; + float speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / timeDifference.toMillis(); trackPoint.setSpeed((float) speed); } } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index 80c2fc1db..b459e8ff7 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -35,6 +35,8 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.core.app.TaskStackBuilder; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -228,12 +230,12 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand } //TODO Throw exception, when not recording. - public long getTotalTime() { + public Duration getTotalTime() { if (trackStatisticsUpdater == null) { - return 0; + return Duration.ofSeconds(0); } if (!isPaused()) { - trackStatisticsUpdater.updateTime(System.currentTimeMillis()); + trackStatisticsUpdater.updateTime(Instant.now()); } return trackStatisticsUpdater.getTrackStatistics().getTotalTime(); } @@ -264,7 +266,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand TrackStatistics stats = trackStatisticsUpdater.getTrackStatistics(); double length = stats.getTotalDistance(); - long duration = stats.getTotalTime(); + long duration = stats.getTotalTime().toMillis(); // Insert marker Marker marker = new Marker(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl); @@ -325,7 +327,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand } // Sync the real time setting the stop time with current time. - track.getTrackStatistics().setStopTime_ms(System.currentTimeMillis()); + track.getTrackStatistics().setStopTime(Instant.now()); trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics()); insertTrackPoint(track, TrackPoint.createSegmentStartManual()); @@ -637,7 +639,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand */ private void insertTrackPointIfNewer(@NonNull Track track, @NonNull TrackPoint trackPoint) { TrackPoint lastValidTrackPoint = getLastValidTrackPointInCurrentSegment(track.getId()); - if (TrackPointUtils.equalTime(trackPoint, lastValidTrackPoint)) { + if (lastValidTrackPoint != null && trackPoint.getTime().equals(lastValidTrackPoint.getTime())) { // Do not insert if inserted already Log.w(TAG, "Ignore insertTrackPoint. trackPoint time same as last valid track point time."); return; @@ -678,7 +680,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand * @param track the track */ private void updateTrackTotalTime(Track track) { - trackStatisticsUpdater.updateTime(System.currentTimeMillis()); + trackStatisticsUpdater.updateTime(Instant.now()); track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics()); contentProviderUtils.updateTrack(track); } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java index 9882b59e4..3cc7be682 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java @@ -2,6 +2,8 @@ package de.dennisguse.opentracks.services; import androidx.annotation.VisibleForTesting; +import java.time.Duration; + import de.dennisguse.opentracks.content.data.Marker; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; @@ -85,7 +87,7 @@ class TrackRecordingServiceBinder extends android.os.Binder implements TrackReco } @Override - public long getTotalTime() { + public Duration getTotalTime() { return trackRecordingService.getTotalTime(); } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java index d580c555b..99486c79c 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java @@ -17,6 +17,8 @@ package de.dennisguse.opentracks.services; import androidx.annotation.VisibleForTesting; +import java.time.Duration; + import de.dennisguse.opentracks.content.data.Marker; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; @@ -59,8 +61,7 @@ public interface TrackRecordingServiceInterface { /** * Gets the total time for the current recording track. Returns 0 if not recording. */ - //TODO milliseconds? - long getTotalTime(); + Duration getTotalTime(); Marker.Id insertMarker(String name, String category, String description, String photoUrl); diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/AbsoluteLocationListenerPolicy.java b/src/main/java/de/dennisguse/opentracks/services/handlers/AbsoluteLocationListenerPolicy.java index 17ba96b89..92d548f9a 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/AbsoluteLocationListenerPolicy.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/AbsoluteLocationListenerPolicy.java @@ -16,6 +16,8 @@ package de.dennisguse.opentracks.services.handlers; +import java.time.Duration; + /** * This is a simple location listener policy that will always dictate the same polling interval. * @@ -23,19 +25,19 @@ package de.dennisguse.opentracks.services.handlers; */ public class AbsoluteLocationListenerPolicy implements LocationListenerPolicy { - private final long interval; + private final Duration interval; /** * Constructor. * * @param interval the interval to request for gps signal */ - public AbsoluteLocationListenerPolicy(long interval) { + public AbsoluteLocationListenerPolicy(Duration interval) { this.interval = interval; } @Override - public long getDesiredPollingInterval() { + public Duration getDesiredPollingInterval() { return interval; } @@ -45,7 +47,7 @@ public class AbsoluteLocationListenerPolicy implements LocationListenerPolicy { } @Override - public void updateIdleTime(long idleTime) { + public void updateIdleTime(Duration idleTime) { // Ignore } } diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/AdaptiveLocationListenerPolicy.java b/src/main/java/de/dennisguse/opentracks/services/handlers/AdaptiveLocationListenerPolicy.java index 03a5c3261..66bf8b331 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/AdaptiveLocationListenerPolicy.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/AdaptiveLocationListenerPolicy.java @@ -16,6 +16,8 @@ package de.dennisguse.opentracks.services.handlers; +import java.time.Duration; + /** * A {@link LocationListenerPolicy} that will change based on how long the user has been stationary. * This policy will dictate a policy based on a min, max and idle time. @@ -25,35 +27,41 @@ package de.dennisguse.opentracks.services.handlers; */ public class AdaptiveLocationListenerPolicy implements LocationListenerPolicy { - private final long minInterval_ms; - private final long maxInterval_ms; + private final Duration minInterval; + private final Duration maxInterval; private final int minDistance_m; // The time the user has been idle at the current location, in milliseconds. - private long idleTime; + private Duration idleTime; /** * Creates a policy that will be bounded by the given minInterval_ms and maxInterval_ms. * - * @param minInterval_ms the smallest interval this policy will dictate - * @param maxInterval_ms the largest interval this policy will dictate + * @param minInterval the smallest interval this policy will dictate + * @param maxInterval the largest interval this policy will dictate * @param minDistance_m the minimum distance */ - public AdaptiveLocationListenerPolicy(long minInterval_ms, long maxInterval_ms, int minDistance_m) { - this.minInterval_ms = minInterval_ms; - this.maxInterval_ms = maxInterval_ms; + public AdaptiveLocationListenerPolicy(Duration minInterval, Duration maxInterval, int minDistance_m) { + this.minInterval = minInterval; + this.maxInterval = maxInterval; this.minDistance_m = minDistance_m; } /* - * Returns an interval half of the idle time, but bounded by minInterval_ms and maxInterval_ms. + * Returns an interval half of the idle time, but bounded by minInterval and maxInterval. */ - @Override - public long getDesiredPollingInterval() { - long desiredInterval_ms = idleTime / 2; + public Duration getDesiredPollingInterval() { + Duration desiredInterval = idleTime.dividedBy(2); + // Round to second to avoid setting the interval too often - desiredInterval_ms = (desiredInterval_ms / 1000) * 1000; - return Math.max(Math.min(maxInterval_ms, desiredInterval_ms), minInterval_ms); + desiredInterval = Duration.ofSeconds(desiredInterval.getSeconds()); + + if (minInterval.compareTo(desiredInterval) > 0) { + return minInterval; + } else if (maxInterval.compareTo(desiredInterval) < 0) { + return maxInterval; + } + return desiredInterval; } @Override @@ -62,7 +70,7 @@ public class AdaptiveLocationListenerPolicy implements LocationListenerPolicy { } @Override - public void updateIdleTime(long newIdleTime) { + public void updateIdleTime(Duration newIdleTime) { idleTime = newIdleTime; } } diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java b/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java index d56ee70ea..28b6cd7c9 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java @@ -6,9 +6,11 @@ import android.os.Handler; import androidx.annotation.Nullable; +import java.time.Duration; +import java.time.Instant; + import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.util.PreferencesUtils; -import de.dennisguse.opentracks.util.UnitConversions; /** * This class handle GPS status according to received locations and some thresholds. @@ -17,13 +19,13 @@ class GpsStatus { private static final String TAG = GpsStatus.class.getSimpleName(); - // The quantity of milliseconds that GpsStatus waits from minimal interval to consider GPS lost. - private static final int SIGNAL_LOST_THRESHOLD = (int) (10 * UnitConversions.S_TO_MS); + // The duration that GpsStatus waits from minimal interval to consider GPS lost. + private static final Duration SIGNAL_LOST_THRESHOLD = Duration.ofSeconds(10); // Threshold for accuracy. private double signalBadThreshold; // Threshold for time without points. - private int signalLostThreshold; + private Duration signalLostThreshold; private GpsStatusValue gpsStatus = GpsStatusValue.GPS_NONE; private GpsStatusListener client; @@ -46,7 +48,7 @@ class GpsStatus { public void run() { if (gpsStatus != null && !stopped) { onLocationChanged(null); - gpsStatusHandler.postDelayed(gpsStatusRunner, getIntervalThreshold()); + gpsStatusHandler.postDelayed(gpsStatusRunner, getIntervalThreshold().toMillis()); } } @@ -63,11 +65,11 @@ class GpsStatus { * @param client The client. * @param minRecordingInterval Value of min recording interval preference. */ - public GpsStatus(Context context, GpsStatusListener client, int minRecordingInterval) { + public GpsStatus(Context context, GpsStatusListener client, Duration minRecordingInterval) { this.client = client; this.context = context; signalBadThreshold = PreferencesUtils.getRecordingDistanceInterval(context); - signalLostThreshold = minRecordingInterval > 0 ? minRecordingInterval * (int) UnitConversions.ONE_SECOND_MS + SIGNAL_LOST_THRESHOLD : SIGNAL_LOST_THRESHOLD; + signalLostThreshold = !minRecordingInterval.isNegative() ? SIGNAL_LOST_THRESHOLD.plus(minRecordingInterval) : SIGNAL_LOST_THRESHOLD; gpsStatusHandler = new Handler(); } @@ -97,7 +99,7 @@ class GpsStatus { * @param value Minimal recording interval preference value in seconds or an special value: -1, -2, 0. */ public void onMinRecordingIntervalChanged(int value) { - signalLostThreshold = value > 0 ? value * (int) UnitConversions.ONE_SECOND_MS + SIGNAL_LOST_THRESHOLD : SIGNAL_LOST_THRESHOLD; + signalLostThreshold = value > 0 ? SIGNAL_LOST_THRESHOLD.plus(Duration.ofSeconds(value)) : SIGNAL_LOST_THRESHOLD; } /** @@ -119,7 +121,7 @@ class GpsStatus { if (trackPoint != null) { // Update trackPoint's time to the current time millis when trackPoint has been received. - trackPoint.setTime(System.currentTimeMillis()); + trackPoint.setTime(Instant.now()); lastValidTrackPoint = trackPoint; } lastTrackPoint = trackPoint; @@ -133,7 +135,7 @@ class GpsStatus { * Also, it'll run the runnable if signal is bad or stop it if the signal is lost. */ private void checkStatusFromLastLocation() { - if (System.currentTimeMillis() - lastTrackPoint.getTime() > signalLostThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) { + if (Duration.between(lastTrackPoint.getTime(), Instant.now()).compareTo(signalLostThreshold) > 0 && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) { // Too much time without receiving signal -> signal lost. GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST; @@ -160,7 +162,8 @@ class GpsStatus { * If there is any change then it does the change. */ private void checkStatusFromLastValidLocation() { - if (System.currentTimeMillis() - lastValidTrackPoint.getTime() > signalLostThreshold) { + Duration elapsed = Duration.between(lastValidTrackPoint.getTime(), Instant.now()); + if (signalLostThreshold.minus(elapsed).isNegative()) { // Too much time without locations -> lost signal? (wait signalLostThreshold from last valid location). GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST; @@ -222,7 +225,7 @@ class GpsStatus { } } - public int getIntervalThreshold() { + public Duration getIntervalThreshold() { return signalLostThreshold; } diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java index 9846fc523..d8f5e7635 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java @@ -10,12 +10,13 @@ import android.util.Log; import androidx.annotation.NonNull; +import java.time.Duration; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.util.LocationUtils; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.TrackPointUtils; -import de.dennisguse.opentracks.util.UnitConversions; class LocationHandler implements HandlerServer.Handler, LocationListener, GpsStatus.GpsStatusListener { @@ -25,7 +26,7 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta private final HandlerServer handlerServer; private GpsStatus gpsStatus; private LocationListenerPolicy locationListenerPolicy; - private long currentRecordingInterval; + private Duration currentRecordingInterval; private int recordingGpsAccuracy; private TrackPoint lastValidTrackPoint; @@ -35,7 +36,7 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta @Override public void onStart(Context context) { - gpsStatus = new GpsStatus(context, this, PreferencesUtils.getMinRecordingInterval(context)); + gpsStatus = new GpsStatus(context, this, Duration.ofSeconds(PreferencesUtils.getMinRecordingInterval(context))); locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); registerLocationListener(); } @@ -56,12 +57,12 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta int minRecordingInterval = PreferencesUtils.getMinRecordingInterval(context); if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptBatteryLife(context)) { // Choose battery life over moving time accuracy. - locationListenerPolicy = new AdaptiveLocationListenerPolicy(30 * UnitConversions.ONE_SECOND_MS, 5 * UnitConversions.ONE_MINUTE_MS, 5); + locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(30), Duration.ofSeconds(5), 5); } else if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptAccuracy(context)) { // Get all the updates. - locationListenerPolicy = new AdaptiveLocationListenerPolicy(UnitConversions.ONE_SECOND_MS, 30 * UnitConversions.ONE_SECOND_MS, 0); + locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(1), Duration.ofSeconds(30), 0); } else { - locationListenerPolicy = new AbsoluteLocationListenerPolicy(minRecordingInterval * UnitConversions.ONE_SECOND_MS); + locationListenerPolicy = new AbsoluteLocationListenerPolicy(Duration.ofSeconds(minRecordingInterval)); } if (locationManager != null) { @@ -108,9 +109,9 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta return; } - long idleTime = 0L; - if (TrackPointUtils.after(trackPoint, lastValidTrackPoint)) { - idleTime = trackPoint.getTime() - lastValidTrackPoint.getTime(); + Duration idleTime = Duration.ofSeconds(0); + if (lastValidTrackPoint != null && trackPoint.getTime().isAfter(lastValidTrackPoint.getTime())) { + idleTime = Duration.between(lastValidTrackPoint.getTime(), trackPoint.getTime()); } locationListenerPolicy.updateIdleTime(idleTime); @@ -146,9 +147,9 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta return; } try { - long interval = locationListenerPolicy.getDesiredPollingInterval(); + Duration interval = locationListenerPolicy.getDesiredPollingInterval(); currentRecordingInterval = interval; - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, locationListenerPolicy.getMinDistance_m(), this); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval.toMillis(), locationListenerPolicy.getMinDistance_m(), this); } catch (SecurityException e) { Log.e(TAG, "Could not register location listener; permissions not granted.", e); } diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationListenerPolicy.java b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationListenerPolicy.java index beebeda4e..f94d7b05b 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationListenerPolicy.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationListenerPolicy.java @@ -16,6 +16,8 @@ package de.dennisguse.opentracks.services.handlers; +import java.time.Duration; + /** * This is an interface for classes that will manage the location listener policy. * @@ -28,7 +30,7 @@ interface LocationListenerPolicy { * * @return the polling interval */ - long getDesiredPollingInterval(); + Duration getDesiredPollingInterval(); /** * Returns the minimum distance between updates. @@ -40,5 +42,5 @@ interface LocationListenerPolicy { * * @param idleTime the time that the user has been idle at his current location */ - void updateIdleTime(long idleTime); + void updateIdleTime(Duration idleTime); } diff --git a/src/main/java/de/dennisguse/opentracks/services/tasks/PeriodicTaskExecutor.java b/src/main/java/de/dennisguse/opentracks/services/tasks/PeriodicTaskExecutor.java index b94b7693f..f16ea3c1d 100644 --- a/src/main/java/de/dennisguse/opentracks/services/tasks/PeriodicTaskExecutor.java +++ b/src/main/java/de/dennisguse/opentracks/services/tasks/PeriodicTaskExecutor.java @@ -17,6 +17,8 @@ package de.dennisguse.opentracks.services.tasks; import android.util.Log; +import java.time.Duration; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.stats.TrackStatistics; @@ -92,7 +94,7 @@ public class PeriodicTaskExecutor { if (timerTaskExecutor == null) { timerTaskExecutor = new TimerTaskExecutor(periodicTask, trackRecordingService); } - timerTaskExecutor.scheduleTask(taskFrequency * UnitConversions.ONE_MINUTE_MS); + timerTaskExecutor.scheduleTask(Duration.ofSeconds(taskFrequency)); } else { // For distance periodic task calculateNextTaskDistance(); diff --git a/src/main/java/de/dennisguse/opentracks/services/tasks/TimerTaskExecutor.java b/src/main/java/de/dennisguse/opentracks/services/tasks/TimerTaskExecutor.java index e8b45ed9d..d7ad7e4b8 100644 --- a/src/main/java/de/dennisguse/opentracks/services/tasks/TimerTaskExecutor.java +++ b/src/main/java/de/dennisguse/opentracks/services/tasks/TimerTaskExecutor.java @@ -16,6 +16,7 @@ package de.dennisguse.opentracks.services.tasks; +import java.time.Duration; import java.util.Date; import java.util.Timer; import java.util.TimerTask; @@ -42,15 +43,9 @@ class TimerTaskExecutor { } /** - * Schedules the periodic task in milliseconds. - * - * @param interval_ms the interval_ms + * Schedules the periodic task. */ - void scheduleTask(long interval_ms) { - if (interval_ms <= 0) { - return; - } - + void scheduleTask(Duration interval) { if (!trackRecordingService.isRecording() || trackRecordingService.isPaused()) { return; } @@ -69,8 +64,10 @@ class TimerTaskExecutor { } }; timer = new Timer(TimerTaskExecutor.class.getSimpleName()); - long next = System.currentTimeMillis() + interval_ms - (trackStatistics.getTotalTime() % interval_ms); - timer.scheduleAtFixedRate(timerTask, new Date(next), interval_ms); + + //TODO Simplify: far too complicated for it's purpose + long next = System.currentTimeMillis() + interval.toMillis() - (trackStatistics.getTotalTime().toMillis() % interval.toMillis()); + timer.scheduleAtFixedRate(timerTask, new Date(next), interval.toMillis()); } void shutdown() { diff --git a/src/main/java/de/dennisguse/opentracks/stats/TrackStatistics.java b/src/main/java/de/dennisguse/opentracks/stats/TrackStatistics.java index 49fd74fc5..8e947ab77 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/TrackStatistics.java +++ b/src/main/java/de/dennisguse/opentracks/stats/TrackStatistics.java @@ -19,6 +19,9 @@ package de.dennisguse.opentracks.stats; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.time.Duration; +import java.time.Instant; + /** * Statistical data about a {@link de.dennisguse.opentracks.content.data.Track}. * The data in this class should be filled out by {@link TrackStatisticsUpdater}. @@ -33,15 +36,15 @@ public class TrackStatistics { private final ExtremityMonitor elevationExtremities = new ExtremityMonitor(); // The track start time. - private long startTime_ms; + private Instant startTime; // The track stop time. - private long stopTime_ms; + private Instant stopTime; private double totalDistance_m; // Updated when new points are received, may be stale. - private long totalTime_ms; + private Duration totalTime; // Based on when we believe the user is traveling. - private long movingTime_ms; + private Duration movingTime; // The maximum speed (meters/second) that we believe is valid. private double maxSpeed_mps; // The total elevation gained (meters). @@ -60,11 +63,11 @@ public class TrackStatistics { * @param other another statistics data object to copy from */ public TrackStatistics(TrackStatistics other) { - startTime_ms = other.startTime_ms; - stopTime_ms = other.stopTime_ms; + startTime = other.startTime; + stopTime = other.stopTime; totalDistance_m = other.totalDistance_m; - totalTime_ms = other.totalTime_ms; - movingTime_ms = other.movingTime_ms; + totalTime = other.totalTime; + movingTime = other.movingTime; maxSpeed_mps = other.maxSpeed_mps; elevationExtremities.set(other.elevationExtremities.getMin(), other.elevationExtremities.getMax()); totalElevationGain_m = other.totalElevationGain_m; @@ -78,11 +81,11 @@ public class TrackStatistics { * @param other another statistics data object */ public void merge(TrackStatistics other) { - startTime_ms = Math.min(startTime_ms, other.startTime_ms); - stopTime_ms = Math.max(stopTime_ms, other.stopTime_ms); + startTime = startTime.isBefore(other.startTime) ? startTime : other.startTime; + stopTime = stopTime.isAfter(other.stopTime) ? stopTime : other.stopTime; totalDistance_m += other.totalDistance_m; - totalTime_ms += other.totalTime_ms; - movingTime_ms += other.movingTime_ms; + totalTime = totalTime.plus(other.totalTime); + movingTime = movingTime.plus(other.movingTime); maxSpeed_mps = Math.max(maxSpeed_mps, other.maxSpeed_mps); if (other.elevationExtremities.hasData()) { elevationExtremities.update(other.elevationExtremities.getMin()); @@ -109,44 +112,41 @@ public class TrackStatistics { } public void reset() { - setStartTime_ms(0); + setStartTime(Instant.ofEpochMilli(0)); //TODO should probably initialized with null setTotalDistance(0); - setTotalTime(0); - setMovingTime(0); + setTotalTime(Duration.ofSeconds(0)); + setMovingTime(Duration.ofSeconds(0)); setMaxSpeed(0); setTotalElevationGain(null); } - public void reset(long startTime_ms) { + public void reset(Instant startTime) { reset(); - setStartTime_ms(startTime_ms); + setStartTime(startTime); } - /** - * Gets the track start time. The number of milliseconds since epoch. - */ - public long getStartTime_ms() { - return startTime_ms; + public Instant getStartTime() { + return startTime; } /** * Should only be called on start. */ - public void setStartTime_ms(long startTime_ms) { - this.startTime_ms = startTime_ms; - setStopTime_ms(startTime_ms); + public void setStartTime(Instant startTime) { + this.startTime = startTime; + setStopTime(startTime); } - public long getStopTime_ms() { - return stopTime_ms; + public Instant getStopTime() { + return stopTime; } - public void setStopTime_ms(long stopTime_ms) { - if (stopTime_ms < startTime_ms) { - throw new RuntimeException("stopTime cannot be less than startTime: " + startTime_ms + " " + stopTime_ms); + public void setStopTime(Instant stopTime) { + if (stopTime.isBefore(startTime)) { + throw new RuntimeException("stopTime cannot be less than startTime: " + startTime + " " + stopTime); } - this.stopTime_ms = stopTime_ms; + this.stopTime = stopTime; } public double getTotalDistance() { @@ -164,26 +164,26 @@ public class TrackStatistics { /** * Gets the total time in milliseconds that this track has been active. * This statistic is only updated when a new point is added to the statistics, so it may be off. - * If you need to calculate the proper total time, use {@link #getStartTime_ms} with the current time. + * If you need to calculate the proper total time, use {@link #getStartTime} with the current time. */ - public long getTotalTime() { - return totalTime_ms; + public Duration getTotalTime() { + return totalTime; } - public void setTotalTime(long totalTime_ms) { - this.totalTime_ms = totalTime_ms; + public void setTotalTime(Duration totalTime) { + this.totalTime = totalTime; } - public long getMovingTime() { - return movingTime_ms; + public Duration getMovingTime() { + return movingTime; } - public void setMovingTime(long movingTime_ms) { - this.movingTime_ms = movingTime_ms; + public void setMovingTime(Duration movingTime) { + this.movingTime = movingTime; } - public void addMovingTime(long time_ms) { - movingTime_ms += time_ms; + public void addMovingTime(Duration time) { + movingTime = movingTime.plus(time); } /** @@ -191,20 +191,20 @@ public class TrackStatistics { * This calculation only takes into account the displacement until the last point that was accounted for in statistics. */ public double getAverageSpeed() { - if (totalTime_ms == 0L) { + if (totalTime.isZero()) { return 0.0; } - return totalDistance_m / ((double) totalTime_ms / 1000.0); + return totalDistance_m / (double) totalTime.getSeconds(); } /** * Gets the average moving speed in meters/second. */ public double getAverageMovingSpeed() { - if (movingTime_ms == 0L) { + if (movingTime.isZero()) { return 0.0; } - return totalDistance_m / ((double) movingTime_ms / 1000.0); + return totalDistance_m / (double) movingTime.getSeconds(); } /** @@ -317,7 +317,7 @@ public class TrackStatistics { @NonNull @Override public String toString() { - return "TrackStatistics { Start Time: " + getStartTime_ms() + "; Stop Time: " + getStopTime_ms() + return "TrackStatistics { Start Time: " + getStartTime() + "; Stop Time: " + getStopTime() + "; Total Distance: " + getTotalDistance() + "; Total Time: " + getTotalTime() + "; Moving Time: " + getMovingTime() + "; Max Speed: " + getMaxSpeed() + "; Min Elevation: " + getMinElevation() + "; Max Elevation: " + getMaxElevation() diff --git a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java index 713205aa2..af87c041c 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java @@ -21,6 +21,9 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import java.time.Duration; +import java.time.Instant; + import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.util.TrackPointUtils; @@ -88,9 +91,9 @@ public class TrackStatisticsUpdater { trackInitialized = true; } - public void updateTime(long time_ms) { - currentSegment.setStopTime_ms(time_ms); - currentSegment.setTotalTime(time_ms - currentSegment.getStartTime_ms()); + public void updateTime(Instant time) { + currentSegment.setStopTime(time); + currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), time)); } public TrackStatistics getTrackStatistics() { @@ -108,11 +111,11 @@ public class TrackStatisticsUpdater { */ public void addTrackPoint(TrackPoint trackPoint, int minRecordingDistance) { if (!trackInitialized) { - trackStatistics.setStartTime_ms(trackPoint.getTime()); + trackStatistics.setStartTime(trackPoint.getTime()); trackInitialized = true; } if (!segmentInitialized) { - currentSegment.setStartTime_ms(trackPoint.getTime()); + currentSegment.setStartTime(trackPoint.getTime()); segmentInitialized = true; } @@ -162,8 +165,8 @@ public class TrackStatisticsUpdater { lastTrackPoint = trackPoint; return; } - long movingTime = trackPoint.getTime() - lastTrackPoint.getTime(); - if (movingTime < 0) { + Duration movingTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); + if (movingTime.isNegative()) { lastTrackPoint = trackPoint; return; } @@ -252,9 +255,9 @@ public class TrackStatisticsUpdater { } // See if the speed seems physically likely. Ignore any speeds that imply acceleration greater than 2g. - long timeDifference = trackPoint.getTime() - lastTrackPoint.getTime(); + Duration timeDifference = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); double speedDifference = Math.abs(lastTrackPoint.getSpeed() - trackPoint.getSpeed()); - if (speedDifference > MAX_ACCELERATION * timeDifference) { + if (speedDifference > MAX_ACCELERATION * timeDifference.toMillis()) { return false; } @@ -262,7 +265,7 @@ public class TrackStatisticsUpdater { if (speedBuffer_ms.isFull()) { double average = speedBuffer_ms.getAverage(); double diff = Math.abs(average - trackPoint.getSpeed()); - return (trackPoint.getSpeed() < average * 10) && (diff < MAX_ACCELERATION * timeDifference); + return (trackPoint.getSpeed() < average * 10) && (diff < MAX_ACCELERATION * timeDifference.toMillis()); } return true; diff --git a/src/main/java/de/dennisguse/opentracks/util/AnnouncementUtils.java b/src/main/java/de/dennisguse/opentracks/util/AnnouncementUtils.java index 62ae20beb..ee5dff3af 100644 --- a/src/main/java/de/dennisguse/opentracks/util/AnnouncementUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/AnnouncementUtils.java @@ -4,13 +4,16 @@ import android.content.Context; import androidx.annotation.Nullable; +import java.time.Duration; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.viewmodels.IntervalStatistics; public class AnnouncementUtils { - private AnnouncementUtils() {} + private AnnouncementUtils() { + } public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category, @Nullable IntervalStatistics.Interval currentInterval) { boolean metricUnits = PreferencesUtils.isMetricUnits(context); @@ -41,11 +44,11 @@ public class AnnouncementUtils { } else { double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime; int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile; - long time = Math.round(timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS); + Duration time = Duration.ofMillis((long) (timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS)); rate = context.getString(paceId, getAnnounceTime(context, time)); double currentTimePerDistance = currentDistancePerTime == 0 ? 0.0 : 1 / currentDistancePerTime; - long currentTime = Math.round(currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS); + Duration currentTime = Duration.ofMillis((long) (currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS)); currentRate = context.getString(paceId, getAnnounceTime(context, currentTime)); currentRateMsg = context.getString(R.string.voice_pace_lap, currentRate); } @@ -58,23 +61,25 @@ public class AnnouncementUtils { return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate) + currentRateMsg; } - private static String getAnnounceTime(Context context, long time) { - int[] parts = StringUtils.getTimeParts(time); - String seconds = context.getResources() - .getQuantityString(R.plurals.voiceSeconds, parts[0], parts[0]); - String minutes = context.getResources() - .getQuantityString(R.plurals.voiceMinutes, parts[1], parts[1]); - String hours = context.getResources() - .getQuantityString(R.plurals.voiceHours, parts[2], parts[2]); - StringBuilder sb = new StringBuilder(); - if (parts[2] != 0) { - sb.append(hours); - sb.append(" "); + //TODO We might need to localize this using strings.xml if order is relevant. + private static String getAnnounceTime(Context context, Duration duration) { + String result = ""; + + int hours = (int) (duration.getSeconds() / (60 * 60)); + int minutes = (int) (duration.getSeconds() / 60); + int seconds = (int) (duration.getSeconds() % 60); + + if (hours != 0) { + String hoursText = context.getResources() + .getQuantityString(R.plurals.voiceHours, hours, hours); + result += hoursText + " "; } - sb.append(minutes); - sb.append(" "); - sb.append(seconds); - return sb.toString(); + String minutesText = context.getResources() + .getQuantityString(R.plurals.voiceMinutes, minutes, minutes); + String secondsText = context.getResources() + .getQuantityString(R.plurals.voiceSeconds, seconds, seconds); + + return result + minutesText + " " + secondsText; } /** diff --git a/src/main/java/de/dennisguse/opentracks/util/LocationUtils.java b/src/main/java/de/dennisguse/opentracks/util/LocationUtils.java index 05c5dcc98..d4704b59c 100644 --- a/src/main/java/de/dennisguse/opentracks/util/LocationUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/LocationUtils.java @@ -17,6 +17,9 @@ package de.dennisguse.opentracks.util; import android.location.Location; +import java.time.Duration; +import java.time.Instant; + import de.dennisguse.opentracks.content.data.TrackPoint; /** @@ -28,8 +31,7 @@ public class LocationUtils { private static final String TAG = LocationUtils.class.getSimpleName(); - // 1 minute in milliseconds - private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS); + private static final Duration MAX_LOCATION_AGE = Duration.ofMinutes(1); private LocationUtils() { } @@ -48,6 +50,8 @@ public class LocationUtils { } public static boolean isTrackPointOld(TrackPoint trackPoint) { - return System.currentTimeMillis() - trackPoint.getTime() > MAX_LOCATION_AGE_MS; + return Duration.between(trackPoint.getTime(), Instant.now()) + .minus(MAX_LOCATION_AGE) + .isNegative(); } } diff --git a/src/main/java/de/dennisguse/opentracks/util/StringUtils.java b/src/main/java/de/dennisguse/opentracks/util/StringUtils.java index 94f55ac9e..661d45568 100644 --- a/src/main/java/de/dennisguse/opentracks/util/StringUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/StringUtils.java @@ -22,8 +22,11 @@ import android.text.format.DateUtils; import android.util.Log; import android.util.Pair; +import androidx.annotation.NonNull; + import java.math.RoundingMode; import java.text.DecimalFormat; +import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -50,41 +53,32 @@ public class StringUtils { } /** - * Formats the date and time_ms based on user's phone date/time_ms preferences. - * - * @param context the context - * @param time_ms the time_ms in milliseconds + * Formats the date and time based on user's phone date/time preferences. */ - public static String formatDateTime(Context context, long time_ms) { - return DateUtils.formatDateTime(context, time_ms, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE) - + " " + DateUtils.formatDateTime(context, time_ms, DateUtils.FORMAT_SHOW_TIME); + public static String formatDateTime(Context context, Instant time) { + return DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE) + + " " + DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_TIME); } /** - * Formats the time using the ISO 8601 date time_ms format with fractional seconds in UTC time zone. - * - * @param time_ms the time in milliseconds + * Formats the time using the ISO 8601 date time format with fractional seconds in UTC time zone. */ - public static String formatDateTimeIso8601(long time_ms) { - return Instant.ofEpochMilli(time_ms).toString(); + public static String formatDateTimeIso8601(@NonNull Instant time) { + return time.toString(); } /** * Formats the elapsed timed in the form "MM:SS" or "H:MM:SS". - * - * @param time_ms the time in milliseconds */ - public static String formatElapsedTime(long time_ms) { - return DateUtils.formatElapsedTime((long) (time_ms * UnitConversions.MS_TO_S)); + public static String formatElapsedTime(@NonNull Duration time) { + return DateUtils.formatElapsedTime(time.getSeconds()); } /** * Formats the elapsed time in the form "H:MM:SS". - * - * @param time_ms the time in milliseconds */ - public static String formatElapsedTimeWithHour(long time_ms) { - String value = formatElapsedTime(time_ms); + public static String formatElapsedTimeWithHour(@NonNull Duration time) { + String value = formatElapsedTime(time); return TextUtils.split(value, ":").length == 2 ? "0:" + value : value; } @@ -289,45 +283,20 @@ public class StringUtils { * * @param xmlDateTime the XML date time string */ - public static long parseTime(String xmlDateTime) { + public static Instant parseTime(String xmlDateTime) { try { TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parseBest(xmlDateTime, ZonedDateTime::from, LocalDateTime::from); if (t instanceof LocalDateTime) { Log.w(TAG, "Date does not contain timezone information: using UTC."); t = ((LocalDateTime) t).atZone(ZoneOffset.UTC); } - return Instant.from(t).toEpochMilli(); + return Instant.from(t); } catch (Exception e) { Log.e(TAG, "Invalid XML dateTime value"); throw e; } } - /** - * Gets the time as an array of three integers. - * Index 0 contains the number of seconds, index 1 contains the number of minutes, and index 2 contains the number of hours. - * - * @param time the time in milliseconds - * @return an array of 3 elements. - */ - public static int[] getTimeParts(long time) { - if (time < 0) { - int[] parts = getTimeParts(time * -1); - parts[0] *= -1; - parts[1] *= -1; - parts[2] *= -1; - return parts; - } - int[] parts = new int[3]; - - long seconds = (long) (time * UnitConversions.MS_TO_S); - parts[0] = (int) (seconds % 60); - int minutes = (int) (seconds / 60); - parts[1] = minutes % 60; - parts[2] = minutes / 60; - return parts; - } - /** * Gets the frequency display options. * diff --git a/src/main/java/de/dennisguse/opentracks/util/TrackNameUtils.java b/src/main/java/de/dennisguse/opentracks/util/TrackNameUtils.java index a5423f853..cd8bbe2a9 100644 --- a/src/main/java/de/dennisguse/opentracks/util/TrackNameUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/TrackNameUtils.java @@ -21,6 +21,7 @@ import android.content.Context; import androidx.annotation.VisibleForTesting; import java.text.SimpleDateFormat; +import java.time.Instant; import java.util.Locale; import de.dennisguse.opentracks.R; @@ -40,20 +41,13 @@ public class TrackNameUtils { private TrackNameUtils() { } - /** - * Gets the track name. - * - * @param context the context - * @param trackId the track id - * @param startTime the track start time - */ - public static String getTrackName(Context context, Track.Id trackId, long startTime) { + public static String getTrackName(Context context, Track.Id trackId, Instant startTime) { String trackName = PreferencesUtils.getString(context, R.string.track_name_key, context.getString(R.string.track_name_default)); if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) { return StringUtils.formatDateTime(context, startTime); } else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) { - return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime); + return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime.toEpochMilli()); } else { return context.getString(R.string.track_name_format, trackId.getId()); } diff --git a/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java b/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java index 6343423e9..d3bfc5f1f 100644 --- a/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java @@ -18,22 +18,6 @@ public class TrackPointUtils { return trackPoint.hasSpeed() && trackPoint.getSpeed() >= MAX_NO_MOVEMENT_SPEED; } - public static boolean equalTime(TrackPoint t1, TrackPoint t2) { - if (t1 == null || t2 == null) { - return false; - } - - return t1.getTime() == t2.getTime(); - } - - public static boolean after(TrackPoint t1, TrackPoint t2) { - if (t1 == null || t2 == null) { - return false; - } - - return t1.getTime() > t2.getTime(); - } - /** * Is accuracy better than threshold? */ diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java index 90f773dc8..a461f5ee2 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java @@ -2,6 +2,7 @@ package de.dennisguse.opentracks.viewmodels; import androidx.annotation.NonNull; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,7 @@ public class IntervalStatistics { if (trackPoint.hasLocation() && prevTrackPoint.hasLocation()) { interval.distance_m += prevTrackPoint.distanceTo(trackPoint); - interval.time_ms += trackPoint.getTime() - prevTrackPoint.getTime(); + interval.time = interval.time.plus(Duration.between(prevTrackPoint.getTime(), trackPoint.getTime())); interval.gain_m += trackPoint.hasElevationGain() ? trackPoint.getElevationGain() : 0; interval.loss_m += trackPoint.hasElevationLoss() ? trackPoint.getElevationLoss() : 0; @@ -44,7 +45,7 @@ public class IntervalStatistics { intervalList.add(adjustedInterval); - interval = new Interval(interval.distance_m - adjustedInterval.distance_m, interval.time_ms - adjustedInterval.time_ms); + interval = new Interval(interval.distance_m - adjustedInterval.distance_m, interval.time.minus(adjustedInterval.time)); } } } @@ -81,22 +82,21 @@ public class IntervalStatistics { public static class Interval { private float distance_m = 0f; - private float time_ms = 0f; + private Duration time = Duration.ofSeconds(0); private float gain_m = 0f; private float loss_m = 0f; - public Interval() {} + public Interval() { + } - public Interval(float distance_m, float time_ms) { + public Interval(float distance_m, Duration time) { this.distance_m = distance_m; - this.time_ms = time_ms; - this.gain_m = 0f; - this.loss_m = 0f; + this.time = time; } public Interval(Interval i) { distance_m = i.distance_m; - time_ms = i.time_ms; + time = i.time; gain_m = i.gain_m; loss_m = i.loss_m; } @@ -107,7 +107,7 @@ public class IntervalStatistics { public void adjust(float adjustFactor) { distance_m *= adjustFactor; - time_ms *= adjustFactor; + time = Duration.ofMillis((long) (time.toMillis() * adjustFactor)); } /** @@ -117,7 +117,7 @@ public class IntervalStatistics { if (distance_m == 0f) { return 0f; } - return distance_m / (float) (time_ms * UnitConversions.MS_TO_S); + return (distance_m / (time.toMillis() * (float) UnitConversions.MS_TO_S)); } public float getGain_m() {