forked from upstream-mirrors/OpenTracks
Segments: import/export is working incl. restoring TrackStatistics.
KML exports sensor data if actually present. #316.
This commit is contained in:
@@ -38,6 +38,7 @@ public class TestDataUtil {
|
||||
* @param trackId the trackId of the track
|
||||
* @param numPoints the trackPoints number in the track
|
||||
*/
|
||||
@Deprecated //TODO Should start with SEGMENT_START_MANUAL and end with SEGMENT_END_MANUAL.
|
||||
public static Pair<Track, List<TrackPoint>> createTrack(Track.Id trackId, int numPoints) {
|
||||
Track track = createTrack(trackId);
|
||||
|
||||
@@ -49,6 +50,51 @@ public class TestDataUtil {
|
||||
return new Pair<>(track, trackPoints);
|
||||
}
|
||||
|
||||
|
||||
public static TrackData createTestingTrack(Track.Id trackId) {
|
||||
Track track = createTrack(trackId);
|
||||
|
||||
int i = 0;
|
||||
List<TrackPoint> trackPoints = List.of(
|
||||
TrackPoint.createSegmentStartManualWithTime(i++ + 1),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++, TrackPoint.Type.SEGMENT_START_AUTOMATIC),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
TrackPoint.createSegmentEndWithTime(i++ + 1),
|
||||
|
||||
TrackPoint.createSegmentStartManualWithTime(i++),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
createTrackPoint(i++),
|
||||
TrackPoint.createSegmentEndWithTime(i++ + 1)
|
||||
);
|
||||
|
||||
List<Marker> markers = List.of(
|
||||
new Marker("Marker 1", "Marker description 1", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(1).getLocation(), null),
|
||||
new Marker("Marker 2", "Marker description 2", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(4).getLocation(), null),
|
||||
new Marker("Marker 3", "Marker description 3", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(5).getLocation(), null)
|
||||
);
|
||||
|
||||
return new TrackData(track, trackPoints, markers);
|
||||
}
|
||||
|
||||
public static class TrackData {
|
||||
public final Track track;
|
||||
public final List<TrackPoint> trackPoints;
|
||||
public final List<Marker> markers;
|
||||
|
||||
public TrackData(Track track, List<TrackPoint> trackPoints, List<Marker> markers) {
|
||||
this.track = track;
|
||||
this.trackPoints = trackPoints;
|
||||
this.markers = markers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Track createTrackAndInsert(ContentProviderUtils contentProviderUtils, Track.Id trackId, int numPoints) {
|
||||
Pair<Track, List<TrackPoint>> pair = createTrack(trackId, numPoints);
|
||||
|
||||
@@ -63,7 +109,7 @@ public class TestDataUtil {
|
||||
* @param i the index for the TrackPoint.
|
||||
*/
|
||||
public static TrackPoint createTrackPoint(int i) {
|
||||
TrackPoint trackPoint = new TrackPoint();
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT);
|
||||
trackPoint.setLatitude(INITIAL_LATITUDE + (double) i / 10000.0);
|
||||
trackPoint.setLongitude(INITIAL_LONGITUDE - (double) i / 10000.0);
|
||||
trackPoint.setAccuracy((float) i / 100.0f);
|
||||
@@ -79,6 +125,12 @@ public class TestDataUtil {
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
public static TrackPoint createTrackPoint(int i, TrackPoint.Type type) {
|
||||
TrackPoint trackPoint = createTrackPoint(i);
|
||||
trackPoint.setType(type);
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a track with locations into the database.
|
||||
*
|
||||
|
||||
+2
-2
@@ -270,7 +270,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Track.Id trackId2 = new Track.Id(random + 1);
|
||||
Track.Id trackId3 = new Track.Id(random + 2);
|
||||
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId1, 0);
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId1, 10);
|
||||
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId2, 10);
|
||||
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
|
||||
@@ -282,7 +282,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
||||
assertEquals(3, tracksCursor.getCount());
|
||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
||||
assertEquals(20, tracksPointsCursor.getCount());
|
||||
assertEquals(30, tracksPointsCursor.getCount());
|
||||
Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||
assertEquals(1, markerCursor.getCount());
|
||||
// Delete one track.
|
||||
|
||||
@@ -256,7 +256,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.setSpeed(130);
|
||||
trackPoint2.setSpeed(130f);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
assertEquals(130.0 * UnitConversions.MPS_TO_KMH, point.getSpeed(), 0.01);
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class ChartFragmentTest {
|
||||
* Speed is valid if: speedDifference > Constants.MAX_ACCELERATION * timeDifference speedDifference = 102 -100 timeDifference = 222
|
||||
*/
|
||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||
trackPoint2.setSpeed(102);
|
||||
trackPoint2.setSpeed(102f);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
assertEquals(102.0 * UnitConversions.MPS_TO_KMH * UnitConversions.KM_TO_MI, point.getSpeed(), 0.01);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ public class ChartFragmentTest {
|
||||
* Speed is valid if: speedDifference > Constants.MAX_ACCELERATION * timeDifference speedDifference = 102 -100 timeDifference = 222
|
||||
*/
|
||||
trackPoint2.setTime(trackPoint2.getTime() + 222);
|
||||
trackPoint2.setSpeed(102);
|
||||
trackPoint2.setSpeed(102f);
|
||||
point = chartFragment.createPendingPoint(trackPoint2);
|
||||
assertEquals(HOURS_PER_UNIT / (102.0 * UnitConversions.MPS_TO_KMH), point.getPace(), 0.01);
|
||||
}
|
||||
@@ -318,7 +318,7 @@ public class ChartFragmentTest {
|
||||
public void testCreatePendingPoint_pace_zeroSpeed() {
|
||||
chartFragment.setReportSpeed(false);
|
||||
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint();
|
||||
trackPoint.setSpeed(0);
|
||||
trackPoint.setSpeed(0f);
|
||||
ChartPoint point = chartFragment.createPendingPoint(trackPoint);
|
||||
assertEquals(0.0, point.getPace(), 0.01);
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.time.Instant;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class KmlTrackWriterTest {
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
/**
|
||||
* Sensor data by type should only be created if present in at least on TrackPoint.
|
||||
*/
|
||||
@Test
|
||||
public void writeCloseSegment_only_write_sensordata_if_present() {
|
||||
String expected = "<when>1970-01-01T00:00:00Z</when>\n" +
|
||||
"<gx:coord/>\n" +
|
||||
"<ExtendedData>\n" +
|
||||
"<SchemaData schemaUrl=\"#schema\">\n" +
|
||||
"</SchemaData>\n" +
|
||||
"</ExtendedData>\n" +
|
||||
"</gx:Track>\n";
|
||||
|
||||
// given
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0));
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
KmlTrackWriter kmlTrackWriter = (KmlTrackWriter) TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.newTrackWriter(context);
|
||||
kmlTrackWriter.prepare(outputStream);
|
||||
|
||||
kmlTrackWriter.writeTrackPoint(trackPoint);
|
||||
|
||||
// when
|
||||
kmlTrackWriter.writeCloseSegment();
|
||||
kmlTrackWriter.close();
|
||||
|
||||
// then
|
||||
assertEquals(expected, outputStream.toString());
|
||||
}
|
||||
}
|
||||
+144
-41
@@ -1,15 +1,21 @@
|
||||
package de.dennisguse.opentracks.io.file.importer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -19,15 +25,18 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
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.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
|
||||
@@ -45,6 +54,20 @@ public class ExportImportTest {
|
||||
|
||||
private static final String TAG = ExportImportTest.class.getSimpleName();
|
||||
|
||||
@Rule
|
||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
|
||||
@BeforeClass
|
||||
public static void preSetUp() {
|
||||
// Prepare looper for Android's message queue
|
||||
if (Looper.myLooper() == null) Looper.prepare();
|
||||
}
|
||||
|
||||
private TrackRecordingServiceInterface service;
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
@@ -53,37 +76,44 @@ public class ExportImportTest {
|
||||
private static final String TRACK_CATEGORY = "the category";
|
||||
private static final String TRACK_DESCRIPTION = "the description";
|
||||
|
||||
private final List<Marker> markers = new ArrayList<>();
|
||||
private final List<TrackPoint> trackPoints = new ArrayList<>();
|
||||
private Track track;
|
||||
private List<Marker> markers = new ArrayList<>();
|
||||
private List<TrackPoint> trackPoints = new ArrayList<>();
|
||||
|
||||
private Track.Id trackId;
|
||||
private Track.Id importTrackId;
|
||||
private final Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
|
||||
track.first.setIcon(TRACK_ICON);
|
||||
track.first.setCategory(TRACK_CATEGORY);
|
||||
track.first.setDescription(TRACK_DESCRIPTION);
|
||||
contentProviderUtils.insertTrack(track.first);
|
||||
contentProviderUtils.bulkInsertTrackPoint(track.second, track.first.getId());
|
||||
public void setUp() throws TimeoutException, InterruptedException {
|
||||
service = ((TrackRecordingServiceInterface) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)));
|
||||
|
||||
trackPoints.clear();
|
||||
trackPoints.addAll(track.second);
|
||||
trackId = service.startNewTrack();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Marker marker = new Marker(trackId, track.second.get(i).getLocation());
|
||||
marker.setName("the marker " + i);
|
||||
marker.setDescription("the marker description " + i);
|
||||
marker.setCategory("the marker category" + i);
|
||||
marker.setIcon("the marker icon" + i);
|
||||
marker.setPhotoUrl("the photo url" + i);
|
||||
contentProviderUtils.insertMarker(marker);
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.001, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.002, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
||||
Thread.sleep(10);
|
||||
service.pauseCurrentTrack();
|
||||
|
||||
markers.add(marker);
|
||||
}
|
||||
service.resumeCurrentTrack();
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.003, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16.001, 10, 15, 10, 0, 66, 3, 50), 0);
|
||||
service.endCurrentTrack();
|
||||
|
||||
assertEquals(markers.size(), contentProviderUtils.getMarkerCount(trackId));
|
||||
track = contentProviderUtils.getTrack(trackId);
|
||||
track.setIcon(TRACK_ICON);
|
||||
track.setCategory(TRACK_CATEGORY);
|
||||
track.setDescription(TRACK_DESCRIPTION);
|
||||
contentProviderUtils.updateTrack(track);
|
||||
|
||||
track = contentProviderUtils.getTrack(trackId);
|
||||
trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
||||
markers = contentProviderUtils.getMarkers(trackId);
|
||||
assertEquals(10, trackPoints.size());
|
||||
assertEquals(2, markers.size());
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -94,6 +124,7 @@ public class ExportImportTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Not implemented")
|
||||
@LargeTest
|
||||
@Test
|
||||
public void kml_only_track() {
|
||||
@@ -130,11 +161,14 @@ public class ExportImportTest {
|
||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||
assertEquals(track.getUuid(), importedTrack.getUuid());
|
||||
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
// 2. trackpoints
|
||||
assertTrackpoints(false, false, false, false, false);
|
||||
|
||||
// 3. trackstatistics
|
||||
assertTrackStatistics();
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -165,11 +199,14 @@ public class ExportImportTest {
|
||||
assertEquals(track.getName(), importedTrack.getName());
|
||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
// 2. trackpoints
|
||||
assertTrackpoints(true, true, true, true, true);
|
||||
|
||||
// 2. trackstatistics
|
||||
assertTrackStatistics();
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -258,11 +295,14 @@ public class ExportImportTest {
|
||||
//TODO exporting and importing a track icon is not yet supported by GpxTrackWriter.
|
||||
//assertEquals(track.getIcon(), trackImported.getIcon());
|
||||
|
||||
// 2. markers
|
||||
assertMarkers();
|
||||
|
||||
// 3. trackpoints
|
||||
// 2. trackpoints
|
||||
assertTrackpoints(false, true, true, true, true);
|
||||
|
||||
// 3. trackstatistics
|
||||
assertTrackStatistics();
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@@ -318,14 +358,31 @@ public class ExportImportTest {
|
||||
TrackPoint importedTrackPoint = importedTrackPoints.get(i);
|
||||
|
||||
assertEquals(trackPoint.getTime(), importedTrackPoint.getTime(), 0.01);
|
||||
TrackPoint.Type type = trackPoint.getType();
|
||||
assertEquals("" + i, trackPoint.getType(), importedTrackPoint.getType());
|
||||
|
||||
// TODO Not exported for GPX/KML
|
||||
// assertEquals(trackPoint.getAccuracy(), importedTrackPoint.getAccuracy(), 0.01);
|
||||
|
||||
assertEquals(trackPoint.getLatitude(), importedTrackPoint.getLatitude(), 0.001);
|
||||
assertEquals(trackPoint.getLongitude(), importedTrackPoint.getLongitude(), 0.001);
|
||||
assertEquals(trackPoint.getAltitude(), importedTrackPoint.getAltitude(), 0.001);
|
||||
assertEquals(trackPoint.getSpeed(), importedTrackPoint.getSpeed(), 0.001);
|
||||
assertEquals(trackPoint.hasLocation(), importedTrackPoint.hasLocation());
|
||||
if (trackPoint.hasLocation()) {
|
||||
assertEquals(trackPoint.getLatitude(), importedTrackPoint.getLatitude(), 0.001);
|
||||
assertEquals(trackPoint.getLongitude(), importedTrackPoint.getLongitude(), 0.001);
|
||||
}
|
||||
assertEquals(trackPoint.hasSpeed(), importedTrackPoint.hasSpeed());
|
||||
if (trackPoint.hasSpeed()) {
|
||||
assertEquals(trackPoint.getSpeed(), importedTrackPoint.getSpeed(), 0.001);
|
||||
}
|
||||
assertEquals(trackPoint.hasAltitude(), importedTrackPoint.hasAltitude());
|
||||
if (trackPoint.hasAltitude()) {
|
||||
assertEquals(trackPoint.getAltitude(), importedTrackPoint.getAltitude(), 0.001);
|
||||
}
|
||||
|
||||
if (type.equals(TrackPoint.Type.SEGMENT_START_MANUAL) || type.equals(TrackPoint.Type.SEGMENT_END_MANUAL)) {
|
||||
//TODO REMOVE
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verifyHeartrate) {
|
||||
assertEquals(trackPoint.getHeartRate_bpm(), importedTrackPoint.getHeartRate_bpm(), 0.01);
|
||||
}
|
||||
@@ -343,4 +400,50 @@ public class ExportImportTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTrackStatistics() {
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
|
||||
assertNotNull(importedTrack.getTrackStatistics());
|
||||
|
||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
|
||||
|
||||
// Time
|
||||
assertEquals(trackStatistics.getStartTime_ms(), trackStatistics.getStartTime_ms(), 0.01);
|
||||
assertEquals(trackStatistics.getStopTime_ms(), trackStatistics.getStopTime_ms());
|
||||
assertEquals(trackStatistics.getTotalTime(), trackStatistics.getTotalTime());
|
||||
assertEquals(trackStatistics.getMovingTime(), trackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(trackStatistics.getTotalDistance(), trackStatistics.getTotalDistance(), 0.01);
|
||||
|
||||
// Speed
|
||||
assertEquals(trackStatistics.getMaxSpeed(), trackStatistics.getMaxSpeed(), 0.01);
|
||||
assertEquals(trackStatistics.getAverageSpeed(), trackStatistics.getAverageSpeed(), 0.01);
|
||||
assertEquals(trackStatistics.getAverageMovingSpeed(), trackStatistics.getAverageMovingSpeed(), 0.01);
|
||||
|
||||
// Elevation
|
||||
assertEquals(trackStatistics.getMinElevation(), trackStatistics.getMinElevation(), 0.01);
|
||||
assertEquals(trackStatistics.getMaxElevation(), trackStatistics.getMaxElevation(), 0.01);
|
||||
assertEquals(trackStatistics.getTotalElevationGain(), trackStatistics.getTotalElevationGain(), 0.01);
|
||||
assertEquals(trackStatistics.getTotalElevationLoss(), trackStatistics.getTotalElevationLoss(), 0.01);
|
||||
}
|
||||
|
||||
private static TrackPoint createTrackPoint(long time, double latitude, double longitude, float accuracy, long speed, long altitude, float elevationGain, float heartRate, float cyclingCadence, float power) {
|
||||
Location location = new Location("gps");
|
||||
location.setTime(time);
|
||||
location.setLongitude(longitude);
|
||||
location.setLatitude(latitude);
|
||||
location.setAccuracy(accuracy);
|
||||
location.setAltitude(altitude);
|
||||
location.setSpeed(speed);
|
||||
|
||||
TrackPoint tp = new TrackPoint(location);
|
||||
tp.setHeartRate_bpm(heartRate);
|
||||
tp.setCyclingCadence_rpm(cyclingCadence);
|
||||
tp.setPower(power);
|
||||
tp.setElevationGain(elevationGain);
|
||||
return tp;
|
||||
}
|
||||
}
|
||||
+6
-12
@@ -65,25 +65,19 @@ public class LegacyKmlImportTest {
|
||||
|
||||
// 3. trackpoints
|
||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
||||
assertEquals(8, importedTrackPoints.size()); // 6 trackpoints + segmentEnd and segmentStart
|
||||
assertEquals(6, importedTrackPoints.size());
|
||||
|
||||
// first 3 trackpoints
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_AUTOMATIC, importedTrackPoints.get(0).getType());
|
||||
assertTrackpoint(importedTrackPoints.get(0), "2020-11-28T17:06:22.401Z", 1.234156, 12.340097, 469.286376953125);
|
||||
assertTrackpoint(importedTrackPoints.get(1), "2020-11-28T17:06:25.448Z", 1.23415, 12.340036, 439.1626281738281);
|
||||
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, 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, 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);
|
||||
assertTrackpoint(importedTrackPoints.get(6), "2020-11-28T17:06:56.905Z", 1.23405, 12.340057, 419.9036560058594);
|
||||
assertTrackpoint(importedTrackPoints.get(7), "2020-11-28T17:07:20.870Z", 1.234046, 12.340082, 417.99432373046875);
|
||||
assertEquals(TrackPoint.Type.SEGMENT_START_AUTOMATIC, importedTrackPoints.get(3).getType());
|
||||
assertTrackpoint(importedTrackPoints.get(3), "2020-11-28T17:06:55.861Z", 1.23405, 12.340057, 419.93902587890625);
|
||||
assertTrackpoint(importedTrackPoints.get(4), "2020-11-28T17:06:56.905Z", 1.23405, 12.340057, 419.9036560058594);
|
||||
assertTrackpoint(importedTrackPoints.get(5), "2020-11-28T17:07:20.870Z", 1.234046, 12.340082, 417.99432373046875);
|
||||
}
|
||||
|
||||
private void assertTrackpoint(final TrackPoint trackPoint, final String when, final double longitude, final double latitude, final double altitude) {
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class HandlerServerTest {
|
||||
@Test
|
||||
public void sendTrackPoint() throws InterruptedException {
|
||||
// given
|
||||
TrackPoint trackPoint = new TrackPoint();
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT);
|
||||
int accuracy = 50;
|
||||
|
||||
// when
|
||||
|
||||
@@ -44,6 +44,8 @@ public final class Marker {
|
||||
//TODO It is the distance from the track starting point; rename to something more meaningful
|
||||
private double length = 0.0;
|
||||
private long duration = 0;
|
||||
|
||||
@Deprecated //TODO Replace by storing latitude/longitude directly.
|
||||
private final Location location;
|
||||
@Deprecated //TODO Make an URI instead of String
|
||||
private String photoUrl = "";
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package de.dennisguse.opentracks.content.data;
|
||||
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -40,21 +39,25 @@ import java.util.Objects;
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
//TODO Merge constructors by use case; we have too many.
|
||||
public class TrackPoint {
|
||||
|
||||
private TrackPoint.Id id;
|
||||
|
||||
private final Location location;
|
||||
private long time_ms;
|
||||
private Double latitude;
|
||||
private Double longitude;
|
||||
private Float accuracy;
|
||||
private Double altitude_m;
|
||||
private Float speed_mps;
|
||||
private Float bearing;
|
||||
|
||||
//TODO Private
|
||||
public enum Type {
|
||||
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume); no useful coordinates
|
||||
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
|
||||
|
||||
SEGMENT_START_AUTOMATIC(-1), //Start of a segment due to too much distance from previous TrackPoint
|
||||
TRACKPOINT(0), //Normal trackpoint got from GPS
|
||||
TRACKPOINT(0), //Just GPS data.
|
||||
|
||||
SEGMENT_END_MANUAL(1); //End of a segment; no useful coordinates
|
||||
SEGMENT_END_MANUAL(1); //End of a segment
|
||||
|
||||
public final int type_db;
|
||||
|
||||
@@ -64,7 +67,7 @@ public class TrackPoint {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + type_db;
|
||||
return name() + "(" + type_db + ")";
|
||||
}
|
||||
|
||||
public static Type getById(int id) {
|
||||
@@ -74,10 +77,6 @@ public class TrackPoint {
|
||||
|
||||
throw new RuntimeException("unknown id: " + id);
|
||||
}
|
||||
|
||||
public boolean hasLocation() {
|
||||
return this == SEGMENT_START_AUTOMATIC || this == TRACKPOINT;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -89,35 +88,33 @@ public class TrackPoint {
|
||||
private Float elevationGain = null;
|
||||
private Float elevationLoss = null;
|
||||
|
||||
public TrackPoint() {
|
||||
this(Type.TRACKPOINT, new Location(""));
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull Type type) {
|
||||
this.type = type;
|
||||
this.location = new Location("");
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull Location location) {
|
||||
this.type = Type.TRACKPOINT;
|
||||
this.location = location;
|
||||
this(Type.TRACKPOINT);
|
||||
|
||||
this.latitude = location.getLatitude();
|
||||
this.longitude = location.getLongitude();
|
||||
this.altitude_m = location.getAltitude();
|
||||
this.speed_mps = location.getSpeed();
|
||||
this.accuracy = location.getAccuracy();
|
||||
|
||||
setTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public TrackPoint(@NonNull Type type, @NonNull Location location) {
|
||||
this.type = type;
|
||||
this.location = location;
|
||||
public TrackPoint(@NonNull Type type, long time_ms) {
|
||||
this(type);
|
||||
this.time_ms = time_ms;
|
||||
}
|
||||
|
||||
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);
|
||||
if (altitude != null) {
|
||||
location.setAltitude(altitude);
|
||||
}
|
||||
location.setTime(time);
|
||||
this(Type.TRACKPOINT);
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.altitude_m = altitude;
|
||||
this.time_ms = time;
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
@@ -126,9 +123,7 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentStartManualWithTime(long time) {
|
||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||
resume.setTime(time);
|
||||
return new TrackPoint(Type.SEGMENT_START_MANUAL, resume);
|
||||
return new TrackPoint(Type.SEGMENT_START_MANUAL, time);
|
||||
}
|
||||
|
||||
@Deprecated //See #316
|
||||
@@ -137,9 +132,7 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentStartAutomaticWithTime(long time) {
|
||||
Location resume = new Location(LocationManager.GPS_PROVIDER);
|
||||
resume.setTime(time);
|
||||
return new TrackPoint(Type.SEGMENT_START_AUTOMATIC, resume);
|
||||
return new TrackPoint(Type.SEGMENT_START_AUTOMATIC, time);
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentEnd() {
|
||||
@@ -151,9 +144,7 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public static TrackPoint createSegmentEndWithTime(long time) {
|
||||
Location pause = new Location(LocationManager.GPS_PROVIDER);
|
||||
pause.setTime(time);
|
||||
return new TrackPoint(Type.SEGMENT_END_MANUAL, pause);
|
||||
return new TrackPoint(Type.SEGMENT_END_MANUAL, time);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -185,8 +176,28 @@ public class TrackPoint {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean hasLocation() {
|
||||
return latitude != null || longitude != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Location getLocation() {
|
||||
Location location = new Location("");
|
||||
location.setTime(time_ms);
|
||||
if (hasLocation()) {
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
}
|
||||
if (hasBearing()) {
|
||||
location.setBearing(bearing);
|
||||
}
|
||||
if (hasAccuracy()) {
|
||||
location.setAccuracy(accuracy);
|
||||
}
|
||||
if (hasAltitude()) {
|
||||
location.setAltitude(altitude_m);
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
@@ -194,7 +205,7 @@ public class TrackPoint {
|
||||
return elevationGain != null;
|
||||
}
|
||||
|
||||
public float getElevationGain() {
|
||||
public Float getElevationGain() {
|
||||
return elevationGain;
|
||||
}
|
||||
|
||||
@@ -215,87 +226,87 @@ public class TrackPoint {
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return location.getLatitude();
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
location.setLatitude(latitude);
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return location.getLongitude();
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
location.setLongitude(longitude);
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return location.getTime();
|
||||
return time_ms;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
location.setTime(time);
|
||||
this.time_ms = time;
|
||||
}
|
||||
|
||||
public boolean hasAltitude() {
|
||||
return location.hasAltitude();
|
||||
return altitude_m != null;
|
||||
}
|
||||
|
||||
public double getAltitude() {
|
||||
return location.getAltitude();
|
||||
return altitude_m;
|
||||
}
|
||||
|
||||
public void setAltitude(double altitude) {
|
||||
location.setAltitude(altitude);
|
||||
this.altitude_m = altitude;
|
||||
}
|
||||
|
||||
public boolean hasSpeed() {
|
||||
return location.hasSpeed();
|
||||
return speed_mps != null;
|
||||
}
|
||||
|
||||
public float getSpeed() {
|
||||
return location.getSpeed();
|
||||
return speed_mps;
|
||||
}
|
||||
|
||||
public void setSpeed(float speed) {
|
||||
location.setSpeed(speed);
|
||||
public void setSpeed(Float speed) {
|
||||
this.speed_mps = speed;
|
||||
}
|
||||
|
||||
public boolean hasBearing() {
|
||||
return location.hasBearing();
|
||||
return bearing != null;
|
||||
}
|
||||
|
||||
public float getBearing() {
|
||||
return location.getBearing();
|
||||
return bearing;
|
||||
}
|
||||
|
||||
public void setBearing(float bearing) {
|
||||
location.setBearing(bearing);
|
||||
public void setBearing(Float bearing) {
|
||||
this.bearing = bearing;
|
||||
}
|
||||
|
||||
public boolean hasAccuracy() {
|
||||
return location.hasAccuracy();
|
||||
return accuracy != null;
|
||||
}
|
||||
|
||||
public float getAccuracy() {
|
||||
return location.getAccuracy();
|
||||
return accuracy;
|
||||
}
|
||||
|
||||
public void setAccuracy(float horizontalAccuracy) {
|
||||
location.setAccuracy(horizontalAccuracy);
|
||||
this.accuracy = horizontalAccuracy;
|
||||
}
|
||||
|
||||
public float distanceTo(@NonNull TrackPoint dest) {
|
||||
return location.distanceTo(dest.getLocation());
|
||||
return getLocation().distanceTo(dest.getLocation());
|
||||
}
|
||||
|
||||
public float bearingTo(@NonNull TrackPoint dest) {
|
||||
return location.bearingTo(dest.getLocation());
|
||||
return getLocation().bearingTo(dest.getLocation());
|
||||
}
|
||||
|
||||
public float bearingTo(@NonNull Location dest) {
|
||||
return location.bearingTo(dest);
|
||||
return getLocation().bearingTo(dest);
|
||||
}
|
||||
|
||||
// Sensor data
|
||||
@@ -342,7 +353,16 @@ public class TrackPoint {
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "time=" + getTime() + " (type=" + getType() + "): lat=" + getLatitude() + " lng=" + getLongitude() + " acc=" + getAccuracy();
|
||||
String result = "time=" + getTime() + " (type=" + getType() + ")";
|
||||
if (!hasLocation()) {
|
||||
return result;
|
||||
}
|
||||
result += ": lat=" + getLatitude() + " lng=" + getLongitude();
|
||||
if (!hasAccuracy()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result + " acc=" + getAccuracy();
|
||||
}
|
||||
|
||||
public static class Id {
|
||||
|
||||
@@ -543,9 +543,7 @@ public class ContentProviderUtils {
|
||||
*/
|
||||
static TrackPoint fillTrackPoint(Cursor cursor, CachedTrackPointsIndexes indexes) {
|
||||
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)));
|
||||
}
|
||||
trackPoint.setId(new TrackPoint.Id(cursor.getInt(indexes.idIndex)));
|
||||
|
||||
if (!cursor.isNull(indexes.longitudeIndex)) {
|
||||
trackPoint.setLongitude(((double) cursor.getInt(indexes.longitudeIndex)) / 1E6);
|
||||
@@ -694,7 +692,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.TYPE + " IN (" + TrackPoint.Type.SEGMENT_START_AUTOMATIC + "," + TrackPoint.Type.TRACKPOINT + "))";
|
||||
String selection = TrackPointsColumns._ID + "=(SELECT MAX(" + TrackPointsColumns._ID + ") FROM " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND " + TrackPointsColumns.TYPE + " IN (" + TrackPoint.Type.SEGMENT_START_AUTOMATIC.type_db + "," + TrackPoint.Type.TRACKPOINT.type_db + "))";
|
||||
String[] selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
return findTrackPointBy(selection, selectionArgs);
|
||||
}
|
||||
@@ -719,12 +717,12 @@ public class ContentProviderUtils {
|
||||
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));
|
||||
values.put(TrackPointsColumns.TYPE, trackPoint.getType().type_db);
|
||||
|
||||
if (trackPoint.hasLocation()) {
|
||||
values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getLongitude() * 1E6));
|
||||
values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getLatitude() * 1E6));
|
||||
}
|
||||
values.put(TrackPointsColumns.TIME, trackPoint.getTime());
|
||||
if (trackPoint.hasAltitude()) {
|
||||
values.put(TrackPointsColumns.ALTITUDE, trackPoint.getAltitude());
|
||||
|
||||
@@ -12,6 +12,7 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
/**
|
||||
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
|
||||
*/
|
||||
//TODO Remove batching; that should be handled by the database/contentprovider (i.e., already in place as we use a cursor)!
|
||||
public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
||||
|
||||
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
||||
@@ -22,7 +23,6 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
||||
private TrackPoint.Id lastTrackPointId = null;
|
||||
private Cursor cursor;
|
||||
|
||||
|
||||
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
this.trackId = trackId;
|
||||
|
||||
@@ -191,7 +191,7 @@ 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 && trackPoint.getType().hasLocation()) {
|
||||
if (trackPoint != null && trackPoint.hasLocation()) {
|
||||
boolean hasFix = !LocationUtils.isTrackPointOld(trackPoint);
|
||||
|
||||
if (!hasFix) {
|
||||
|
||||
@@ -45,8 +45,8 @@ public class FileTrackExporter implements TrackExporter {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param contentProviderUtils the content provider utils
|
||||
* @param trackWriter the track writer
|
||||
* @param contentProviderUtils the content provider utils
|
||||
* @param trackWriter the track writer
|
||||
*/
|
||||
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter) {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
@@ -70,6 +70,7 @@ public class FileTrackExporter implements TrackExporter {
|
||||
if (hasMultipleTracks) {
|
||||
trackWriter.writeMultiTrackBegin();
|
||||
}
|
||||
//TODO Why use startTime of first track for the others?
|
||||
long startTime = tracks[0].getTrackStatistics().getStartTime_ms();
|
||||
for (Track track : tracks) {
|
||||
long offset = track.getTrackStatistics().getStartTime_ms() - startTime;
|
||||
@@ -122,50 +123,40 @@ public class FileTrackExporter implements TrackExporter {
|
||||
private void writeLocations(Track track, long offset) throws InterruptedException {
|
||||
boolean wroteTrack = false;
|
||||
boolean wroteSegment = false;
|
||||
boolean isLastLocationValid = false;
|
||||
TrackPoint lastTrackPoint = null;
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
setLocationTime(trackPoint, offset);
|
||||
|
||||
boolean isLocationValid = trackPoint.getType().hasLocation();
|
||||
boolean isSegmentValid = isLocationValid && isLastLocationValid;
|
||||
if (!wroteTrack && isSegmentValid) {
|
||||
// Found the first two consecutive locations that are valid
|
||||
trackWriter.writeBeginTrack(track, lastTrackPoint);
|
||||
if (!wroteTrack) {
|
||||
trackWriter.writeBeginTrack(track, trackPoint);
|
||||
wroteTrack = true;
|
||||
}
|
||||
|
||||
if (isSegmentValid) {
|
||||
if (!wroteSegment) {
|
||||
// Start a segment
|
||||
trackWriter.writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
|
||||
// Write the previous trackPoint, which we had previously skipped
|
||||
trackWriter.writeTrackPoint(lastTrackPoint);
|
||||
}
|
||||
|
||||
// Write the current trackPoint
|
||||
boolean newSegment = TrackPoint.Type.SEGMENT_START_AUTOMATIC.equals(trackPoint.getType()) || TrackPoint.Type.SEGMENT_START_MANUAL.equals(trackPoint.getType());
|
||||
if (newSegment) {
|
||||
if (wroteSegment) trackWriter.writeCloseSegment();
|
||||
trackWriter.writeOpenSegment();
|
||||
trackWriter.writeTrackPoint(trackPoint);
|
||||
} else {
|
||||
if (wroteSegment) {
|
||||
trackWriter.writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
}
|
||||
wroteSegment = true;
|
||||
continue;
|
||||
}
|
||||
lastTrackPoint = trackPoint;
|
||||
isLastLocationValid = isLocationValid;
|
||||
if (TrackPoint.Type.SEGMENT_END_MANUAL.equals(trackPoint.getType())) {
|
||||
if (!wroteSegment) trackWriter.writeOpenSegment();
|
||||
trackWriter.writeTrackPoint(trackPoint);
|
||||
trackWriter.writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
trackWriter.writeTrackPoint(trackPoint);
|
||||
}
|
||||
|
||||
if (wroteSegment) {
|
||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||
//Close the last segment
|
||||
trackWriter.writeCloseSegment();
|
||||
}
|
||||
@@ -188,6 +179,7 @@ public class FileTrackExporter implements TrackExporter {
|
||||
* @param trackPoint the trackPoint
|
||||
* @param offset the time offset
|
||||
*/
|
||||
//TODO Why?
|
||||
private void setLocationTime(TrackPoint trackPoint, long offset) {
|
||||
if (trackPoint != null) {
|
||||
trackPoint.setTime(trackPoint.getTime() - offset);
|
||||
|
||||
@@ -190,7 +190,9 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
@Override
|
||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLocation()) + ">");
|
||||
String coordinates = trackPoint.hasLocation() ? " " + formatLocation(trackPoint.getLocation()) : "";
|
||||
printWriter.println("<trkpt " + coordinates + ">");
|
||||
|
||||
if (trackPoint.hasAltitude()) {
|
||||
printWriter.println("<ele>" + ELEVATION_FORMAT.format(trackPoint.getAltitude()) + "</ele>");
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.DescriptionGenerator;
|
||||
@@ -239,6 +240,8 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
powerList.clear();
|
||||
cadenceList.clear();
|
||||
heartRateList.clear();
|
||||
elevationGainList.clear();
|
||||
elevationLossList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,23 +250,23 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<ExtendedData>");
|
||||
printWriter.println("<SchemaData schemaUrl=\"#" + SCHEMA_ID + "\">");
|
||||
if (speedList.size() > 0) {
|
||||
if (speedList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(speedList, EXTENDED_DATA_TYPE_SPEED);
|
||||
}
|
||||
if (exportSensorData) {
|
||||
if (powerList.size() > 0) {
|
||||
if (powerList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(powerList, EXTENDED_DATA_TYPE_POWER);
|
||||
}
|
||||
if (cadenceList.size() > 0) {
|
||||
if (cadenceList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(cadenceList, EXTENDED_DATA_TYPE_CADENCE);
|
||||
}
|
||||
if (heartRateList.size() > 0) {
|
||||
if (heartRateList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(heartRateList, EXTENDED_DATA_TYPE_HEART_RATE);
|
||||
}
|
||||
if (elevationGainList.size() > 0) {
|
||||
if (elevationGainList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(elevationGainList, EXTENDED_DATA_TYPE_ELEVATION_GAIN);
|
||||
}
|
||||
if (elevationLossList.size() > 0) {
|
||||
if (elevationLossList.stream().anyMatch(Objects::nonNull)) {
|
||||
writeSimpleArrayData(elevationLossList, EXTENDED_DATA_TYPE_ELEVATION_LOSS);
|
||||
}
|
||||
}
|
||||
@@ -280,28 +283,20 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
printWriter.println("<when>" + getTime(trackPoint.getLocation()) + "</when>");
|
||||
}
|
||||
|
||||
printWriter.println("<gx:coord>" + getCoordinates(trackPoint.getLocation(), " ") + "</gx:coord>");
|
||||
|
||||
if (trackPoint.hasSpeed()) {
|
||||
speedList.add(trackPoint.getSpeed());
|
||||
if (trackPoint.hasLocation()) {
|
||||
printWriter.println("<gx:coord>" + (trackPoint.hasLocation() ? getCoordinates(trackPoint.getLocation(), " ") : "") + "</gx:coord>");
|
||||
} else {
|
||||
printWriter.println("<gx:coord/>");
|
||||
}
|
||||
speedList.add(trackPoint.hasSpeed() ? trackPoint.getSpeed() : null);
|
||||
|
||||
if (exportSensorData) {
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
heartRateList.add(trackPoint.getHeartRate_bpm());
|
||||
}
|
||||
if (trackPoint.hasCyclingCadence()) {
|
||||
cadenceList.add(trackPoint.getCyclingCadence_rpm());
|
||||
}
|
||||
if (trackPoint.hasPower()) {
|
||||
powerList.add(trackPoint.getPower());
|
||||
}
|
||||
if (trackPoint.hasElevationGain()) {
|
||||
elevationGainList.add(trackPoint.getElevationGain());
|
||||
}
|
||||
if (trackPoint.hasElevationLoss()) {
|
||||
elevationLossList.add(trackPoint.getElevationLoss());
|
||||
}
|
||||
heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate_bpm() : null);
|
||||
cadenceList.add(trackPoint.hasCyclingCadence() ? trackPoint.getCyclingCadence_rpm() : null);
|
||||
powerList.add(trackPoint.hasPower() ? trackPoint.getPower() : null);
|
||||
|
||||
elevationGainList.add(trackPoint.hasElevationGain() ? trackPoint.getElevationGain() : null);
|
||||
elevationLossList.add(trackPoint.hasElevationLoss() ? trackPoint.getElevationLoss() : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,7 +310,12 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
private void writeSimpleArrayData(List<Float> list, String name) {
|
||||
printWriter.println("<gx:SimpleArrayData name=\"" + name + "\">");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
printWriter.println("<gx:value>" + list.get(i) + "</gx:value>");
|
||||
Float value = list.get(i);
|
||||
if (value == null) {
|
||||
printWriter.println("<gx:value />");
|
||||
} else {
|
||||
printWriter.println("<gx:value>" + list.get(i) + "</gx:value>");
|
||||
}
|
||||
}
|
||||
printWriter.println("</gx:SimpleArrayData>");
|
||||
}
|
||||
|
||||
+55
-57
@@ -158,6 +158,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
TrackPoint trackPoint = null;
|
||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
|
||||
// TODO We are doing in memory processing for trackpoints; so we can do this in memory as well.
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
|
||||
while (true) {
|
||||
@@ -190,7 +191,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
marker = null;
|
||||
} else {
|
||||
// The marker trackPoint time matches the track point time
|
||||
if (!trackPoint.getType().hasLocation()) {
|
||||
if (!trackPoint.hasLocation()) {
|
||||
// Invalid trackPoint, load the next trackPoint
|
||||
trackPoint = null;
|
||||
continue;
|
||||
@@ -274,31 +275,43 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
trackIds.add(trackId);
|
||||
trackData.track.setId(trackId);
|
||||
|
||||
flushLocations(trackData);
|
||||
flushTrackPoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* On track segment start.
|
||||
*/
|
||||
protected void onTrackSegmentStart() {
|
||||
trackData.numberOfSegments++;
|
||||
|
||||
//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.createSegmentEndWithTime(trackData.lastLocationInCurrentSegment.getTime()));
|
||||
//If not the first segment, add a pause separator if there is at least one TrackPoint in the last segment.
|
||||
if (trackData.numberOfSegments > 1
|
||||
&& trackData.lastLocationInCurrentSegment != null
|
||||
&& (trackData.lastLocationInCurrentSegment.getType().equals(TrackPoint.Type.SEGMENT_START_MANUAL) || trackData.lastLocationInCurrentSegment.getType().equals(TrackPoint.Type.SEGMENT_START_AUTOMATIC))
|
||||
) {
|
||||
insertTrackPoint(TrackPoint.createSegmentEndWithTime(trackData.lastLocationInCurrentSegment.getTime()));
|
||||
}
|
||||
trackData.lastLocationInCurrentSegment = null;
|
||||
}
|
||||
|
||||
protected void onTrackSegmentEnd() {
|
||||
TrackPoint trackPoint = trackData.lastLocationInCurrentSegment;
|
||||
if (trackPoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!trackPoint.hasLocation()) {
|
||||
trackPoint.setType(TrackPoint.Type.SEGMENT_END_MANUAL);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addMarker() throws SAXException {
|
||||
// Markers must have a time, else cannot match to the track points
|
||||
if (time == null) {
|
||||
Log.w(TAG, "Marker without time ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
TrackPoint trackPoint = createTrackPoint();
|
||||
|
||||
if (!trackPoint.getType().hasLocation()) {
|
||||
if (!trackPoint.hasLocation()) {
|
||||
Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.getLocation());
|
||||
return;
|
||||
}
|
||||
@@ -320,14 +333,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
markers.add(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a track point.
|
||||
*/
|
||||
protected TrackPoint getTrackPoint() throws SAXException {
|
||||
TrackPoint trackPoint = createTrackPoint();
|
||||
if (trackPoint == null) {
|
||||
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
|
||||
}
|
||||
|
||||
// Calculate derived attributes from the previous point
|
||||
if (trackData.lastLocationInCurrentSegment != null && trackData.lastLocationInCurrentSegment.getTime() != 0) {
|
||||
@@ -344,34 +351,31 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
* 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;
|
||||
double speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / duration;
|
||||
trackPoint.setSpeed((float) speed);
|
||||
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
||||
double speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / duration;
|
||||
trackPoint.setSpeed((float) speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
||||
trackPoint.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(trackPoint));
|
||||
|
||||
long maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance(context);
|
||||
double distanceToLastTrackLocation = trackPoint.distanceTo(trackData.lastLocationInCurrentSegment);
|
||||
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
||||
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||
}
|
||||
}
|
||||
trackPoint.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(trackPoint));
|
||||
}
|
||||
|
||||
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
if (trackPoint.hasLocation() && !LocationUtils.isValidLocation(trackPoint.getLocation())) {
|
||||
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
|
||||
}
|
||||
|
||||
if (trackData.numberOfSegments > 1 && trackData.lastLocationInCurrentSegment == null) {
|
||||
// If not the first segment, add a resume separator before adding the first location.
|
||||
insertLocation(TrackPoint.createSegmentStartManualWithTime(trackPoint.getTime()));
|
||||
}
|
||||
trackData.lastLocationInCurrentSegment = trackPoint;
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a track point.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
*/
|
||||
protected void insertTrackPoint(TrackPoint trackPoint) {
|
||||
insertLocation(trackPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error message.
|
||||
*
|
||||
@@ -411,11 +415,17 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
* Creates a location.
|
||||
*/
|
||||
private TrackPoint createTrackPoint() throws SAXException {
|
||||
if (latitude == null || longitude == null) {
|
||||
return null;
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT);
|
||||
|
||||
try {
|
||||
trackPoint.setTime(StringUtils.parseTime(time));
|
||||
} catch (Exception e) {
|
||||
throw new SAXException(createErrorMessage(String.format(Locale.US, "Unable to parse time: %s", time)), e);
|
||||
}
|
||||
|
||||
TrackPoint trackPoint = new TrackPoint();
|
||||
if (latitude == null || longitude == null) {
|
||||
return trackPoint;
|
||||
}
|
||||
|
||||
try {
|
||||
trackPoint.setLatitude(Double.parseDouble(latitude));
|
||||
@@ -424,11 +434,6 @@ 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
@@ -484,7 +489,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
*/
|
||||
private void insertLocation(TrackPoint trackPoint) {
|
||||
protected void insertTrackPoint(TrackPoint trackPoint) {
|
||||
if (trackData.trackStatisticsUpdater == null) {
|
||||
trackData.trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||
}
|
||||
@@ -492,21 +497,20 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
trackData.trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||
|
||||
trackData.bufferedTrackPoints.add(trackPoint);
|
||||
trackData.numBufferedTrackPoints++;
|
||||
trackData.numberOfLocations++;
|
||||
}
|
||||
|
||||
protected boolean isFirstTrackPointInSegment() {
|
||||
return trackData.lastLocationInCurrentSegment == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the locations to the database.
|
||||
*
|
||||
* @param data the track data
|
||||
* Flushes the TrackPoints to the database.
|
||||
*/
|
||||
private void flushLocations(TrackData data) {
|
||||
if (data.numBufferedTrackPoints <= 0) {
|
||||
return;
|
||||
private void flushTrackPoints() {
|
||||
if (trackData.bufferedTrackPoints.size() > 0) {
|
||||
contentProviderUtils.bulkInsertTrackPoint(trackData.bufferedTrackPoints, trackData.track.getId());
|
||||
trackData.bufferedTrackPoints.clear();
|
||||
}
|
||||
contentProviderUtils.bulkInsertTrackPoint(data.bufferedTrackPoints, data.track.getId());
|
||||
data.numBufferedTrackPoints = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,16 +536,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
// The last location in the current segment; Null if the current segment doesn't have a last location
|
||||
TrackPoint lastLocationInCurrentSegment;
|
||||
|
||||
// The number of locations processed for the current track
|
||||
int numberOfLocations = 0;
|
||||
|
||||
// The TrackStatisticsUpdater for the current track
|
||||
TrackStatisticsUpdater trackStatisticsUpdater;
|
||||
|
||||
// The buffered locations
|
||||
final List<TrackPoint> bufferedTrackPoints = new ArrayList<>();
|
||||
|
||||
// The number of buffered locations
|
||||
int numBufferedTrackPoints = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,9 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
case TAG_TRACK:
|
||||
onTrackEnd();
|
||||
break;
|
||||
case TAG_TRACK_SEGMENT:
|
||||
onTrackSegmentEnd();
|
||||
break;
|
||||
case TAG_TRACK_POINT:
|
||||
onTrackPointEnd();
|
||||
break;
|
||||
@@ -193,13 +196,13 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
loss = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* On track point end.
|
||||
*/
|
||||
private void onTrackPointEnd() throws SAXException {
|
||||
boolean isFirstTrackPointInSegment = isFirstTrackPointInSegment();
|
||||
TrackPoint trackPoint = getTrackPoint();
|
||||
if (trackPoint == null) {
|
||||
return;
|
||||
if (isFirstTrackPointInSegment) {
|
||||
TrackPoint.Type type = !trackPoint.hasLocation() ? TrackPoint.Type.SEGMENT_START_MANUAL : TrackPoint.Type.SEGMENT_START_AUTOMATIC;
|
||||
|
||||
trackPoint.setType(type);
|
||||
}
|
||||
insertTrackPoint(trackPoint);
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
if (content != null) {
|
||||
time = content.trim();
|
||||
}
|
||||
|
||||
break;
|
||||
case TAG_STYLE_URL:
|
||||
if (content != null) {
|
||||
@@ -221,10 +222,8 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
elevationLossList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* On track segment end.
|
||||
*/
|
||||
private void onTrackSegmentEnd() {
|
||||
protected void onTrackSegmentEnd() {
|
||||
super.onTrackSegmentEnd();
|
||||
// Close a track segment by inserting the segment locations
|
||||
for (int i = 0; i < trackPoints.size(); i++) {
|
||||
TrackPoint trackPoint = trackPoints.get(i);
|
||||
@@ -256,24 +255,32 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
* On track point end. gx:coord end tag.
|
||||
*/
|
||||
private void onTrackPointEnd() throws SAXException {
|
||||
// Add location to locationList
|
||||
// Add trackPoint to trackPoints
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
String[] parts = content.trim().split(" ");
|
||||
if (parts.length != 2 && parts.length != 3) {
|
||||
return;
|
||||
if (parts.length == 2 || parts.length == 3) {
|
||||
longitude = parts[0];
|
||||
latitude = parts[1];
|
||||
altitude = parts.length == 3 ? parts[2] : null;
|
||||
}
|
||||
longitude = parts[0];
|
||||
latitude = parts[1];
|
||||
altitude = parts.length == 3 ? parts[2] : null;
|
||||
|
||||
TrackPoint location = getTrackPoint();
|
||||
if (location == null) {
|
||||
return;
|
||||
// Similar to GPX
|
||||
boolean isFirstTrackPointInSegment = isFirstTrackPointInSegment();
|
||||
TrackPoint trackPoint = getTrackPoint();
|
||||
if (isFirstTrackPointInSegment) {
|
||||
TrackPoint.Type type = !trackPoint.hasLocation() ? TrackPoint.Type.SEGMENT_START_MANUAL : TrackPoint.Type.SEGMENT_START_AUTOMATIC;
|
||||
|
||||
trackPoint.setType(type);
|
||||
}
|
||||
trackPoints.add(location);
|
||||
trackPoints.add(trackPoint);
|
||||
|
||||
// Reset variables for next trackpoint (which might not have such data).
|
||||
time = null;
|
||||
longitude = null;
|
||||
latitude = null;
|
||||
altitude = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,18 +294,16 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
* On extended data value end. gx:value end tag.
|
||||
*/
|
||||
private void onExtendedDataValueEnd() throws SAXException {
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
content = content.trim();
|
||||
if (content.equals("")) {
|
||||
return;
|
||||
}
|
||||
float value;
|
||||
try {
|
||||
value = Float.parseFloat(content);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SAXException(createErrorMessage("Unable to parse gx:value:" + content), e);
|
||||
Float value = null;
|
||||
if (content != null) {
|
||||
content = content.trim();
|
||||
if (!content.equals("")) {
|
||||
try {
|
||||
value = Float.parseFloat(content);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SAXException(createErrorMessage("Unable to parse gx:value:" + content), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (extendedDataType) {
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_SPEED:
|
||||
|
||||
@@ -31,7 +31,7 @@ public class IntervalStatistics {
|
||||
TrackPoint prevTrackPoint = trackPoints.get(i - 1);
|
||||
TrackPoint trackPoint = trackPoints.get(i);
|
||||
|
||||
if (trackPoint.getType().hasLocation() && prevTrackPoint.getType().hasLocation()) {
|
||||
if (trackPoint.hasLocation() && prevTrackPoint.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