KML export: write close tag for last segment.

Closes #21.
This commit is contained in:
Dennis Guse
2019-08-10 14:00:38 +02:00
parent 617ee719c8
commit cd267123e7
5 changed files with 27 additions and 44 deletions
@@ -6,6 +6,7 @@ import android.os.Parcelable;
import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter; import de.dennisguse.opentracks.io.file.exporter.GpxTrackWriter;
import de.dennisguse.opentracks.io.file.exporter.KmlTrackWriter; import de.dennisguse.opentracks.io.file.exporter.KmlTrackWriter;
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
import de.dennisguse.opentracks.io.file.exporter.TrackWriter; import de.dennisguse.opentracks.io.file.exporter.TrackWriter;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
@@ -53,8 +53,7 @@ public class FileTrackExporter implements TrackExporter {
* @param trackWriter the track writer * @param trackWriter the track writer
* @param trackExporterListener the track export listener * @param trackExporterListener the track export listener
*/ */
public FileTrackExporter(ContentProviderUtils contentProviderUtils, Track[] tracks, public FileTrackExporter(ContentProviderUtils contentProviderUtils, Track[] tracks, TrackWriter trackWriter, TrackExporterListener trackExporterListener) {
TrackWriter trackWriter, TrackExporterListener trackExporterListener) {
this.contentProviderUtils = contentProviderUtils; this.contentProviderUtils = contentProviderUtils;
this.tracks = tracks; this.tracks = tracks;
this.trackWriter = trackWriter; this.trackWriter = trackWriter;
@@ -95,8 +94,7 @@ public class FileTrackExporter implements TrackExporter {
* load them into objects all at the same time. * load them into objects all at the same time.
*/ */
boolean hasWaypoints = false; boolean hasWaypoints = false;
try (Cursor cursor = contentProviderUtils.getWaypointCursor( try (Cursor cursor = contentProviderUtils.getWaypointCursor(track.getId(), -1L, Constants.MAX_LOADED_WAYPOINTS_POINTS)) {
track.getId(), -1L, Constants.MAX_LOADED_WAYPOINTS_POINTS)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
/* /*
* Yes, this will skip the first waypoint and that is intentional as the * Yes, this will skip the first waypoint and that is intentional as the
@@ -132,8 +130,7 @@ public class FileTrackExporter implements TrackExporter {
LocationIterator locationIterator = null; LocationIterator locationIterator = null;
try { try {
locationIterator = contentProviderUtils.getTrackPointLocationIterator( locationIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false, locationFactory);
track.getId(), -1L, false, locationFactory);
while (locationIterator.hasNext()) { while (locationIterator.hasNext()) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
@@ -177,6 +174,11 @@ public class FileTrackExporter implements TrackExporter {
isLastLocationValid = isLocationValid; isLastLocationValid = isLocationValid;
} }
if (wroteSegment) {
//Close the last segment
trackWriter.writeCloseSegment();
}
if (wroteTrack) { if (wroteTrack) {
Location lastValidTrackPoint = contentProviderUtils.getLastValidTrackPoint(track.getId()); Location lastValidTrackPoint = contentProviderUtils.getLastValidTrackPoint(track.getId());
setLocationTime(lastValidTrackPoint, offset); setLocationTime(lastValidTrackPoint, offset);
@@ -56,16 +56,11 @@ public class KmlTrackWriter implements TrackWriter {
private static final String HEART_RATE = "heart_rate"; private static final String HEART_RATE = "heart_rate";
private static final String POWER = "power"; private static final String POWER = "power";
private static final String private static final String WAYPOINT_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png";
WAYPOINT_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png"; private static final String STATISTICS_ICON = "http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png";
private static final String private static final String START_ICON = "http://maps.google.com/mapfiles/kml/paddle/grn-circle.png";
STATISTICS_ICON = "http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"; private static final String END_ICON = "http://maps.google.com/mapfiles/kml/paddle/red-circle.png";
private static final String private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
START_ICON = "http://maps.google.com/mapfiles/kml/paddle/grn-circle.png";
private static final String
END_ICON = "http://maps.google.com/mapfiles/kml/paddle/red-circle.png";
private static final String
TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
private final Context context; private final Context context;
private final boolean multiple; private final boolean multiple;
@@ -124,9 +119,7 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.println("<visibility>1</visibility>"); printWriter.println("<visibility>1</visibility>");
Track track = tracks[0]; Track track = tracks[0];
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<atom:author><atom:name>" printWriter.println("<atom:author><atom:name>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:name></atom:author>");
+ StringUtils.formatCData(context.getString(R.string.app_name))
+ "</atom:name></atom:author>");
writeTrackStyle(); writeTrackStyle();
writePlacemarkerStyle(START_STYLE, START_ICON, 32, 1); writePlacemarkerStyle(START_STYLE, START_ICON, 32, 1);
writePlacemarkerStyle(END_STYLE, END_ICON, 32, 1); writePlacemarkerStyle(END_STYLE, END_ICON, 32, 1);
@@ -151,9 +144,7 @@ public class KmlTrackWriter implements TrackWriter {
@Override @Override
public void writeBeginWaypoints(Track track) { public void writeBeginWaypoints(Track track) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("<Folder><name>" printWriter.println("<Folder><name>" + StringUtils.formatCData(context.getString(R.string.track_markers, track.getName())) + "</name>");
+ StringUtils.formatCData(context.getString(R.string.track_markers, track.getName()))
+ "</name>");
printWriter.println("<open>1</open>"); printWriter.println("<open>1</open>");
} }
} }
@@ -258,8 +249,7 @@ public class KmlTrackWriter implements TrackWriter {
@Override @Override
public void writeLocation(Location location) { public void writeLocation(Location location) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println( printWriter.println("<when>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</when>");
"<when>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</when>");
printWriter.println("<gx:coord>" + getCoordinates(location, " ") + "</gx:coord>"); printWriter.println("<gx:coord>" + getCoordinates(location, " ") + "</gx:coord>");
if (location instanceof SensorDataSetLocation) { if (location instanceof SensorDataSetLocation) {
SensorDataSet sensorDataSet = ((SensorDataSetLocation) location).getSensorDataSet(); SensorDataSet sensorDataSet = ((SensorDataSetLocation) location).getSensorDataSet();
@@ -306,10 +296,8 @@ public class KmlTrackWriter implements TrackWriter {
if (location != null) { if (location != null) {
printWriter.println("<Placemark>"); printWriter.println("<Placemark>");
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
printWriter.println( printWriter.println( "<description>" + StringUtils.formatCData(description) + "</description>");
"<description>" + StringUtils.formatCData(description) + "</description>"); printWriter.println("<TimeStamp><when>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
printWriter.println("<TimeStamp><when>"
+ StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>"); printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
writeCategory(category); writeCategory(category);
printWriter.println("<Point>"); printWriter.println("<Point>");
@@ -330,13 +318,11 @@ public class KmlTrackWriter implements TrackWriter {
* @param photoUrl the photo url * @param photoUrl the photo url
* @param heading the heading * @param heading the heading
*/ */
private void writePhotoOverlay(String name, String category, String description, String styleName, private void writePhotoOverlay(String name, String category, String description, String styleName, Location location, String photoUrl, float heading) {
Location location, String photoUrl, float heading) {
if (location != null) { if (location != null) {
printWriter.println("<PhotoOverlay>"); printWriter.println("<PhotoOverlay>");
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
printWriter.println( printWriter.println( "<description>" + StringUtils.formatCData(description) + "</description>");
"<description>" + StringUtils.formatCData(description) + "</description>");
printWriter.print("<Camera>"); printWriter.print("<Camera>");
printWriter.print("<longitude>" + location.getLongitude() + "</longitude>"); printWriter.print("<longitude>" + location.getLongitude() + "</longitude>");
printWriter.print("<latitude>" + location.getLatitude() + "</latitude>"); printWriter.print("<latitude>" + location.getLatitude() + "</latitude>");
@@ -344,16 +330,14 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.print("<heading>" + heading + "</heading>"); printWriter.print("<heading>" + heading + "</heading>");
printWriter.print("<tilt>90</tilt>"); printWriter.print("<tilt>90</tilt>");
printWriter.println("</Camera>"); printWriter.println("</Camera>");
printWriter.println("<TimeStamp><when>" printWriter.println("<TimeStamp><when>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
+ StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>"); printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
writeCategory(category); writeCategory(category);
if (playTrack) { if (playTrack) {
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>"); printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
} else { } else {
Uri uri = Uri.parse(photoUrl); Uri uri = Uri.parse(photoUrl);
printWriter.println("<Icon><href>" + KmzTrackExporter.KMZ_IMAGES_DIR + File.separatorChar printWriter.println("<Icon><href>" + KmzTrackExporter.KMZ_IMAGES_DIR + File.separatorChar + uri.getLastPathSegment() + "</href></Icon>");
+ uri.getLastPathSegment() + "</href></Icon>");
} }
printWriter.print("<ViewVolume>"); printWriter.print("<ViewVolume>");
@@ -411,8 +395,7 @@ public class KmlTrackWriter implements TrackWriter {
return; return;
} }
printWriter.println("<ExtendedData>"); printWriter.println("<ExtendedData>");
printWriter.println( printWriter.println( "<Data name=\"type\"><value>" + StringUtils.formatCData(category) + "</value></Data>");
"<Data name=\"type\"><value>" + StringUtils.formatCData(category) + "</value></Data>");
printWriter.println("</ExtendedData>"); printWriter.println("</ExtendedData>");
} }
@@ -441,8 +424,7 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.println("<Style id=\"" + name + "\"><IconStyle>"); printWriter.println("<Style id=\"" + name + "\"><IconStyle>");
printWriter.println("<scale>1.3</scale>"); printWriter.println("<scale>1.3</scale>");
printWriter.println("<Icon><href>" + url + "</href></Icon>"); printWriter.println("<Icon><href>" + url + "</href></Icon>");
printWriter.println( printWriter.println("<hotSpot x=\"" + x + "\" y=\"" + y + "\" xunits=\"pixels\" yunits=\"pixels\"/>");
"<hotSpot x=\"" + x + "\" y=\"" + y + "\" xunits=\"pixels\" yunits=\"pixels\"/>");
printWriter.println("</IconStyle></Style>"); printWriter.println("</IconStyle></Style>");
} }
@@ -56,10 +56,8 @@ public class KmzTrackExporter implements TrackExporter {
* @param contentProviderUtils the content provider utils * @param contentProviderUtils the content provider utils
* @param fileTrackExporter the file track exporter * @param fileTrackExporter the file track exporter
* @param tracks the tracks to export * @param tracks the tracks to export
* @param context the context
*/ */
public KmzTrackExporter(ContentProviderUtils contentProviderUtils, public KmzTrackExporter(ContentProviderUtils contentProviderUtils, FileTrackExporter fileTrackExporter, Track[] tracks) {
FileTrackExporter fileTrackExporter, Track[] tracks, Context context) {
this.contentProviderUtils = contentProviderUtils; this.contentProviderUtils = contentProviderUtils;
this.fileTrackExporter = fileTrackExporter; this.fileTrackExporter = fileTrackExporter;
this.tracks = tracks; this.tracks = tracks;
@@ -198,7 +198,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
} }
}); });
TrackExporter trackExporter = useKmz ? new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, context) : fileTrackExporter; TrackExporter trackExporter = useKmz ? new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks) : fileTrackExporter;
String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension); String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension);
File file = new File(directory, fileName); File file = new File(directory, fileName);