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 80cee95cf..128a80979 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java @@ -14,6 +14,7 @@ import java.util.List; import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.stats.TrackStatistics; +import de.dennisguse.opentracks.stats.TrackStatisticsUpdater; import de.dennisguse.opentracks.util.FileUtils; public class TestDataUtil { @@ -166,4 +167,20 @@ public class TestDataUtil { } return trackPoints; } + + public static Pair buildTrackWithTrackPoints(ContentProviderUtils contentProviderUtils, int numberOfPoints) { + Track dummyTrack = new Track(); + dummyTrack.setId(new Track.Id(System.currentTimeMillis())); + dummyTrack.setName("Dummy Track"); + contentProviderUtils.insertTrack(dummyTrack); + TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(); + for (int i = 0; i < numberOfPoints; i++) { + TrackPoint tp = TestDataUtil.createTrackPoint(i); + contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId()); + trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0)); + } + dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics()); + contentProviderUtils.updateTrack(dummyTrack); + return new Pair<>(dummyTrack.getId(), trackStatisticsUpdater.getTrackStatistics()); + } } diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java index d9b3ff178..670980f24 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/util/AnnouncementUtilsTest.java @@ -1,21 +1,23 @@ package de.dennisguse.opentracks.util; import android.content.Context; +import android.util.Pair; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.time.Duration; -import java.util.List; import de.dennisguse.opentracks.content.data.Distance; import de.dennisguse.opentracks.content.data.Speed; import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.content.data.Track; -import de.dennisguse.opentracks.content.data.TrackPoint; +import de.dennisguse.opentracks.content.provider.ContentProviderUtils; +import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.viewmodels.IntervalStatistics; @@ -25,6 +27,12 @@ import static org.junit.Assert.assertEquals; public class AnnouncementUtilsTest { private final Context context = ApplicationProvider.getApplicationContext(); + private ContentProviderUtils contentProviderUtils; + + @Before + public void setUp() { + contentProviderUtils = new ContentProviderUtils(context); + } @Test public void getAnnouncement_metric_speed() { @@ -44,23 +52,31 @@ public class AnnouncementUtilsTest { @Test public void getAnnouncement_withInterval_metric_speed() { - TrackStatistics stats = new TrackStatistics(); - stats.setTotalDistance(Distance.of(20000)); - stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10)); - stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10)); - stats.setMaxSpeed(Speed.of(100)); - stats.setTotalAltitudeGain(6000f); - - List trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second; - IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); - intervalStatistics.addTrackPoints(trackPoints); - IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + // given + int numberOfPoints = 1000; + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics stats = trackWithStats.second; + IntervalStatistics.Interval lastInterval; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); + lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + } // when String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval); // then - assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour Lap speed of 51.2 kilometers per hour", announcement); + assertEquals( + "OpenTracks total distance " + + StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first + + " kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " + + StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), true, true).first + + " kilometers per hour Lap speed of " + + StringUtils.getSpeedParts(context, lastInterval.getSpeed(), true, true).first + + " kilometers per hour", + announcement); } @Test @@ -81,23 +97,31 @@ public class AnnouncementUtilsTest { @Test public void getAnnouncement_withInterval_metric_pace() { - TrackStatistics stats = new TrackStatistics(); - stats.setTotalDistance(Distance.of(20000)); - stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10)); - stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10)); - stats.setMaxSpeed(Speed.of(100)); - stats.setTotalAltitudeGain(6000f); - - List trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second; - IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); - intervalStatistics.addTrackPoints(trackPoints); - IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + // given + int numberOfPoints = 1000; + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics stats = trackWithStats.second; + IntervalStatistics.Interval lastInterval; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); + lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + } // when String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval); // then - assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 3 minutes 15 seconds per kilometer Lap time of 1 minute 10 seconds per kilometer", announcement); + assertEquals( + "OpenTracks total distance " + + StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first + + " kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " + + buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(true), true) + + " per kilometer Lap time of " + + buildAndGetTimeText(lastInterval.getSpeed().toPace(true), true) + + " per kilometer", + announcement); } @Test @@ -118,23 +142,31 @@ public class AnnouncementUtilsTest { @Test public void getAnnouncement_withInterval_imperial_speed() { - TrackStatistics stats = new TrackStatistics(); - stats.setTotalDistance(Distance.of(20000)); - stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10)); - stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10)); - stats.setMaxSpeed(Speed.of(100)); - stats.setTotalAltitudeGain(6000f); - - List trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second; - IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); - intervalStatistics.addTrackPoints(trackPoints); - IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + // given + int numberOfPoints = 1000; + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics stats = trackWithStats.second; + IntervalStatistics.Interval lastInterval; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); + lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + } // when String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval); // then - assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 11.4 miles per hour Lap speed of 31.8 miles per hour", announcement); + assertEquals( + "OpenTracks total distance " + + StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first + + " miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " + + StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), false, true).first + + " miles per hour Lap speed of " + + StringUtils.getSpeedParts(context, lastInterval.getSpeed(), false, true).first + + " miles per hour", + announcement); } @Test @@ -155,22 +187,60 @@ public class AnnouncementUtilsTest { @Test public void getAnnouncement_withInterval_imperial_pace() { - TrackStatistics stats = new TrackStatistics(); - stats.setTotalDistance(Distance.of(20000)); - stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10)); - stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10)); - stats.setMaxSpeed(Speed.of(100)); - stats.setTotalAltitudeGain(6000f); - - List trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second; - IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); - intervalStatistics.addTrackPoints(trackPoints); - IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + // given + int numberOfPoints = 1000; + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics stats = trackWithStats.second; + IntervalStatistics.Interval lastInterval; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0)); + lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + } // when String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval); // then - assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement); + //assertEquals("OpenTracks total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement); + assertEquals( + "OpenTracks total distance " + + StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first + + " miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " + + buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(false), true) + + " per mile Lap time of " + + buildAndGetTimeText(lastInterval.getSpeed().toPace(false), true) + + " per mile", + announcement); + } + + /** + * Builds an returns the text representing the duration's time. + * + * @param duration Duration object. + * @param showFromMinutes show minutes tough it's 0. + * @return text representing the duratin's time. + */ + private String buildAndGetTimeText(Duration duration, boolean showFromMinutes) { + long hours = Math.abs(duration.getSeconds()) / 3600; + long minutes = (Math.abs(duration.getSeconds()) % 3600) / 60; + long seconds = Math.abs(duration.getSeconds()) % 60; + String hUnit = hours > 1 || hours == 0 ? "hours" : "hour"; + String mUnit = minutes > 1 || minutes == 0 ? "minutes" : "minute"; + String sUnit = seconds > 1 || seconds == 0 ? "seconds" : "second"; + + String res = hours > 0 ? hours + " " + hUnit : ""; + if (hours > 0) { + res += minutes > 0 || showFromMinutes ? " " + minutes + " " + mUnit : ""; + } else { + res += minutes > 0 || showFromMinutes ? minutes + " " + mUnit : ""; + } + if (hours > 0 || minutes > 0 || showFromMinutes) { + res += " " + seconds + " " + sUnit; + } else { + res += seconds + " " + sUnit; + } + return res; } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java index c90b96a1c..f1a6a9424 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsTest.java @@ -1,5 +1,11 @@ package de.dennisguse.opentracks.viewmodels; +import android.content.Context; +import android.util.Pair; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -10,6 +16,8 @@ import de.dennisguse.opentracks.content.data.Distance; import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; +import de.dennisguse.opentracks.content.provider.ContentProviderUtils; +import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.stats.TrackStatisticsUpdater; import de.dennisguse.opentracks.util.UnitConversions; @@ -21,8 +29,12 @@ public class IntervalStatisticsTest { private static final String TAG = IntervalStatisticsTest.class.getSimpleName(); - private List buildTrackPoints(int numberOfTrackPoints) { - return TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), numberOfTrackPoints).second; + private final Context context = ApplicationProvider.getApplicationContext(); + private ContentProviderUtils contentProviderUtils; + + @Before + public void setUp() { + contentProviderUtils = new ContentProviderUtils(context); } private TrackStatistics buildTrackStatistics(List trackPoints) { @@ -41,12 +53,10 @@ public class IntervalStatisticsTest { // With 50 points and interval distance of 1000m. // given - List trackPoints = buildTrackPoints(50); - TrackStatistics trackStatistics = buildTrackStatistics(trackPoints); float distanceInterval = 1000f; // when and then - whenAndThen(trackPoints, trackStatistics, distanceInterval); + whenAndThen(50, distanceInterval); } /** @@ -57,12 +67,10 @@ public class IntervalStatisticsTest { // With 200 points and interval distance of 1000m. // given - List trackPoints = buildTrackPoints(200); - TrackStatistics trackStatistics = buildTrackStatistics(trackPoints); float distanceInterval = 1000f; // when and then - whenAndThen(trackPoints, trackStatistics, distanceInterval); + whenAndThen(200, distanceInterval); } /** @@ -73,12 +81,10 @@ public class IntervalStatisticsTest { // With 200 points and interval distance of 3000m. // given - List trackPoints = buildTrackPoints(200); - TrackStatistics trackStatistics = buildTrackStatistics(trackPoints); float distanceInterval = 3000f; // when and then - whenAndThen(trackPoints, trackStatistics, distanceInterval); + whenAndThen(3000, distanceInterval); } /** @@ -89,12 +95,10 @@ public class IntervalStatisticsTest { // With 1000 points and interval distance of 3000m. // given - List trackPoints = buildTrackPoints(1000); - TrackStatistics trackStatistics = buildTrackStatistics(trackPoints); float distanceInterval = 3000f; // when and then - whenAndThen(trackPoints, trackStatistics, distanceInterval); + whenAndThen(1000, distanceInterval); } /** @@ -105,17 +109,21 @@ public class IntervalStatisticsTest { // With 10000 points and interval distance of 1000m. // given - List trackPoints = buildTrackPoints(10000); - TrackStatistics trackStatistics = buildTrackStatistics(trackPoints); float distanceInterval = 1000f; // when and then - whenAndThen(trackPoints, trackStatistics, distanceInterval); + whenAndThen(10000, distanceInterval); } - private void whenAndThen(List trackPoints, TrackStatistics trackStatistics, float distanceInterval) { + private void whenAndThen(int numberOfPoints, float distanceInterval) { IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(distanceInterval), Distance.of(0)); - intervalStatistics.addTrackPoints(trackPoints); + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics trackStatistics = trackWithStats.second; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + intervalStatistics.addTrackPoints(trackPointIterator); + } List intervalList = intervalStatistics.getIntervalList(); Distance totalDistance = Distance.of(0); float totalTime = 0L; @@ -130,7 +138,7 @@ public class IntervalStatisticsTest { assertEquals(trackStatistics.getTotalDistance().toM(), totalDistance.toM(), 0.01); assertEquals(trackStatistics.getTotalTime().toMillis(), totalTime * UnitConversions.S_TO_MS, 1); assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance().toM() / distanceInterval)); - assertEquals(totalGain, trackPoints.size() * TestDataUtil.ALTITUDE_GAIN, 0.1); + assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1); for (int i = 0; i < intervalList.size() - 1; i++) { assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001); 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 693a2fa70..605dbecd3 100644 --- a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java +++ b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java @@ -37,6 +37,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.UUID; +import java.util.stream.StreamSupport; import de.dennisguse.opentracks.BuildConfig; import de.dennisguse.opentracks.content.data.Altitude; @@ -745,16 +746,6 @@ public class ContentProviderUtils { return new TrackPointIterator(this, trackId, startTrackPointId); } - public List getTrackPoints(final Track.Id trackId, final TrackPoint.Id startTrackPointId) { - List trackPoints = new ArrayList<>(); - try (TrackPointIterator trackPointIterator = getTrackPointLocationIterator(trackId, startTrackPointId)) { - while (trackPointIterator.hasNext()) { - trackPoints.add(trackPointIterator.next()); - } - } - return trackPoints; - } - @Deprecated private TrackPoint findTrackPointBy(String selection, String[] selectionArgs) { try (Cursor cursor = getTrackPointCursor(null, selection, selectionArgs, TrackPointsColumns._ID)) { diff --git a/src/main/java/de/dennisguse/opentracks/fragments/IntervalsFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsFragment.java index f9cefd294..27db82638 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/IntervalsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/IntervalsFragment.java @@ -64,7 +64,7 @@ public class IntervalsFragment extends Fragment { /** * Creates an instance of this class. * - * @param trackId track's id. + * @param trackId * @param fromTopToBottom If true then the intervals are shown from top to bottom (the first interval on top). Otherwise the intervals are shown from bottom to top. * @return IntervalsFragment instance. */ @@ -185,7 +185,7 @@ public class IntervalsFragment extends Fragment { } private synchronized void updateIntervals(boolean metricUnits, IntervalStatisticsModel.IntervalOption selectedInterval) { - boolean update = metricUnits != this.metricUnits || !selectedInterval.equals(this.selectedInterval); + boolean update = metricUnits != this.metricUnits || !selectedInterval.sameMultiplier(this.selectedInterval); this.metricUnits = metricUnits; this.selectedInterval = selectedInterval; diff --git a/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java b/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java index 315653077..e5fc9227c 100644 --- a/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java +++ b/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java @@ -178,19 +178,13 @@ public class AnnouncementPeriodicTask implements PeriodicTask { } String category = track.getCategory(); - //TODO Querying all TrackPoints all the time is inefficient; get infos from TrackRecordingService - TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null); - ArrayList trackPoints = new ArrayList<>(); - while (trackPointIterator.hasNext()) { - trackPoints.add(trackPointIterator.next()); - } - boolean isMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context); boolean isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category); Distance minGPSDistance = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context); + TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null); IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.one(isMetricUnits), minGPSDistance); - intervalStatistics.addTrackPoints(trackPoints); + intervalStatistics.addTrackPoints(trackPointIterator); IntervalStatistics.Interval lastInterval = intervalStatistics.getLastInterval(); String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, isMetricUnits, isReportSpeed, lastInterval); diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java index d3ff8716e..f2a855d85 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatistics.java @@ -1,6 +1,5 @@ package de.dennisguse.opentracks.viewmodels; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.time.Duration; @@ -10,6 +9,7 @@ import java.util.List; import de.dennisguse.opentracks.content.data.Distance; import de.dennisguse.opentracks.content.data.Speed; import de.dennisguse.opentracks.content.data.TrackPoint; +import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.stats.TrackStatisticsUpdater; @@ -34,24 +34,28 @@ public class IntervalStatistics { intervalList.add(lastInterval); } - public void addTrackPoints(@NonNull List trackPoints) { - if (trackPoints.size() == 0) { - return; - } - + /** + * Complete intervals with the tracks points from the iterator. + * + * @param trackPointIterator + * @return the last track point's id used to compute the intervals. + */ + public TrackPoint.Id addTrackPoints(TrackPointIterator trackPointIterator) { boolean newIntervalAdded = false; - for (TrackPoint trackPoint : trackPoints) { + TrackPoint trackPoint = null; + + while (trackPointIterator.hasNext()) { + trackPoint = trackPointIterator.next(); trackStatisticsUpdater.addTrackPoint(trackPoint, minGPSDistance); if (trackStatisticsUpdater.getTrackStatistics().getTotalDistance().plus(interval.distance).greaterOrEqualThan(distanceInterval)) { - interval.update(trackStatisticsUpdater.getTrackStatistics(), trackPoint); + interval.add(trackStatisticsUpdater.getTrackStatistics(), trackPoint); double adjustFactor = distanceInterval.dividedBy(interval.distance); Interval adjustedInterval = new Interval(interval); adjustedInterval.adjust(adjustFactor); - intervalList.remove(intervalList.size() - 1); - intervalList.add(adjustedInterval); + intervalList.set(intervalList.size() - 1, adjustedInterval); interval = new Interval(interval.distance.minus(adjustedInterval.distance), interval.time.minus(adjustedInterval.time)); trackStatisticsUpdater = new TrackStatisticsUpdater(); @@ -65,10 +69,12 @@ public class IntervalStatistics { } if (newIntervalAdded) { - lastInterval.update(trackStatisticsUpdater.getTrackStatistics(), null); + lastInterval.add(trackStatisticsUpdater.getTrackStatistics(), null); } else { lastInterval.set(trackStatisticsUpdater.getTrackStatistics()); } + + return trackPoint != null ? trackPoint.getId() : null; } public List getIntervalList() { @@ -145,7 +151,7 @@ public class IntervalStatistics { return loss_m; } - private void update(TrackStatistics trackStatistics, @Nullable TrackPoint lastTrackPoint) { + private void add(TrackStatistics trackStatistics, @Nullable TrackPoint lastTrackPoint) { distance = distance.plus(trackStatistics.getTotalDistance()); time = time.plus(trackStatistics.getTotalTime()); gain_m = trackStatistics.hasTotalAltitudeGain() ? trackStatistics.getTotalAltitudeGain() : gain_m; diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsModel.java b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsModel.java index 0c8e53f1f..e49cd2149 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsModel.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/IntervalStatisticsModel.java @@ -21,6 +21,7 @@ import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.content.data.TrackPointsColumns; import de.dennisguse.opentracks.content.provider.ContentProviderUtils; +import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.util.PreferencesUtils; /** @@ -47,6 +48,9 @@ public class IntervalStatisticsModel extends AndroidViewModel { super(application); minGPSDistance = PreferencesUtils.getRecordingDistanceInterval(PreferencesUtils.getSharedPreferences(application), application); contentResolver = getApplication().getContentResolver(); + handlerThread = new HandlerThread(TAG); + handlerThread.start(); + handler = new Handler(handlerThread.getLooper()); } @Override @@ -54,6 +58,7 @@ public class IntervalStatisticsModel extends AndroidViewModel { super.onCleared(); if (trackPointsTableObserver != null) { contentResolver.unregisterContentObserver(trackPointsTableObserver); + trackPointsTableObserver = null; } if (handlerThread != null) { handlerThread.getLooper().quit(); @@ -75,25 +80,6 @@ public class IntervalStatisticsModel extends AndroidViewModel { loadIntervalStatistics(trackId); } - registerTrackPointsObserver(trackId); - - return intervalsLiveData; - } - - private void loadIntervalStatistics(Track.Id trackId) { - executor.execute(() -> { - ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication()); - List trackPoints = contentProviderUtils.getTrackPoints(trackId, lastTrackPointId); - lastTrackPointId = trackPoints.size() > 0 ? trackPoints.get(trackPoints.size() - 1).getId() : lastTrackPointId; - intervalStatistics.addTrackPoints(trackPoints); - intervalsLiveData.postValue(intervalStatistics.getIntervalList()); - }); - } - - private void registerTrackPointsObserver(Track.Id trackId) { - handlerThread = new HandlerThread(TAG); - handlerThread.start(); - handler = new Handler(handlerThread.getLooper()); trackPointsTableObserver = new ContentObserver(handler) { @Override public void onChange(boolean selfChange, Uri uri) { @@ -101,6 +87,18 @@ public class IntervalStatisticsModel extends AndroidViewModel { } }; contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_TRACKID, false, trackPointsTableObserver); + + return intervalsLiveData; + } + + private void loadIntervalStatistics(Track.Id trackId) { + executor.execute(() -> { + ContentProviderUtils contentProviderUtils = new ContentProviderUtils(getApplication()); + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, lastTrackPointId)) { + lastTrackPointId = intervalStatistics.addTrackPoints(trackPointIterator); + intervalsLiveData.postValue(intervalStatistics.getIntervalList()); + } + }); } public void onPause() { @@ -145,7 +143,7 @@ public class IntervalStatisticsModel extends AndroidViewModel { .multipliedBy(multiplier); } - public boolean equals(IntervalOption intervalOption) { + public boolean sameMultiplier(IntervalOption intervalOption) { return intervalOption != null && this.multiplier == intervalOption.multiplier; }