forked from upstream-mirrors/OpenTracks
GPX: only export TrackPoints with lat/lng. (#591)
GPX: only export TrackPoints with lat/lng. Thus, segmentation (manual/automatic) cannot be restored on import. This also affects the TrackStatistics.
This commit is contained in:
@@ -36,7 +36,7 @@ import java.util.Objects;
|
||||
* 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.
|
||||
* TODO: if these might be a problem, we need to store both timestamps.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
@@ -177,7 +177,7 @@ public class TrackPoint {
|
||||
return latitude != null || longitude != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
public Location getLocation() {
|
||||
Location location = new Location("");
|
||||
location.setTime(time.toEpochMilli());
|
||||
|
||||
@@ -221,7 +221,7 @@ public class ShareContentProvider extends CustomContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
final TrackExporter trackExporter = getTrackFileFormat(uri).newTrackExporter(getContext());
|
||||
final TrackExporter trackExporter = getTrackFileFormat(uri).createTrackExporter(getContext());
|
||||
|
||||
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
||||
|
||||
@@ -6,12 +6,10 @@ import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.exporter.FileTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KmlTrackWriter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackWriter;
|
||||
|
||||
/**
|
||||
* Definition of all possible track formats.
|
||||
@@ -20,8 +18,8 @@ public enum TrackFileFormat {
|
||||
|
||||
KML_ONLY_TRACK {
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, false, false, false);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
return new KMLTrackExporter(context, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,8 +33,8 @@ public enum TrackFileFormat {
|
||||
},
|
||||
KML_WITH_TRACKDETAIL {
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, true, false, false);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
return new KMLTrackExporter(context, true, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,8 +48,8 @@ public enum TrackFileFormat {
|
||||
},
|
||||
KML_WITH_TRACKDETAIL_AND_SENSORDATA {
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, true, true, false);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
return new KMLTrackExporter(context, true, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,16 +62,12 @@ public enum TrackFileFormat {
|
||||
}
|
||||
},
|
||||
KMZ_ONLY_TRACK {
|
||||
|
||||
private static final boolean exportPhotos = false;
|
||||
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, false, false, exportPhotos);
|
||||
}
|
||||
|
||||
public TrackExporter newTrackExporter(Context context) {
|
||||
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, false, false, exportPhotos);
|
||||
return new KmzTrackExporter(context, new ContentProviderUtils(context), exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,12 +89,9 @@ public enum TrackFileFormat {
|
||||
private static final boolean exportPhotos = false;
|
||||
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, true, false, exportPhotos);
|
||||
}
|
||||
|
||||
public TrackExporter newTrackExporter(Context context) {
|
||||
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, true, false, exportPhotos);
|
||||
return new KmzTrackExporter(context, new ContentProviderUtils(context), exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,8 +114,9 @@ public enum TrackFileFormat {
|
||||
private static final boolean exportPhotos = false;
|
||||
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, true, true, exportPhotos);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, true, true, exportPhotos);
|
||||
return new KmzTrackExporter(context, new ContentProviderUtils(context), exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,10 +124,6 @@ public enum TrackFileFormat {
|
||||
return MIME_KMZ;
|
||||
}
|
||||
|
||||
public TrackExporter newTrackExporter(Context context) {
|
||||
return newKmzTrackExporter(context, this.newTrackWriter(context), exportPhotos);
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return "kmz";
|
||||
}
|
||||
@@ -152,8 +140,9 @@ public enum TrackFileFormat {
|
||||
private static final boolean exportPhotos = true;
|
||||
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new KmlTrackWriter(context, true, true, exportPhotos);
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, true, true, exportPhotos);
|
||||
return new KmzTrackExporter(context, new ContentProviderUtils(context), exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,10 +150,6 @@ public enum TrackFileFormat {
|
||||
return MIME_KMZ;
|
||||
}
|
||||
|
||||
public TrackExporter newTrackExporter(Context context) {
|
||||
return newKmzTrackExporter(context, newTrackWriter(context), exportPhotos);
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return "kmz";
|
||||
}
|
||||
@@ -177,8 +162,8 @@ public enum TrackFileFormat {
|
||||
},
|
||||
GPX {
|
||||
@Override
|
||||
public TrackWriter newTrackWriter(Context context) {
|
||||
return new GpxTrackWriter(context.getString(R.string.app_name));
|
||||
public TrackExporter createTrackExporter(Context context) {
|
||||
return new GPXTrackExporter(new ContentProviderUtils(context), context.getString(R.string.app_name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,31 +180,17 @@ public enum TrackFileFormat {
|
||||
|
||||
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
|
||||
|
||||
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, boolean exportPhotos) {
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
|
||||
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter);
|
||||
|
||||
return new KmzTrackExporter(context, contentProviderUtils, fileTrackExporter, exportPhotos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type for each format.
|
||||
*/
|
||||
public abstract String getMimeType();
|
||||
|
||||
public TrackExporter newTrackExporter(Context context) {
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
TrackWriter trackWriter = newTrackWriter(context);
|
||||
return new FileTrackExporter(contentProviderUtils, trackWriter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new track writer for the format.
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
public abstract TrackWriter newTrackWriter(Context context);
|
||||
public abstract TrackExporter createTrackExporter(Context context);
|
||||
|
||||
/**
|
||||
* Returns the file extension for each format.
|
||||
@@ -234,7 +205,7 @@ public enum TrackFileFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of for each format.
|
||||
* Returns the name for each format.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name().toLowerCase(Locale.US);
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
|
||||
/**
|
||||
* Track Writer for writing tracks to an {@link OutputStream}.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class FileTrackExporter implements TrackExporter {
|
||||
|
||||
private static final String TAG = FileTrackExporter.class.getSimpleName();
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
private final TrackWriter trackWriter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param contentProviderUtils the content provider utils
|
||||
* @param trackWriter the track writer
|
||||
*/
|
||||
public FileTrackExporter(ContentProviderUtils contentProviderUtils, TrackWriter trackWriter) {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
this.trackWriter = trackWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(tracks);
|
||||
for (Track track : tracks) {
|
||||
writeMarkers(track);
|
||||
}
|
||||
boolean hasMultipleTracks = tracks.length > 1;
|
||||
if (hasMultipleTracks) {
|
||||
trackWriter.writeMultiTrackBegin();
|
||||
}
|
||||
//TODO Why use startTime of first track for the others?
|
||||
Instant startTime = tracks[0].getTrackStatistics().getStartTime();
|
||||
for (Track track : tracks) {
|
||||
Duration offset = Duration.between(track.getTrackStatistics().getStartTime(), startTime);
|
||||
writeLocations(track, offset);
|
||||
}
|
||||
if (hasMultipleTracks) {
|
||||
trackWriter.writeMultiTrackEnd();
|
||||
}
|
||||
trackWriter.writeFooter();
|
||||
trackWriter.close();
|
||||
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMarkers(Track track) throws InterruptedException {
|
||||
/*
|
||||
* TODO: Stream through the markers in chunks.
|
||||
* 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, -1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (!hasMarkers) {
|
||||
trackWriter.writeBeginMarkers(track);
|
||||
hasMarkers = true;
|
||||
}
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
trackWriter.writeMarker(marker);
|
||||
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasMarkers) {
|
||||
trackWriter.writeEndMarkers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the locations.
|
||||
*/
|
||||
private void writeLocations(Track track, Duration offset) throws InterruptedException {
|
||||
boolean wroteTrack = false;
|
||||
boolean wroteSegment = false;
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
setLocationTime(trackPoint, offset);
|
||||
|
||||
if (!wroteTrack) {
|
||||
trackWriter.writeBeginTrack(track, trackPoint);
|
||||
wroteTrack = true;
|
||||
}
|
||||
|
||||
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);
|
||||
wroteSegment = true;
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
if (wroteTrack) {
|
||||
TrackPoint lastValidTrackPoint = contentProviderUtils.getLastValidTrackPoint(track.getId());
|
||||
setLocationTime(lastValidTrackPoint, offset);
|
||||
trackWriter.writeEndTrack(track, lastValidTrackPoint);
|
||||
} else {
|
||||
// Write an empty track
|
||||
trackWriter.writeBeginTrack(track, null);
|
||||
trackWriter.writeEndTrack(track, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a trackPoint time.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
* @param offset the time offset
|
||||
*/
|
||||
//TODO Why?
|
||||
private void setLocationTime(TrackPoint trackPoint, Duration offset) {
|
||||
if (trackPoint != null) {
|
||||
trackPoint.setTime(trackPoint.getTime().minus(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
+123
-37
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.NumberFormat;
|
||||
@@ -24,15 +29,21 @@ import java.util.Locale;
|
||||
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.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Write track as GPX to a file.
|
||||
* Convert {@link Track} incl. {@link Marker} and {@link TrackPoint} to KML.
|
||||
* NOTE:
|
||||
* * does not export {@link TrackPoint} without a latitude/longitude (not supported by GPX 1.1).
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
//TODO Export markers
|
||||
public class GpxTrackWriter implements TrackWriter {
|
||||
public class GPXTrackExporter implements TrackExporter {
|
||||
|
||||
private static final String TAG = GPXTrackExporter.class.getSimpleName();
|
||||
|
||||
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
@@ -62,19 +73,106 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
CADENCE_FORMAT.setGroupingUsed(false);
|
||||
}
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
|
||||
private final String creator;
|
||||
private PrintWriter printWriter;
|
||||
|
||||
public GpxTrackWriter(String creator) {
|
||||
public GPXTrackExporter(ContentProviderUtils contentProviderUtils, String creator) {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
writeHeader(track);
|
||||
|
||||
writeMarkers(track);
|
||||
|
||||
writeLocations(track);
|
||||
|
||||
writeFooter();
|
||||
close();
|
||||
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void writeLocations(Track track) throws InterruptedException {
|
||||
boolean wroteTrack = false;
|
||||
boolean wroteSegment = false;
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
|
||||
if (!wroteTrack) {
|
||||
writeBeginTrack(track, trackPoint);
|
||||
wroteTrack = true;
|
||||
}
|
||||
|
||||
switch (trackPoint.getType()) {
|
||||
case SEGMENT_START_MANUAL:
|
||||
if (wroteSegment) writeCloseSegment();
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
Log.i(TAG, "Exporting " + TrackPoint.Type.SEGMENT_START_MANUAL.name() + " is not supported.");
|
||||
break;
|
||||
case SEGMENT_END_MANUAL:
|
||||
writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
Log.i(TAG, "Exporting " + TrackPoint.Type.SEGMENT_END_MANUAL.name() + " is not supported.");
|
||||
break;
|
||||
case SEGMENT_START_AUTOMATIC:
|
||||
if (wroteSegment) writeCloseSegment();
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
writeTrackPoint(trackPoint);
|
||||
break;
|
||||
case TRACKPOINT:
|
||||
if (!wroteSegment) {
|
||||
// Might happen for older data (pre v3.15.0)
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
}
|
||||
writeTrackPoint(trackPoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wroteSegment) {
|
||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||
// Anyhow, make sure that the last segment is closed.
|
||||
writeCloseSegment();
|
||||
}
|
||||
|
||||
if (wroteTrack) {
|
||||
TrackPoint lastValidTrackPoint = contentProviderUtils.getLastValidTrackPoint(track.getId());
|
||||
writeEndTrack(track, lastValidTrackPoint);
|
||||
} else {
|
||||
// Write an empty track
|
||||
writeBeginTrack(track, null);
|
||||
writeEndTrack(track, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void prepare(OutputStream outputStream) {
|
||||
this.printWriter = new PrintWriter(outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (printWriter != null) {
|
||||
printWriter.flush();
|
||||
@@ -82,8 +180,8 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(Track[] tracks) {
|
||||
|
||||
public void writeHeader(Track track) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
printWriter.println("<gpx");
|
||||
@@ -103,31 +201,34 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
|
||||
printWriter.println("<metadata>");
|
||||
|
||||
Track track = tracks[0];
|
||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
|
||||
printWriter.println("</metadata>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFooter() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</gpx>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginMarkers(Track track) {
|
||||
// Do nothing
|
||||
private void writeMarkers(Track track) throws InterruptedException {
|
||||
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()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
writeMarker(marker);
|
||||
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndMarkers() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMarker(Marker marker) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<wpt " + formatLocation(marker.getLatitude(), marker.getLongitude()) + ">");
|
||||
@@ -142,17 +243,6 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMultiTrackBegin() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMultiTrackEnd() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginTrack(Track track, TrackPoint startTrackPoint) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<trk>");
|
||||
@@ -167,28 +257,24 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndTrack(Track track, TrackPoint endTrackPoint) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</trk>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOpenSegment() {
|
||||
printWriter.println("<trkseg>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCloseSegment() {
|
||||
printWriter.println("</trkseg>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
||||
if (printWriter != null) {
|
||||
String coordinates = trackPoint.hasLocation() ? " " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) : "";
|
||||
printWriter.println("<trkpt " + coordinates + ">");
|
||||
|
||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
||||
|
||||
if (trackPoint.hasAltitude()) {
|
||||
printWriter.println("<ele>" + ELEVATION_FORMAT.format(trackPoint.getAltitude()) + "</ele>");
|
||||
@@ -208,7 +294,7 @@ public class GpxTrackWriter implements TrackWriter {
|
||||
}
|
||||
|
||||
if (trackPoint.hasCyclingCadence()) {
|
||||
printWriter.println("<gpxtpx:cad>" + HEARTRATE_FORMAT.format(trackPoint.getCyclingCadence_rpm()) + "</gpxtpx:cad>");
|
||||
printWriter.println("<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCyclingCadence_rpm()) + "</gpxtpx:cad>");
|
||||
}
|
||||
|
||||
if (trackPoint.hasElevationGain()) {
|
||||
+174
-44
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
@@ -13,13 +13,20 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -31,15 +38,20 @@ 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.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Write track as KML to a file.
|
||||
* Convert {@link Track} incl. {@link Marker} and {@link TrackPoint} to KML.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
public class KmlTrackWriter implements TrackWriter {
|
||||
public class KMLTrackExporter implements TrackExporter {
|
||||
|
||||
private static final String TAG = KMLTrackExporter.class.getSimpleName();
|
||||
|
||||
public static final String MARKER_STYLE = "waypoint";
|
||||
private static final String START_STYLE = "start";
|
||||
@@ -76,13 +88,7 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
|
||||
private TrackPoint startTrackPoint;
|
||||
|
||||
/**
|
||||
* @param context the context
|
||||
* @param exportTrackDetail should detailed information about the track be exported (e.g., title, description, markers, timing)?
|
||||
* @param exportSensorData should {@link TrackPoint}'s sensor data be exported?
|
||||
* @param exportPhotos should pictures be exported (if true: exports to KMZ)?
|
||||
*/
|
||||
public KmlTrackWriter(Context context, boolean exportTrackDetail, boolean exportSensorData, boolean exportPhotos) {
|
||||
public KMLTrackExporter(Context context, boolean exportTrackDetail, boolean exportSensorData, boolean exportPhotos) {
|
||||
this.context = context;
|
||||
this.exportTrackDetail = exportTrackDetail;
|
||||
this.exportSensorData = exportSensorData;
|
||||
@@ -91,21 +97,137 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
this.contentProviderUtils = new ContentProviderUtils(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(OutputStream outputStream) {
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
writeHeader(tracks);
|
||||
for (Track track : tracks) {
|
||||
writeMarkers(track);
|
||||
}
|
||||
boolean hasMultipleTracks = tracks.length > 1;
|
||||
if (hasMultipleTracks) {
|
||||
writeMultiTrackBegin();
|
||||
}
|
||||
//TODO Why use startTime of first track for the others?
|
||||
Instant startTime = tracks[0].getTrackStatistics().getStartTime();
|
||||
for (Track track : tracks) {
|
||||
Duration offset = Duration.between(track.getTrackStatistics().getStartTime(), startTime);
|
||||
writeLocations(track, offset);
|
||||
}
|
||||
if (hasMultipleTracks) {
|
||||
writeMultiTrackEnd();
|
||||
}
|
||||
writeFooter();
|
||||
close();
|
||||
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMarkers(Track track) throws InterruptedException {
|
||||
boolean hasMarkers = false;
|
||||
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()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (!hasMarkers) {
|
||||
writeBeginMarkers(track);
|
||||
hasMarkers = true;
|
||||
}
|
||||
Marker marker = contentProviderUtils.createMarker(cursor);
|
||||
writeMarker(marker);
|
||||
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasMarkers) {
|
||||
writeEndMarkers();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLocations(Track track, Duration offset) throws InterruptedException {
|
||||
boolean wroteTrack = false;
|
||||
boolean wroteSegment = false;
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
|
||||
TrackPoint trackPoint = trackPointIterator.next();
|
||||
setLocationTime(trackPoint, offset);
|
||||
|
||||
if (!wroteTrack) {
|
||||
writeBeginTrack(track, trackPoint);
|
||||
wroteTrack = true;
|
||||
}
|
||||
|
||||
switch (trackPoint.getType()) {
|
||||
case SEGMENT_START_MANUAL:
|
||||
case SEGMENT_START_AUTOMATIC:
|
||||
if (wroteSegment) writeCloseSegment();
|
||||
writeOpenSegment();
|
||||
writeTrackPoint(trackPoint);
|
||||
wroteSegment = true;
|
||||
break;
|
||||
case SEGMENT_END_MANUAL:
|
||||
if (!wroteSegment) writeOpenSegment();
|
||||
writeTrackPoint(trackPoint);
|
||||
writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
break;
|
||||
case TRACKPOINT:
|
||||
if (!wroteSegment) {
|
||||
// Might happen for older data (pre v3.15.0)
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
}
|
||||
writeTrackPoint(trackPoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wroteSegment) {
|
||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||
// Anyhow, make sure that the last segment is closed.
|
||||
writeCloseSegment();
|
||||
}
|
||||
|
||||
if (wroteTrack) {
|
||||
TrackPoint lastValidTrackPoint = contentProviderUtils.getLastValidTrackPoint(track.getId());
|
||||
setLocationTime(lastValidTrackPoint, offset);
|
||||
writeEndTrack(track, lastValidTrackPoint);
|
||||
} else {
|
||||
// Write an empty track
|
||||
writeBeginTrack(track, null);
|
||||
writeEndTrack(track, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void prepare(OutputStream outputStream) {
|
||||
this.printWriter = new PrintWriter(outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
@VisibleForTesting
|
||||
void close() {
|
||||
if (printWriter != null) {
|
||||
printWriter.flush();
|
||||
printWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(Track[] tracks) {
|
||||
private void writeHeader(Track[] tracks) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
printWriter.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\"");
|
||||
@@ -141,16 +263,14 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFooter() {
|
||||
private void writeFooter() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</Document>");
|
||||
printWriter.println("</kml>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginMarkers(Track track) {
|
||||
private void writeBeginMarkers(Track track) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<Folder>");
|
||||
if (exportTrackDetail) {
|
||||
@@ -160,15 +280,7 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndMarkers() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</Folder>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMarker(Marker marker) {
|
||||
private void writeMarker(Marker marker) {
|
||||
if (printWriter != null && exportTrackDetail) {
|
||||
boolean existsPhoto = FileUtils.buildInternalPhotoFile(context, marker.getTrackId(), marker.getPhotoURI()) != null;
|
||||
if (marker.hasPhoto() && exportPhotos && existsPhoto) {
|
||||
@@ -180,7 +292,13 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMultiTrackBegin() {
|
||||
private void writeEndMarkers() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</Folder>");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMultiTrackBegin() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<Folder id=tour>");
|
||||
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
||||
@@ -188,14 +306,13 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMultiTrackEnd() {
|
||||
private void writeMultiTrackEnd() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</Folder>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBeginTrack(Track track, TrackPoint startTrackPoint) {
|
||||
private void writeBeginTrack(Track track, TrackPoint startTrackPoint) {
|
||||
this.startTrackPoint = startTrackPoint;
|
||||
if (printWriter != null) {
|
||||
String name = context.getString(R.string.marker_label_start, track.getName());
|
||||
@@ -218,8 +335,8 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndTrack(Track track, TrackPoint endTrackPoint) {
|
||||
|
||||
private void writeEndTrack(Track track, TrackPoint endTrackPoint) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("</gx:MultiTrack>");
|
||||
printWriter.println("</Placemark>");
|
||||
@@ -233,8 +350,8 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOpenSegment() {
|
||||
@VisibleForTesting
|
||||
void writeOpenSegment() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<gx:Track>");
|
||||
speedList.clear();
|
||||
@@ -246,8 +363,8 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCloseSegment() {
|
||||
@VisibleForTesting
|
||||
void writeCloseSegment() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<ExtendedData>");
|
||||
printWriter.println("<SchemaData schemaUrl=\"#" + SCHEMA_ID + "\">");
|
||||
@@ -277,8 +394,8 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
||||
@VisibleForTesting
|
||||
void writeTrackPoint(TrackPoint trackPoint) {
|
||||
if (printWriter != null) {
|
||||
if (exportTrackDetail) {
|
||||
printWriter.println("<when>" + getTime(trackPoint.getLocation()) + "</when>");
|
||||
@@ -351,14 +468,14 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
printWriter.println("<name>" + StringUtils.formatCData(marker.getName()) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(marker.getDescription()) + "</description>");
|
||||
printWriter.print("<Camera>");
|
||||
printWriter.print("<longitude>" + marker.getLocation().getLongitude() + "</longitude>");
|
||||
printWriter.print("<latitude>" + marker.getLocation().getLatitude() + "</latitude>");
|
||||
printWriter.print("<longitude>" + marker.getLongitude() + "</longitude>");
|
||||
printWriter.print("<latitude>" + marker.getLatitude() + "</latitude>");
|
||||
printWriter.print("<altitude>20</altitude>");
|
||||
printWriter.print("<heading>" + heading + "</heading>");
|
||||
printWriter.print("<tilt>90</tilt>");
|
||||
printWriter.println("</Camera>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(marker.getLocation()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + KmlTrackWriter.MARKER_STYLE + "</styleUrl>");
|
||||
printWriter.println("<styleUrl>#" + MARKER_STYLE + "</styleUrl>");
|
||||
writeCategory(marker.getCategory());
|
||||
|
||||
if (exportPhotos) {
|
||||
@@ -474,4 +591,17 @@ public class KmlTrackWriter implements TrackWriter {
|
||||
printWriter.println("<displayName>" + StringUtils.formatCData(extendedDataType) + "</displayName>");
|
||||
printWriter.println("</gx:SimpleArrayField>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a trackPoint time.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
* @param offset the time offset
|
||||
*/
|
||||
//TODO Why?
|
||||
private void setLocationTime(TrackPoint trackPoint, Duration offset) {
|
||||
if (trackPoint != null) {
|
||||
trackPoint.setTime(trackPoint.getTime().minus(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,19 +50,12 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
private final FileTrackExporter fileTrackExporter;
|
||||
private final KMLTrackExporter fileTrackExporter;
|
||||
|
||||
private final boolean exportPhotos;
|
||||
private final Context context;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context the context
|
||||
* @param contentProviderUtils the content provider utils
|
||||
* @param trackExporter the file track exporter
|
||||
*/
|
||||
public KmzTrackExporter(Context context, ContentProviderUtils contentProviderUtils, FileTrackExporter trackExporter, boolean exportPhotos) {
|
||||
public KmzTrackExporter(Context context, ContentProviderUtils contentProviderUtils, KMLTrackExporter trackExporter, boolean exportPhotos) {
|
||||
this.context = context;
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
this.fileTrackExporter = trackExporter;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
|
||||
/**
|
||||
* Interface for writing tracks to a file. The expected sequence of calls is:
|
||||
*
|
||||
* <pre>
|
||||
* {@link #prepare(OutputStream)}
|
||||
* {@link #writeHeader(Track[])}
|
||||
* For each track:
|
||||
* {@link #writeBeginMarkers(Track)}
|
||||
* For each marker:
|
||||
* {@link #writeMarker(Marker)}
|
||||
* {@link #writeEndMarkers()}
|
||||
* {@link #writeMultiTrackBegin()}
|
||||
* For each track:
|
||||
* {@link #writeBeginTrack(Track, TrackPoint)}
|
||||
* For each segment:
|
||||
* {@link #writeOpenSegment()}
|
||||
* For each trackPoint in the segment:
|
||||
* {@link #writeTrackPoint(TrackPoint)}
|
||||
* {@link #writeCloseSegment()}
|
||||
* {@link #writeEndTrack(Track, TrackPoint)}
|
||||
* {@link #writeMultiTrackEnd()}
|
||||
* {@link #writeFooter()}
|
||||
* {@link #close()}
|
||||
* </pre>
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public interface TrackWriter {
|
||||
|
||||
void prepare(OutputStream outputStream);
|
||||
|
||||
/**
|
||||
* Closes the output stream.
|
||||
*/
|
||||
void close();
|
||||
|
||||
void writeHeader(Track[] tracks);
|
||||
|
||||
void writeFooter();
|
||||
|
||||
void writeBeginMarkers(Track track);
|
||||
|
||||
void writeEndMarkers();
|
||||
|
||||
void writeMarker(Marker marker);
|
||||
|
||||
void writeMultiTrackBegin();
|
||||
|
||||
void writeMultiTrackEnd();
|
||||
|
||||
void writeBeginTrack(Track track, TrackPoint startTrackPoint);
|
||||
|
||||
void writeEndTrack(Track track, TrackPoint endTrackPoint);
|
||||
|
||||
void writeOpenSegment();
|
||||
|
||||
void writeCloseSegment();
|
||||
|
||||
void writeTrackPoint(TrackPoint trackPoint);
|
||||
}
|
||||
+2
-7
@@ -36,7 +36,6 @@ import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
@@ -121,11 +120,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
@Override
|
||||
public Track.Id importFile(InputStream inputStream) {
|
||||
try {
|
||||
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
saxParser.parse(inputStream, this);
|
||||
Log.d(TAG, "Total import time: " + (System.currentTimeMillis() - start) + "ms");
|
||||
SAXParserFactory.newInstance().newSAXParser().parse(inputStream, this);
|
||||
return trackIds.get(0);
|
||||
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||
Log.e(TAG, "Unable to import file", e);
|
||||
@@ -375,7 +370,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
||||
*/
|
||||
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
||||
float speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / timeDifference.toMillis();
|
||||
trackPoint.setSpeed((float) speed);
|
||||
trackPoint.setSpeed(speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
/**
|
||||
* Imports a GPX file.
|
||||
* Uses https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd
|
||||
* <p>
|
||||
* {@link de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter} does not export information if a segment was started automatic or manually.
|
||||
* Therefore, all segments starts are marked as SEGMENT_START_AUTOMATIC.
|
||||
* Thus, the {@link de.dennisguse.opentracks.stats.TrackStatistics} cannot be restored correctly.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
@@ -200,9 +204,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
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);
|
||||
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||
}
|
||||
insertTrackPoint(trackPoint);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.ArrayList;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KmlTrackWriter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
|
||||
|
||||
/**
|
||||
* Imports a KML file.
|
||||
@@ -39,7 +39,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
|
||||
private static final String TAG = KmlFileTrackImporter.class.getSimpleName();
|
||||
|
||||
private static final String MARKER_STYLE = "#" + KmlTrackWriter.MARKER_STYLE;
|
||||
private static final String MARKER_STYLE = "#" + KMLTrackExporter.MARKER_STYLE;
|
||||
|
||||
private static final String TAG_COORDINATES = "coordinates";
|
||||
private static final String TAG_DESCRIPTION = "description";
|
||||
@@ -306,22 +306,22 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
}
|
||||
}
|
||||
switch (extendedDataType) {
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_SPEED:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_SPEED:
|
||||
speedList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_POWER:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_POWER:
|
||||
powerList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_HEART_RATE:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_HEART_RATE:
|
||||
heartRateList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_CADENCE:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_CADENCE:
|
||||
cadenceList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_ELEVATION_GAIN:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_ELEVATION_GAIN:
|
||||
elevationGainList.add(value);
|
||||
break;
|
||||
case KmlTrackWriter.EXTENDED_DATA_TYPE_ELEVATION_LOSS:
|
||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_ELEVATION_LOSS:
|
||||
elevationLossList.add(value);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -35,7 +35,7 @@ public class ExportUtils {
|
||||
}
|
||||
|
||||
public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
|
||||
TrackExporter trackExporter = trackFileFormat.newTrackExporter(context);
|
||||
TrackExporter trackExporter = trackFileFormat.createTrackExporter(context);
|
||||
|
||||
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory);
|
||||
if (exportDocumentFileUri == null) {
|
||||
|
||||
Reference in New Issue
Block a user