forked from upstream-mirrors/OpenTracks
Segments: use TrackPoint.type.
So, far specific latitude for segment start/end (i.e., PAUSE/RESUME) was used. #316.
This commit is contained in:
@@ -63,7 +63,7 @@ public class DescriptionGeneratorTest {
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setMaxElevation(550);
|
||||
stats.setMinElevation(-500);
|
||||
stats.setTotalElevationGain(6000);
|
||||
stats.setTotalElevationGain(6000f);
|
||||
stats.setTotalElevationLoss(6000);
|
||||
stats.setStartTime_ms(START_TIME);
|
||||
track.setTrackStatistics(stats);
|
||||
@@ -101,7 +101,7 @@ public class DescriptionGeneratorTest {
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setMaxElevation(Double.POSITIVE_INFINITY);
|
||||
stats.setMinElevation(Double.NEGATIVE_INFINITY);
|
||||
stats.setTotalElevationGain(6000);
|
||||
stats.setTotalElevationGain(6000f);
|
||||
stats.setTotalElevationLoss(6000);
|
||||
stats.setStartTime_ms(START_TIME);
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
@@ -63,7 +63,6 @@ public class ChartFragmentTest {
|
||||
boolean chartByDistance = false;
|
||||
chartFragment = (ChartFragment) ChartFragment.newInstance(chartByDistance);
|
||||
chartFragment.setChartView(new ChartView(ApplicationProvider.getApplicationContext(), chartByDistance));
|
||||
chartFragment.setTrackStatisticsUpdater(TrackStubUtils.INITIAL_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-3
@@ -65,7 +65,7 @@ public class LegacyKmlImportTest {
|
||||
|
||||
// 3. trackpoints
|
||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
||||
assertEquals(8, importedTrackPoints.size()); // 6 trackpoints + pause and resume
|
||||
assertEquals(8, importedTrackPoints.size()); // 6 trackpoints + segmentEnd and segmentStart
|
||||
|
||||
// first 3 trackpoints
|
||||
assertTrackpoint(importedTrackPoints.get(0), "2020-11-28T17:06:22.401Z", 1.234156, 12.340097, 469.286376953125);
|
||||
@@ -73,9 +73,12 @@ public class LegacyKmlImportTest {
|
||||
assertTrackpoint(importedTrackPoints.get(2), "2020-11-28T17:06:47.888Z", 1.23405, 12.340057, 421.8070983886719);
|
||||
|
||||
// created pause trackpoint with time of previous valid trackpoint
|
||||
assertTrackpoint(importedTrackPoints.get(3), "2020-11-28T17:06:47.888Z", 0.0, 100, 0.0);
|
||||
assertTrackpoint(importedTrackPoints.get(3), "2020-11-28T17:06:47.888Z", 0.0, 0.0, 0.0);
|
||||
assertEquals(1, importedTrackPoints.get(3).getType().type_db);
|
||||
|
||||
// created resume trackpoint with time of next valid trackpoint
|
||||
assertTrackpoint(importedTrackPoints.get(4), "2020-11-28T17:06:55.861Z", 0.0, 200, 0.0);
|
||||
assertTrackpoint(importedTrackPoints.get(4), "2020-11-28T17:06:55.861Z", 0.0, 0.0, 0.0);
|
||||
assertEquals(-2, importedTrackPoints.get(4).getType().type_db);
|
||||
|
||||
// last 3 trackpoints
|
||||
assertTrackpoint(importedTrackPoints.get(5), "2020-11-28T17:06:55.861Z", 1.23405, 12.340057, 419.93902587890625);
|
||||
|
||||
+15
-18
@@ -47,7 +47,6 @@ import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
@@ -158,7 +157,7 @@ public class TrackRecordingServiceTest {
|
||||
@Test
|
||||
public void testRecording_oldTracks() throws TimeoutException {
|
||||
// given
|
||||
createDummyTrack(trackId, -1L, false);
|
||||
createDummyTrack(trackId, false);
|
||||
|
||||
// when
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
@@ -172,7 +171,7 @@ public class TrackRecordingServiceTest {
|
||||
@Test
|
||||
public void testRecording_serviceRestart_whileRecording() throws TimeoutException {
|
||||
// given
|
||||
createDummyTrack(trackId, -1L, true);
|
||||
createDummyTrack(trackId, true);
|
||||
|
||||
//when
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
@@ -185,9 +184,8 @@ public class TrackRecordingServiceTest {
|
||||
@Test
|
||||
public void testRecording_pauseAndResume() throws TimeoutException, InterruptedException {
|
||||
// given
|
||||
createDummyTrack(trackId, -1L, true);
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
newTrackPoint(service);
|
||||
Track.Id trackId = service.startNewTrack();
|
||||
|
||||
// when
|
||||
service.pauseCurrentTrack();
|
||||
@@ -197,29 +195,28 @@ public class TrackRecordingServiceTest {
|
||||
|
||||
//when
|
||||
service.resumeTrack(trackId);
|
||||
newTrackPoint(service);
|
||||
|
||||
// then
|
||||
assertTrue(service.isRecording());
|
||||
assertEquals(trackId, service.getRecordingTrackId());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(5, trackPoints.size());
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(3).getLatitude(), 0.01);
|
||||
assertEquals(3, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(2).getType());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void testRecording_resumeStoppedTrack() throws TimeoutException, InterruptedException {
|
||||
// given
|
||||
createDummyTrack(trackId, -1L, true);
|
||||
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
|
||||
newTrackPoint(service);
|
||||
Track.Id trackId = service.startNewTrack();
|
||||
assertTrue(service.isRecording());
|
||||
service.endCurrentTrack();
|
||||
|
||||
assertEquals(1, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
||||
|
||||
// when
|
||||
service.resumeTrack(trackId);
|
||||
@@ -231,8 +228,10 @@ public class TrackRecordingServiceTest {
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(4, trackPoints.size());
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(TrackPointsColumns.RESUME_LATITUDE, trackPoints.get(2).getLatitude(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(2).getType());
|
||||
assertEquals(TrackPoint.Type.TRACKPOINT, trackPoints.get(3).getType());
|
||||
}
|
||||
|
||||
@Ignore("Sometimes fails on CI.")
|
||||
@@ -336,12 +335,11 @@ public class TrackRecordingServiceTest {
|
||||
}
|
||||
|
||||
// NOTE: Do not use to create a track that is currently recording.
|
||||
private void createDummyTrack(Track.Id id, long stopTime, boolean isRecording) {
|
||||
private void createDummyTrack(Track.Id id, boolean isRecording) {
|
||||
Track dummyTrack = new Track();
|
||||
dummyTrack.setId(id);
|
||||
dummyTrack.setName("Dummy Track");
|
||||
TrackStatistics trackStatistics = new TrackStatistics();
|
||||
trackStatistics.setStopTime_ms(stopTime);
|
||||
dummyTrack.setTrackStatistics(trackStatistics);
|
||||
addTrack(dummyTrack, isRecording);
|
||||
}
|
||||
@@ -368,7 +366,6 @@ public class TrackRecordingServiceTest {
|
||||
TrackPoint trackPoint = new TrackPoint(location);
|
||||
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(ApplicationProvider.getApplicationContext());
|
||||
trackRecordingService.newTrackPoint(trackPoint, prefAccuracy);
|
||||
|
||||
//TODO Needed?
|
||||
Thread.sleep(200);
|
||||
}
|
||||
|
||||
+43
-35
@@ -24,7 +24,6 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
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.CustomContentProvider;
|
||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
||||
@@ -34,6 +33,7 @@ import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Tests insert location.
|
||||
@@ -69,6 +69,7 @@ public class TrackRecordingServiceTestLocation {
|
||||
customContentProvider.attachInfo(context, null);
|
||||
|
||||
contentProviderUtils = new ContentProviderUtils(context);
|
||||
tearDown();
|
||||
|
||||
// Let's use default values.
|
||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||
@@ -79,11 +80,6 @@ public class TrackRecordingServiceTestLocation {
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// Reset service (if some previous test failed)
|
||||
if (service.isRecording() || service.isPaused()) {
|
||||
service.endCurrentTrack();
|
||||
}
|
||||
|
||||
// Ensure that the database is empty after every test
|
||||
contentProviderUtils.deleteAllTracks(context);
|
||||
}
|
||||
@@ -108,8 +104,10 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(6, trackPoints.size());
|
||||
assertEquals(45.0005, trackPoints.get(5).getLatitude(), 0.01);
|
||||
assertEquals(8, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(45.0005, trackPoints.get(6).getLatitude(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(7).getType());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -117,6 +115,7 @@ public class TrackRecordingServiceTestLocation {
|
||||
public void testOnLocationChangedAsync_slowMovingAccurate() throws Exception {
|
||||
// given
|
||||
Track.Id trackId = service.startNewTrack();
|
||||
assertNotNull(trackId);
|
||||
|
||||
// when
|
||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 15);
|
||||
@@ -132,8 +131,10 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(2, trackPoints.size());
|
||||
assertEquals(45.000005, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(4, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(45.000005, trackPoints.get(2).getLatitude(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(3).getType());
|
||||
}
|
||||
|
||||
// @MediumTest
|
||||
@@ -174,10 +175,12 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(3, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(6, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(6, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(4).getType());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -200,14 +203,15 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(4, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(2).getAccuracy(), 0.01); //TODO Check why this trackPoint is inserted.
|
||||
assertEquals(6, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(6, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(3).getAccuracy(), 0.01); //TODO Check why this trackPoint is inserted.
|
||||
assertEquals(6, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(5).getType());
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
@Test
|
||||
public void testOnLocationChangedAsync_idle_withSensorData() throws Exception {
|
||||
@@ -243,13 +247,15 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(6, trackPoints.size());
|
||||
assertEquals(0, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(4, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
assertEquals(8, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(0, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(1, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(2, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(7).getType());
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
@@ -271,13 +277,15 @@ public class TrackRecordingServiceTestLocation {
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
assertEquals(7, trackPoints.size());
|
||||
assertEquals(1, trackPoints.get(0).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(1).getLatitude(), 0.01);
|
||||
assertEquals(2, trackPoints.get(2).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPointsColumns.PAUSE_LATITUDE, trackPoints.get(4).getLatitude(), 0.01);
|
||||
assertEquals(4, trackPoints.get(5).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(6).getAccuracy(), 0.01);
|
||||
assertEquals(9, trackPoints.size());
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||
assertEquals(1, trackPoints.get(1).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(2).getType());
|
||||
assertEquals(2, trackPoints.get(3).getAccuracy(), 0.01);
|
||||
assertEquals(3, trackPoints.get(4).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(5).getType());
|
||||
assertEquals(4, trackPoints.get(6).getAccuracy(), 0.01);
|
||||
assertEquals(5, trackPoints.get(7).getAccuracy(), 0.01);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(8).getType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class AnnouncementUtilsTest {
|
||||
stats.setTotalTime(600000);
|
||||
stats.setMovingTime(300000);
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setTotalElevationGain(6000);
|
||||
stats.setTotalElevationGain(6000f);
|
||||
|
||||
// when
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", null);
|
||||
@@ -47,7 +47,7 @@ public class AnnouncementUtilsTest {
|
||||
stats.setTotalTime(600000);
|
||||
stats.setMovingTime(300000);
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setTotalElevationGain(6000);
|
||||
stats.setTotalElevationGain(6000f);
|
||||
|
||||
List<TrackPoint> trackPoints = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second;
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, 1000);
|
||||
|
||||
+6
-6
@@ -25,12 +25,12 @@ public class IntervalStatisticsTest {
|
||||
}
|
||||
|
||||
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoints.get(0).getTime());
|
||||
for (TrackPoint tp : trackPoints) {
|
||||
trackStatisticsUpdater.addTrackPoint(tp, 0);
|
||||
}
|
||||
return trackStatisticsUpdater.getTrackStatistics();
|
||||
}
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
for (TrackPoint tp : trackPoints) {
|
||||
trackStatisticsUpdater.addTrackPoint(tp, 0);
|
||||
}
|
||||
return trackStatisticsUpdater.getTrackStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
|
||||
|
||||
@@ -40,13 +40,12 @@ import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
/**
|
||||
* Track data hub.
|
||||
* Receives data from {@link de.dennisguse.opentracks.content.provider.CustomContentProvider} and distributes it to {@link TrackDataListener} after some processing.
|
||||
*
|
||||
* <p>
|
||||
* {@link TrackPoint}s are filtered/downsampled with a dynamic sampling frequency.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
@@ -314,9 +313,6 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
if (!LocationUtils.isValidLocation(marker.getLocation())) {
|
||||
continue;
|
||||
}
|
||||
for (TrackDataListener trackDataListener : trackDataListeners) {
|
||||
trackDataListener.onNewMarker(marker);
|
||||
}
|
||||
@@ -362,7 +358,6 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
|
||||
TrackPoint.Id lastTrackPointId = contentProviderUtils.getLastTrackPointId(selectedTrackId);
|
||||
int samplingFrequency = -1;
|
||||
boolean includeNextPoint = false;
|
||||
|
||||
|
||||
TrackPoint.Id next;
|
||||
@@ -390,19 +385,15 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
||||
samplingFrequency = 1 + (int) (numTotalPoints / targetNumPoints);
|
||||
}
|
||||
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) { //This can be split markers (not anymore supported feature)
|
||||
includeNextPoint = true;
|
||||
|
||||
// Also include the last point if the selected track is not recording.
|
||||
if ((localNumLoadedTrackPoints % samplingFrequency == 0) || (trackPointId == lastTrackPointId && !isSelectedTrackRecording())) {
|
||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||
trackDataListener.onSampledInTrackPoint(trackPoint);
|
||||
}
|
||||
} else {
|
||||
// Also include the last point if the selected track is not recording.
|
||||
if (includeNextPoint || (localNumLoadedTrackPoints % samplingFrequency == 0) || (trackPointId == lastTrackPointId && !isSelectedTrackRecording())) {
|
||||
includeNextPoint = false;
|
||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||
trackDataListener.onSampledInTrackPoint(trackPoint);
|
||||
}
|
||||
} else {
|
||||
for (TrackDataListener trackDataListener : sampledOutListeners) {
|
||||
trackDataListener.onSampledOutTrackPoint(trackPoint);
|
||||
}
|
||||
for (TrackDataListener trackDataListener : sampledOutListeners) {
|
||||
trackDataListener.onSampledOutTrackPoint(trackPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import androidx.annotation.VisibleForTesting;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* NOTE: A marker is indirectly (via it's location) assigned to one {@link TrackPoint} with trackPoint.hasLocation() == true.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,16 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class extends the standard Android location with extra information.
|
||||
* <p>
|
||||
* NOTE: default location will be latitude=0.0 and longitude=0.0 (this is not meaningful).
|
||||
* <p>
|
||||
* NOTE: For Locations provided by the GPS.
|
||||
* We are replacing the GPS-provided time using the system time.
|
||||
* Then we have the same timestamps for the user-driven events (aka start, pause, resume) and restore {@link de.dennisguse.opentracks.stats.TrackStatistics}.
|
||||
* Drawbacks:
|
||||
* * GPS-provided timestamp might be more precise (but also have GPS week rollover)
|
||||
* * System clock might be changed (and thus non-monotonic)
|
||||
* TODO: if these might be problems, we need to store both timestamps.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
@@ -36,6 +46,41 @@ public class TrackPoint {
|
||||
|
||||
private final Location location;
|
||||
|
||||
//TODO Private
|
||||
public enum Type {
|
||||
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume); no useful coordinates
|
||||
|
||||
SEGMENT_START_AUTOMATIC(-1), //Start of a segment due to too much distance from previous TrackPoint
|
||||
TRACKPOINT(0), //Normal trackpoint got from GPS
|
||||
|
||||
SEGMENT_END_MANUAL(1); //End of a segment; no useful coordinates
|
||||
|
||||
public final int type_db;
|
||||
|
||||
Type(int type_db) {
|
||||
this.type_db = type_db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + type_db;
|
||||
}
|
||||
|
||||
public static Type getById(int id) {
|
||||
for (Type e : values()) {
|
||||
if (e.type_db == id) return e;
|
||||
}
|
||||
|
||||
throw new RuntimeException("unknown id: " + id);
|
||||
}
|
||||
|
||||
public boolean hasLocation() {
|
||||
return this == SEGMENT_START_AUTOMATIC || this == TRACKPOINT;
|
||||
}
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
|
||||
private Float heartRate_bpm = null;
|
||||
private Float cyclingCadence_rpm = null;
|
||||
private Float power = null;
|
||||
@@ -43,14 +88,26 @@ public class TrackPoint {
|
||||
private Float elevationLoss = null;
|
||||
|
||||
public TrackPoint() {
|
||||
this(Type.TRACKPOINT, new Location(""));
|
||||
}
|
||||
|
||||
public TrackPoint(Type type) {
|
||||
this.type = type;
|
||||
this.location = new Location("");
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull Location location) {
|
||||
this.type = Type.TRACKPOINT;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull Type type, @NonNull Location location) {
|
||||
this.type = type;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull TrackPoint trackPoint) {
|
||||
this.type = trackPoint.getType();
|
||||
this.location = trackPoint.getLocation();
|
||||
|
||||
this.heartRate_bpm = trackPoint.getHeartRate_bpm();
|
||||
@@ -62,6 +119,7 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public TrackPoint(double latitude, double longitude, Double altitude, long time) {
|
||||
this.type = Type.TRACKPOINT;
|
||||
location = new Location(LocationManager.GPS_PROVIDER);
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
@@ -72,31 +130,52 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createPause() {
|
||||
return createPauseWithTime(System.currentTimeMillis());
|
||||
public static TrackPoint createSegmentStartManual() {
|
||||
return createSegmentStartManualWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createPauseWithTime(long time) {
|
||||
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
||||
pause.setLongitude(0);
|
||||
pause.setLatitude(TrackPointsColumns.PAUSE_LATITUDE);
|
||||
pause.setTime(time);
|
||||
return new TrackPoint(pause);
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createResume() {
|
||||
return createResumeWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createResumeWithTime(long time) {
|
||||
public static TrackPoint createSegmentStartManualWithTime(long time) {
|
||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||
resume.setLongitude(0);
|
||||
resume.setLatitude(TrackPointsColumns.RESUME_LATITUDE);
|
||||
resume.setTime(time);
|
||||
return new TrackPoint(resume);
|
||||
return new TrackPoint(Type.SEGMENT_START_MANUAL, resume);
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
public static TrackPoint createSegmentStartAutomatic() {
|
||||
return createSegmentStartAutomaticWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentStartAutomaticWithTime(long time) {
|
||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||
resume.setTime(time);
|
||||
return new TrackPoint(Type.SEGMENT_START_AUTOMATIC, resume);
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentEnd() {
|
||||
return createSegmentEndWithTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentEndWithTime(@NonNull TrackPoint trackPoint) {
|
||||
return createSegmentEndWithTime(trackPoint.getTime());
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentEndWithTime(long time) {
|
||||
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
||||
pause.setTime(time);
|
||||
return new TrackPoint(Type.SEGMENT_END_MANUAL, pause);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isSegmentStart() {
|
||||
return type == Type.SEGMENT_START_AUTOMATIC || type == Type.SEGMENT_START_MANUAL;
|
||||
}
|
||||
|
||||
public boolean isSegmentEnd() {
|
||||
return type == Type.SEGMENT_END_MANUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +347,7 @@ public class TrackPoint {
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "time=" + getTime() + ": lat=" + getLatitude() + " lng=" + getLongitude() + " acc=" + getAccuracy();
|
||||
return "time=" + getTime() + " (type=" + getType() + "): lat=" + getLatitude() + " lng=" + getLongitude() + " acc=" + getAccuracy();
|
||||
}
|
||||
|
||||
public static class Id {
|
||||
|
||||
@@ -37,13 +37,11 @@ public interface TrackPointsColumns extends BaseColumns {
|
||||
|
||||
// Columns
|
||||
String TRACKID = "trackid";
|
||||
// See {@link TrackPoint.Type}
|
||||
String TYPE = "type";
|
||||
|
||||
String LONGITUDE = "longitude";
|
||||
String LATITUDE = "latitude";
|
||||
@Deprecated
|
||||
double PAUSE_LATITUDE = 100.0;
|
||||
@Deprecated
|
||||
double RESUME_LATITUDE = 200.0;
|
||||
|
||||
String TIME = "time";
|
||||
String ALTITUDE = "elevation";
|
||||
@@ -71,6 +69,7 @@ public interface TrackPointsColumns extends BaseColumns {
|
||||
+ SENSOR_POWER + " FLOAT, "
|
||||
+ ELEVATION_GAIN + " FLOAT, "
|
||||
+ ELEVATION_LOSS + " FLOAT, "
|
||||
+ TYPE + " TEXT CHECK(type IN (-2, -1, 0, 1)), "
|
||||
+ "FOREIGN KEY (" + TRACKID + ") REFERENCES " + TracksColumns.TABLE_NAME + "(" + TracksColumns._ID + ") ON UPDATE CASCADE ON DELETE CASCADE"
|
||||
+ ")";
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
*/
|
||||
class CachedTrackPointsIndexes {
|
||||
final int idIndex;
|
||||
final int typeIndex;
|
||||
final int longitudeIndex;
|
||||
final int latitudeIndex;
|
||||
final int timeIndex;
|
||||
@@ -24,6 +25,7 @@ class CachedTrackPointsIndexes {
|
||||
|
||||
CachedTrackPointsIndexes(Cursor cursor) {
|
||||
idIndex = cursor.getColumnIndex(TrackPointsColumns._ID);
|
||||
typeIndex = cursor.getColumnIndex(TrackPointsColumns.TYPE);
|
||||
longitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE);
|
||||
latitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE);
|
||||
timeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.TIME);
|
||||
|
||||
@@ -63,8 +63,6 @@ public class ContentProviderUtils {
|
||||
// The base URI for the app's content provider.
|
||||
public static final String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE;
|
||||
|
||||
// Maximum number of markers that will be loaded at one time.
|
||||
public static final int MAX_LOADED_MARKERS = 10000;
|
||||
private static final String ID_SEPARATOR = ",";
|
||||
|
||||
private final ContentResolver contentResolver;
|
||||
@@ -544,7 +542,7 @@ public class ContentProviderUtils {
|
||||
* @param indexes the cached trackPoints indexes
|
||||
*/
|
||||
static TrackPoint fillTrackPoint(Cursor cursor, CachedTrackPointsIndexes indexes) {
|
||||
TrackPoint trackPoint = new TrackPoint();
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.getById(cursor.getInt(indexes.typeIndex)));
|
||||
if (!cursor.isNull(indexes.longitudeIndex)) {
|
||||
trackPoint.setId(new TrackPoint.Id(cursor.getInt(indexes.idIndex)));
|
||||
}
|
||||
@@ -696,7 +694,7 @@ public class ContentProviderUtils {
|
||||
*/
|
||||
@Deprecated
|
||||
public TrackPoint getLastValidTrackPoint(Track.Id trackId) {
|
||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.LATITUDE + "<=" + MAX_LATITUDE + ")";
|
||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.TYPE + " IN (" + TrackPoint.Type.SEGMENT_START_AUTOMATIC + "," + TrackPoint.Type.TRACKPOINT + "))";
|
||||
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
return findTrackPointBy(selection, selectionArgs);
|
||||
}
|
||||
@@ -715,12 +713,15 @@ public class ContentProviderUtils {
|
||||
/**
|
||||
* Creates the {@link ContentValues} for a {@link TrackPoint}.
|
||||
*
|
||||
* @param trackPoint the trackPointstats_pace_km#87
|
||||
* @param trackPoint the trackPoint
|
||||
* @param trackId the track id
|
||||
*/
|
||||
private ContentValues createContentValues(TrackPoint trackPoint, Track.Id trackId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(TrackPointsColumns.TRACKID, trackId.getId());
|
||||
if (trackPoint.getType() != null) {
|
||||
values.put(TrackPointsColumns.TYPE, trackPoint.getType().type_db);
|
||||
}
|
||||
values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getLongitude() * 1E6));
|
||||
values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getLatitude() * 1E6));
|
||||
|
||||
|
||||
@@ -329,10 +329,8 @@ public class CustomContentProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
private Uri insertTrackPoint(Uri url, ContentValues values) {
|
||||
boolean hasLatitude = values.containsKey(TrackPointsColumns.LATITUDE);
|
||||
boolean hasLongitude = values.containsKey(TrackPointsColumns.LONGITUDE);
|
||||
boolean hasTime = values.containsKey(TrackPointsColumns.TIME);
|
||||
if (!hasLatitude || !hasLongitude || !hasTime) {
|
||||
if (!hasTime) {
|
||||
throw new IllegalArgumentException("Latitude, longitude, and time values are required.");
|
||||
}
|
||||
long rowId = db.insert(TrackPointsColumns.TABLE_NAME, TrackPointsColumns._ID, values);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
||||
|
||||
private static final int DATABASE_VERSION = 29;
|
||||
private static final int DATABASE_VERSION = 30;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final String DATABASE_NAME = "database.db";
|
||||
|
||||
@@ -43,7 +43,6 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.databinding.ChartBinding;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
/**
|
||||
@@ -71,8 +70,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
private TrackDataHub trackDataHub;
|
||||
|
||||
// Stats gathered from the received data
|
||||
private TrackStatisticsUpdater trackStatisticsUpdater;
|
||||
private long startTime;
|
||||
private TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
|
||||
private ChartBinding viewBinding;
|
||||
|
||||
@@ -198,7 +196,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
public void onTrackUpdated(Track track) {
|
||||
if (isResumed()) {
|
||||
if (track == null || track.getTrackStatistics() == null) {
|
||||
startTime = -1L;
|
||||
category = "";
|
||||
return;
|
||||
}
|
||||
@@ -209,14 +206,13 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
chartView.setReportSpeed(reportSpeed);
|
||||
chartView.applyReportSpeed();
|
||||
}
|
||||
startTime = track.getTrackStatistics().getStartTime_ms();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
if (isResumed()) {
|
||||
trackStatisticsUpdater = startTime != -1L ? new TrackStatisticsUpdater(startTime) : null;
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
pendingPoints.clear();
|
||||
chartView.reset();
|
||||
runOnUiThread(() -> {
|
||||
@@ -261,7 +257,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
|
||||
@Override
|
||||
public void onNewMarker(Marker marker) {
|
||||
if (isResumed() && marker != null && LocationUtils.isValidLocation(marker.getLocation())) {
|
||||
if (isResumed() && marker != null) {
|
||||
chartView.addMarker(marker);
|
||||
}
|
||||
}
|
||||
@@ -327,11 +323,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
return new ChartPoint(trackStatisticsUpdater, trackPoint, chartByDistance, chartView.getMetricUnits());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setTrackStatisticsUpdater(long time) {
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater(time);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setChartView(ChartView view) {
|
||||
chartView = view;
|
||||
|
||||
@@ -191,8 +191,8 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
||||
}
|
||||
|
||||
TrackPoint trackPoint = lastTrackPoint; //NOTE: There seems to be a race condition; just fix the symptom for now.
|
||||
if (trackPoint != null) {
|
||||
boolean hasFix = !LocationUtils.isLocationOld(trackPoint.getLocation());
|
||||
if (trackPoint != null && trackPoint.getType().hasLocation()) {
|
||||
boolean hasFix = !LocationUtils.isTrackPointOld(trackPoint);
|
||||
|
||||
if (!hasFix) {
|
||||
lastTrackPoint = null;
|
||||
|
||||
@@ -28,7 +28,6 @@ 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.util.LocationUtils;
|
||||
|
||||
/**
|
||||
* Track Writer for writing tracks to an {@link OutputStream}.
|
||||
@@ -95,7 +94,7 @@ public class FileTrackExporter implements TrackExporter {
|
||||
* I am leaving the number of markers very high which should not be a problem, because we don't try to load them into objects all at the same time.
|
||||
*/
|
||||
boolean hasMarkers = false;
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, ContentProviderUtils.MAX_LOADED_MARKERS)) {
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
if (Thread.interrupted()) {
|
||||
@@ -136,7 +135,7 @@ public class FileTrackExporter implements TrackExporter {
|
||||
|
||||
setLocationTime(trackPoint, offset);
|
||||
|
||||
boolean isLocationValid = LocationUtils.isValidLocation(trackPoint.getLocation());
|
||||
boolean isLocationValid = trackPoint.getType().hasLocation();
|
||||
boolean isSegmentValid = isLocationValid && isLastLocationValid;
|
||||
if (!wroteTrack && isSegmentValid) {
|
||||
// Found the first two consecutive locations that are valid
|
||||
|
||||
+12
-22
@@ -156,9 +156,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
int markerPosition = -1;
|
||||
Marker marker = null;
|
||||
TrackPoint trackPoint = null;
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
||||
// TODO Should not be necessary anymore?
|
||||
TrackStatisticsUpdater markerTrackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
|
||||
@@ -183,7 +181,6 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
}
|
||||
trackPoint = trackPointIterator.next();
|
||||
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
markerTrackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
}
|
||||
|
||||
if (marker.getLocation().getTime() > trackPoint.getTime()) {
|
||||
@@ -193,7 +190,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
marker = null;
|
||||
} else {
|
||||
// The marker trackPoint time matches the track point time
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
if (!trackPoint.getType().hasLocation()) {
|
||||
// Invalid trackPoint, load the next trackPoint
|
||||
trackPoint = null;
|
||||
continue;
|
||||
@@ -253,8 +250,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
trackData.track.setIcon(icon);
|
||||
}
|
||||
if (trackData.trackStatisticsUpdater == null) {
|
||||
trackData.trackStatisticsUpdater = new TrackStatisticsUpdater(trackData.importTime);
|
||||
trackData.trackStatisticsUpdater.updateTime(trackData.importTime);
|
||||
trackData.trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
}
|
||||
trackData.track.setTrackStatistics(trackData.trackStatisticsUpdater.getTrackStatistics());
|
||||
|
||||
@@ -289,7 +285,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
|
||||
//If not the first segment, add a pause separator if there is at least one location in the last segment.
|
||||
if (trackData.numberOfSegments > 1 && trackData.lastLocationInCurrentSegment != null) {
|
||||
insertLocation(TrackPoint.createPauseWithTime(trackData.lastLocationInCurrentSegment.getTime()));
|
||||
insertLocation(TrackPoint.createSegmentEndWithTime(trackData.lastLocationInCurrentSegment.getTime()));
|
||||
}
|
||||
trackData.lastLocationInCurrentSegment = null;
|
||||
}
|
||||
@@ -302,7 +298,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
|
||||
TrackPoint trackPoint = createTrackPoint();
|
||||
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
if (!trackPoint.getType().hasLocation()) {
|
||||
Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.getLocation());
|
||||
return;
|
||||
}
|
||||
@@ -361,7 +357,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
|
||||
if (trackData.numberOfSegments > 1 && trackData.lastLocationInCurrentSegment == null) {
|
||||
// If not the first segment, add a resume separator before adding the first location.
|
||||
insertLocation(TrackPoint.createResumeWithTime(trackPoint.getTime()));
|
||||
insertLocation(TrackPoint.createSegmentStartManualWithTime(trackPoint.getTime()));
|
||||
}
|
||||
trackData.lastLocationInCurrentSegment = trackPoint;
|
||||
return trackPoint;
|
||||
@@ -428,14 +424,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
throw new SAXException(createErrorMessage(String.format(Locale.US, "Unable to parse latitude longitude: %s %s", latitude, longitude)), e);
|
||||
}
|
||||
|
||||
if (time == null) {
|
||||
trackPoint.setTime(trackData.importTime);
|
||||
} else {
|
||||
try {
|
||||
trackPoint.setTime(StringUtils.parseTime(time));
|
||||
} catch (Exception e) {
|
||||
throw new SAXException(createErrorMessage(String.format(Locale.US, "Unable to parse time: %s", time)), e);
|
||||
}
|
||||
try {
|
||||
trackPoint.setTime(StringUtils.parseTime(time));
|
||||
} catch (Exception e) {
|
||||
throw new SAXException(createErrorMessage(String.format(Locale.US, "Unable to parse time: %s", time)), e);
|
||||
}
|
||||
|
||||
if (altitude != null) {
|
||||
@@ -494,8 +486,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
*/
|
||||
private void insertLocation(TrackPoint trackPoint) {
|
||||
if (trackData.trackStatisticsUpdater == null) {
|
||||
trackData.trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoint.getTime() != -1L ? trackPoint.getTime() : trackData.importTime);
|
||||
trackData.trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
}
|
||||
//TODO I guess, we should not filter by recordingDistanceInterval on import; the data is already recorded, so we should not change it.
|
||||
trackData.trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
|
||||
trackData.bufferedTrackPoints.add(trackPoint);
|
||||
@@ -545,9 +538,6 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
// The TrackStatisticsUpdater for the current track
|
||||
TrackStatisticsUpdater trackStatisticsUpdater;
|
||||
|
||||
// The import time of the track.
|
||||
final long importTime = System.currentTimeMillis();
|
||||
|
||||
// The buffered locations
|
||||
final List<TrackPoint> bufferedTrackPoints = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.SystemUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
@@ -283,8 +282,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
Log.d(TAG, "Ignore startNewTrack. Already recording.");
|
||||
return null;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater(now);
|
||||
|
||||
// Insert a track
|
||||
Track track = new Track();
|
||||
@@ -296,7 +293,13 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
|
||||
// Update database
|
||||
track.setId(trackId);
|
||||
track.setName(TrackNameUtils.getTrackName(this, trackId, now));
|
||||
|
||||
TrackPoint segmentStartTrackPoint = TrackPoint.createSegmentStartManual();
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
insertTrackPoint(track, segmentStartTrackPoint);
|
||||
|
||||
//TODO Pass TrackPoint
|
||||
track.setName(TrackNameUtils.getTrackName(this, trackId, segmentStartTrackPoint.getTime()));
|
||||
|
||||
String category = PreferencesUtils.getDefaultActivity(this);
|
||||
track.setCategory(category);
|
||||
@@ -325,8 +328,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
track.getTrackStatistics().setStopTime_ms(System.currentTimeMillis());
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics());
|
||||
|
||||
insertTrackPoint(track, TrackPoint.createPause());
|
||||
insertTrackPoint(track, TrackPoint.createResume());
|
||||
insertTrackPoint(track, TrackPoint.createSegmentStartManual());
|
||||
|
||||
// Update shared preferences.
|
||||
updateRecordingState(trackId, false);
|
||||
@@ -350,7 +352,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
|
||||
Log.d(TAG, "Restarting track: " + track.getId());
|
||||
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics().getStartTime_ms());
|
||||
trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
trackStatisticsUpdater.addTrackPoint(trackPointIterator, recordingDistanceInterval);
|
||||
@@ -371,7 +373,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
// Update database
|
||||
Track track = contentProviderUtils.getTrack(recordingTrackId);
|
||||
if (track != null) {
|
||||
insertTrackPoint(track, TrackPoint.createResume());
|
||||
insertTrackPoint(track, TrackPoint.createSegmentStartManual());
|
||||
}
|
||||
|
||||
startRecording();
|
||||
@@ -424,15 +426,14 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
// Update database
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
if (track != null) {
|
||||
// If not wasPaused, add the last location
|
||||
if (!wasPaused) {
|
||||
if (lastTrackPoint != null) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
}
|
||||
|
||||
// Update the recording track time
|
||||
updateTrackTotalTime(track);
|
||||
if (lastTrackPoint != null) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
}
|
||||
|
||||
insertTrackPoint(track, TrackPoint.createSegmentEnd());
|
||||
|
||||
// Update the recording track time
|
||||
updateTrackTotalTime(track);
|
||||
}
|
||||
|
||||
ExportUtils.postWorkoutExport(this, track, new ExportServiceResultReceiver(new Handler(), this));
|
||||
@@ -454,7 +455,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
if (lastTrackPoint != null) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
}
|
||||
insertTrackPoint(track, TrackPoint.createPause());
|
||||
insertTrackPoint(track, TrackPoint.createSegmentEnd());
|
||||
}
|
||||
|
||||
endRecording(false);
|
||||
@@ -567,18 +568,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastValidTrackPoint == null || !LocationUtils.isValidLocation(lastValidTrackPoint.getLocation())) {
|
||||
// For some reason the previous first trackPoint was not stored, but currentSegmentHasLocation set true.
|
||||
// Should not happen. The current segment should have a location. Just insert the current location.
|
||||
insertTrackPoint(track, trackPoint);
|
||||
lastTrackPoint = trackPoint;
|
||||
return;
|
||||
}
|
||||
|
||||
double distanceToLastTrackLocation = trackPoint.distanceTo(lastValidTrackPoint);
|
||||
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||
insertTrackPoint(track, TrackPoint.createPause());
|
||||
insertTrackPoint(track, TrackPoint.createSegmentEndWithTime(trackPoint));
|
||||
|
||||
insertTrackPoint(track, trackPoint);
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ public interface TrackRecordingServiceInterface {
|
||||
* @param trackPoint the track point object to be inserted.
|
||||
* @param recordingGpsAccuracy recording GPS accuracy.
|
||||
*/
|
||||
@Deprecated //REMOVE
|
||||
@VisibleForTesting
|
||||
void newTrackPoint(TrackPoint trackPoint, int recordingGpsAccuracy);
|
||||
|
||||
|
||||
@@ -26,15 +26,16 @@ import androidx.annotation.Nullable;
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
//TODO Use null instead of Double.isInfinite
|
||||
//TODO Check that data ranges are valid (not less than zero etc.)
|
||||
public class TrackStatistics {
|
||||
|
||||
// The min and max elevation (meters) seen on this track.
|
||||
private final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
||||
|
||||
// The track start time. This is the system time, might not match the GPs time.
|
||||
private long startTime_ms = -1L;
|
||||
// The track stop time. This is the system time, might not match the GPS time.
|
||||
private long stopTime_ms = -1L;
|
||||
// The track start time.
|
||||
private long startTime_ms;
|
||||
// The track stop time.
|
||||
private long stopTime_ms;
|
||||
|
||||
private double totalDistance_m;
|
||||
// Updated when new points are received, may be stale.
|
||||
@@ -44,11 +45,13 @@ public class TrackStatistics {
|
||||
// The maximum speed (meters/second) that we believe is valid.
|
||||
private double maxSpeed_mps;
|
||||
// The total elevation gained (meters).
|
||||
private Float totalElevationGain_m = null;
|
||||
@Nullable
|
||||
private Float totalElevationGain_m;
|
||||
// The total elevation lost (meters).
|
||||
private Float totalElevationLoss_m = null;
|
||||
|
||||
public TrackStatistics() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,6 +108,21 @@ public class TrackStatistics {
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
setStartTime_ms(0);
|
||||
|
||||
setTotalDistance(0);
|
||||
setTotalTime(0);
|
||||
setMovingTime(0);
|
||||
setMaxSpeed(0);
|
||||
setTotalElevationGain(null);
|
||||
}
|
||||
|
||||
public void reset(long startTime_ms) {
|
||||
reset();
|
||||
setStartTime_ms(startTime_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the track start time. The number of milliseconds since epoch.
|
||||
*/
|
||||
@@ -112,8 +130,12 @@ public class TrackStatistics {
|
||||
return startTime_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called on start.
|
||||
*/
|
||||
public void setStartTime_ms(long startTime_ms) {
|
||||
this.startTime_ms = startTime_ms;
|
||||
setStopTime_ms(startTime_ms);
|
||||
}
|
||||
|
||||
public long getStopTime_ms() {
|
||||
@@ -121,6 +143,9 @@ public class TrackStatistics {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
this.stopTime_ms = stopTime_ms;
|
||||
}
|
||||
|
||||
@@ -258,7 +283,7 @@ public class TrackStatistics {
|
||||
return totalElevationGain_m;
|
||||
}
|
||||
|
||||
public void setTotalElevationGain(float totalElevationGain_m) {
|
||||
public void setTotalElevationGain(Float totalElevationGain_m) {
|
||||
this.totalElevationGain_m = totalElevationGain_m;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.TrackPointUtils;
|
||||
|
||||
/**
|
||||
@@ -58,6 +56,9 @@ public class TrackStatisticsUpdater {
|
||||
*/
|
||||
private static final double MAX_ACCELERATION = 0.02;
|
||||
|
||||
private boolean trackInitialized = false;
|
||||
private boolean segmentInitialized = false;
|
||||
|
||||
// The track's statistics
|
||||
private final TrackStatistics trackStatistics;
|
||||
|
||||
@@ -67,20 +68,14 @@ public class TrackStatisticsUpdater {
|
||||
private final DoubleRingBuffer speedBuffer_ms = new DoubleRingBuffer(SPEED_SMOOTHING_FACTOR);
|
||||
|
||||
// The current segment's statistics
|
||||
private TrackStatistics currentSegment;
|
||||
private final TrackStatistics currentSegment = new TrackStatistics();
|
||||
// Current segment's last trackPoint
|
||||
private TrackPoint lastTrackPoint;
|
||||
// Current segment's last moving trackPoint
|
||||
private TrackPoint lastMovingTrackPoint;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TrackStatisticsUpdater}.
|
||||
*
|
||||
* @param startTime_ms the start time in milliseconds
|
||||
*/
|
||||
public TrackStatisticsUpdater(long startTime_ms) {
|
||||
trackStatistics = init(startTime_ms);
|
||||
currentSegment = init(startTime_ms);
|
||||
public TrackStatisticsUpdater() {
|
||||
trackStatistics = new TrackStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,17 +85,14 @@ public class TrackStatisticsUpdater {
|
||||
*/
|
||||
public TrackStatisticsUpdater(TrackStatistics trackStatistics) {
|
||||
this.trackStatistics = trackStatistics;
|
||||
currentSegment = init(System.currentTimeMillis());
|
||||
trackInitialized = true;
|
||||
}
|
||||
|
||||
public void updateTime(long time) {
|
||||
currentSegment.setStopTime_ms(time);
|
||||
currentSegment.setTotalTime(time - currentSegment.getStartTime_ms());
|
||||
public void updateTime(long time_ms) {
|
||||
currentSegment.setStopTime_ms(time_ms);
|
||||
currentSegment.setTotalTime(time_ms - currentSegment.getStartTime_ms());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the track's statistics.
|
||||
*/
|
||||
public TrackStatistics getTrackStatistics() {
|
||||
// Take a snapshot - we don't want anyone messing with our trackStatistics
|
||||
TrackStatistics stats = new TrackStatistics(trackStatistics);
|
||||
@@ -110,23 +102,30 @@ public class TrackStatisticsUpdater {
|
||||
|
||||
/**
|
||||
* Adds a trackPoint.
|
||||
* TODO: This assume trackPoint has a valid time.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
* @param minRecordingDistance the min recording distance
|
||||
*/
|
||||
public void addTrackPoint(TrackPoint trackPoint, int minRecordingDistance) {
|
||||
if (!trackInitialized) {
|
||||
trackStatistics.setStartTime_ms(trackPoint.getTime());
|
||||
trackInitialized = true;
|
||||
}
|
||||
if (!segmentInitialized) {
|
||||
currentSegment.setStartTime_ms(trackPoint.getTime());
|
||||
segmentInitialized = true;
|
||||
}
|
||||
|
||||
// Always update time
|
||||
updateTime(trackPoint.getTime());
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
// Either pause or resume marker
|
||||
if (trackPoint.getLatitude() == TrackPointsColumns.PAUSE_LATITUDE) {
|
||||
if (trackPoint.isSegmentStart() || trackPoint.isSegmentEnd()) {
|
||||
if (trackPoint.isSegmentEnd()) {
|
||||
if (lastTrackPoint != null && lastMovingTrackPoint != null && lastTrackPoint != lastMovingTrackPoint) {
|
||||
currentSegment.addTotalDistance(lastMovingTrackPoint.distanceTo(lastTrackPoint));
|
||||
}
|
||||
trackStatistics.merge(currentSegment);
|
||||
}
|
||||
currentSegment = init(trackPoint.getTime());
|
||||
currentSegment.reset(trackPoint.getTime());
|
||||
lastTrackPoint = null;
|
||||
lastMovingTrackPoint = null;
|
||||
elevationBuffer_m.reset();
|
||||
@@ -238,13 +237,6 @@ public class TrackStatisticsUpdater {
|
||||
return newAverage - oldAverage;
|
||||
}
|
||||
|
||||
private TrackStatistics init(long time) {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setStartTime_ms(time);
|
||||
stats.setStopTime_ms(time);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the speed is valid.
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,8 @@ package de.dennisguse.opentracks.util;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
|
||||
/**
|
||||
* Utility class for decimating tracks at a given level of precision.
|
||||
*
|
||||
@@ -34,26 +36,18 @@ public class LocationUtils {
|
||||
|
||||
/**
|
||||
* Checks if a given location is a valid (i.e. physically possible) location on Earth.
|
||||
* Note: The special separator locations (which have latitude = 100) will not qualify as valid.
|
||||
* Neither will locations with lat=0 and lng=0 as these are most likely "bad" measurements which often cause trouble.
|
||||
*
|
||||
* @param location the location to test
|
||||
* @return true if the location is a valid location.
|
||||
*/
|
||||
//TODO Move to TrackPoint
|
||||
@Deprecated //See #316
|
||||
public static boolean isValidLocation(Location location) {
|
||||
return location != null
|
||||
&& Math.abs(location.getLatitude()) <= 90
|
||||
&& Math.abs(location.getLongitude()) <= 180;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a location is old.
|
||||
*
|
||||
* @param location the location
|
||||
*/
|
||||
public static boolean isLocationOld(Location location) {
|
||||
return !LocationUtils.isValidLocation(location) || (System.currentTimeMillis() - location.getTime() > MAX_LOCATION_AGE_MS);
|
||||
public static boolean isTrackPointOld(TrackPoint trackPoint) {
|
||||
return System.currentTimeMillis() - trackPoint.getTime() > MAX_LOCATION_AGE_MS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package de.dennisguse.opentracks.viewmodels;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.util.LocationUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
|
||||
public class IntervalStatistics {
|
||||
@@ -15,11 +16,11 @@ public class IntervalStatistics {
|
||||
* @param trackPoints the list of TrackPoint.
|
||||
* @param distanceInterval_m the meters of every interval.
|
||||
*/
|
||||
public IntervalStatistics(List<TrackPoint> trackPoints, float distanceInterval_m) {
|
||||
public IntervalStatistics(@NonNull List<TrackPoint> trackPoints, float distanceInterval_m) {
|
||||
intervalList.clear();
|
||||
this.distanceInterval_m = distanceInterval_m;
|
||||
|
||||
if (trackPoints == null || trackPoints.size() == 0) {
|
||||
if (trackPoints.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,7 +31,7 @@ public class IntervalStatistics {
|
||||
TrackPoint prevTrackPoint = trackPoints.get(i - 1);
|
||||
TrackPoint trackPoint = trackPoints.get(i);
|
||||
|
||||
if (LocationUtils.isValidLocation(trackPoint.getLocation()) && LocationUtils.isValidLocation(prevTrackPoint.getLocation())) {
|
||||
if (trackPoint.getType().hasLocation() && prevTrackPoint.getType().hasLocation()) {
|
||||
interval.distance_m += prevTrackPoint.distanceTo(trackPoint);
|
||||
interval.time_ms += trackPoint.getTime() - prevTrackPoint.getTime();
|
||||
interval.gain_m += trackPoint.hasElevationGain() ? trackPoint.getElevationGain() : 0;
|
||||
|
||||
Reference in New Issue
Block a user