diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackExporterTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackExporterTest.java
index e8c8000e9..5e5d152a1 100644
--- a/src/androidTest/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackExporterTest.java
+++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/exporter/KmlTrackExporterTest.java
@@ -28,14 +28,14 @@ public class KmlTrackExporterTest {
@Test
public void writeCloseSegment_only_write_sensordata_if_present() {
String expected = "1970-01-01T00:00:00Z\n" +
- "\n" +
+ "\n" +
"1970-01-01T01:00:00+01:00\n" +
- "\n" +
+ "\n" +
"\n" +
"\n" +
"\n" +
"\n" +
- "\n";
+ "\n";
// given
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0));
diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java
index 304f52b4e..9ee6bfd0b 100644
--- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java
+++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java
@@ -44,7 +44,8 @@ import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.StringUtils;
/**
- * Convert {@link Track} incl. {@link Marker} and {@link TrackPoint} to KML.
+ * Convert {@link Track} incl. {@link Marker} and {@link TrackPoint} to KML version 2.3.
+ * https://docs.opengeospatial.org/is/12-007r2/12-007r2.html
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
@@ -58,6 +59,8 @@ public class KMLTrackExporter implements TrackExporter {
private static final String TRACK_STYLE = "track";
private static final String SCHEMA_ID = "schema";
+ public static final String EXTENDED_DATA_TYPE_CATEGORY = "type";
+
public static final String EXTENDED_DATA_TYPE_SPEED = "speed";
public static final String EXTENDED_DATA_TYPE_DISTANCE = "distance";
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
@@ -224,11 +227,13 @@ public class KMLTrackExporter implements TrackExporter {
private void writeHeader(Track[] tracks) {
if (printWriter != null) {
printWriter.println("");
- printWriter.println("");
- //TODO ADD xsi:schemaLocation here!
+ //TODO ADD xsi:schemaLocation for atom
+ printWriter.println("xsi:schemaLocation=" +
+ "\"http://www.opengis.net/kml/2.3 http://schemas.opengis.net/kml/2.3/ogckml23.xsd"
+ + " http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd\">");
printWriter.println("");
printWriter.println("1");
@@ -309,16 +314,16 @@ public class KMLTrackExporter implements TrackExporter {
printWriter.println("#" + TRACK_STYLE + "");
writeCategory(track.getCategory());
- printWriter.println("");
+ printWriter.println("");
printWriter.println("absolute");
- printWriter.println("1");
+ printWriter.println("1");
}
}
private void writeEndTrack() {
if (printWriter != null) {
- printWriter.println("");
+ printWriter.println("");
printWriter.println("");
}
}
@@ -326,7 +331,7 @@ public class KMLTrackExporter implements TrackExporter {
@VisibleForTesting
void writeOpenSegment() {
if (printWriter != null) {
- printWriter.println("");
+ printWriter.println("");
+ printWriter.println("");
}
}
@@ -383,9 +388,9 @@ public class KMLTrackExporter implements TrackExporter {
printWriter.println("" + getTime(zoneOffset, trackPoint.getLocation()) + "");
if (trackPoint.hasLocation()) {
- printWriter.println("" + getCoordinates(trackPoint.getLocation(), " ") + "");
+ printWriter.println("" + getCoordinates(trackPoint.getLocation(), " ") + "");
} else {
- printWriter.println("");
+ printWriter.println("");
}
speedList.add(trackPoint.hasSpeed() ? (float) trackPoint.getSpeed().toMPS() : null);
@@ -408,16 +413,16 @@ public class KMLTrackExporter implements TrackExporter {
* @param name the name of the simple array data
*/
private void writeSimpleArrayData(List list, String name) {
- printWriter.println("");
+ printWriter.println("");
for (int i = 0; i < list.size(); i++) {
Float value = list.get(i);
if (value == null) {
- printWriter.println("");
+ printWriter.println("");
} else {
- printWriter.println("" + SENSOR_DATA_FORMAT.format(value) + "");
+ printWriter.println("" + SENSOR_DATA_FORMAT.format(value) + "");
}
}
- printWriter.println("");
+ printWriter.println("");
}
/**
@@ -521,7 +526,7 @@ public class KMLTrackExporter implements TrackExporter {
return;
}
printWriter.println("");
- printWriter.println("" + StringUtils.formatCData(category) + "");
+ printWriter.println("" + StringUtils.formatCData(category) + "");
printWriter.println("");
}
@@ -554,8 +559,8 @@ public class KMLTrackExporter implements TrackExporter {
* @param extendedDataType the extended data display name
*/
private void writeSimpleArrayStyle(String name, String extendedDataType) {
- printWriter.println("");
+ printWriter.println("");
printWriter.println("" + StringUtils.formatCData(extendedDataType) + "");
- printWriter.println("");
+ printWriter.println("");
}
}
diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java
index 0def1c475..19b6be926 100644
--- a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java
+++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java
@@ -41,7 +41,7 @@ import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
import de.dennisguse.opentracks.util.StringUtils;
/**
- * Imports a KML file.
+ * Imports a KML file; preferred version: KML2.3, but also supports KML2.2.
*
* @author Jimmy Shih
*/
@@ -54,18 +54,31 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
private static final String TAG_COORDINATES = "coordinates";
private static final String TAG_DESCRIPTION = "description";
private static final String TAG_ICON = "icon";
- private static final String TAG_GX_COORD = "gx:coord";
- private static final String TAG_GX_MULTI_TRACK = "gx:MultiTrack";
- private static final String TAG_GX_SIMPLE_ARRAY_DATA = "gx:SimpleArrayData";
- private static final String TAG_GX_TRACK = "gx:Track";
- private static final String TAG_GX_VALUE = "gx:value";
+
+ private static final String TAG_COORD = "coord";
+ private static final String TAG_KML22_COORD = "gx:coord";
+
+ private static final String TAG_MULTI_TRACK = "MultiTrack";
+ private static final String TAG_KML22_MULTI_TRACK = "gx:MultiTrack";
+
+ private static final String TAG_DATA_CATEGORY = "Data"; //used for Track.category
+
+ private static final String TAG_SIMPLE_ARRAY_DATA = "SimpleArrayData";
+ private static final String TAG_KML22_SIMPLE_ARRAY_DATA = "gx:SimpleArrayData";
+
+ private static final String TAG_TRACK = "Track";
+ private static final String TAG_KML22_TRACK = "gx:Track";
+
+ private static final String TAG_VALUE = "value";
+ private static final String TAG_KML22_VALUE = "gx:value";
+
private static final String TAG_HREF = "href";
private static final String TAG_KML = "kml";
private static final String TAG_NAME = "name";
private static final String TAG_PHOTO_OVERLAY = "PhotoOverlay";
private static final String TAG_PLACEMARK = "Placemark";
private static final String TAG_STYLE_URL = "styleUrl";
- private static final String TAG_VALUE = "value";
+ // private static final String TAG_VALUE = "value"; TODO
private static final String TAG_WHEN = "when";
private static final String TAG_UUID = "opentracks:trackid";
@@ -81,7 +94,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
private final ArrayList whenList = new ArrayList<>();
private final ArrayList locationList = new ArrayList<>();
- private String extendedDataType;
+ private String dataType;
private final ArrayList sensorSpeedList = new ArrayList<>();
private final ArrayList sensorDistanceList = new ArrayList<>();
private final ArrayList sensorCadenceList = new ArrayList<>();
@@ -128,17 +141,21 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
// Note that a track is contained in a Placemark, calling onMarkerStart will clear various track variables like name, category, and description.
onMarkerStart();
break;
- case TAG_GX_MULTI_TRACK:
+ case TAG_MULTI_TRACK:
+ case TAG_KML22_MULTI_TRACK:
trackImporter.newTrack();
break;
- case TAG_GX_TRACK:
+ case TAG_TRACK:
+ case TAG_KML22_TRACK:
if (trackImporter == null) {
- throw new SAXException("No " + TAG_GX_MULTI_TRACK);
+ throw new SAXException("Missing " + TAG_MULTI_TRACK);
}
onTrackSegmentStart();
break;
- case TAG_GX_SIMPLE_ARRAY_DATA:
- onExtendedDataStart(attributes);
+ case TAG_DATA_CATEGORY:
+ case TAG_SIMPLE_ARRAY_DATA:
+ case TAG_KML22_SIMPLE_ARRAY_DATA:
+ dataType = attributes.getValue(ATTRIBUTE_NAME);
break;
}
}
@@ -162,18 +179,28 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
case TAG_COORDINATES:
onMarkerLocationEnd();
break;
- case TAG_GX_MULTI_TRACK:
+ case TAG_MULTI_TRACK:
+ case TAG_KML22_MULTI_TRACK:
trackImporter.setTrack(context, name, uuid, description, category, icon, zoneOffset);
zoneOffset = null;
break;
- case TAG_GX_TRACK:
+ case TAG_TRACK:
+ case TAG_KML22_TRACK:
onTrackSegmentEnd();
break;
- case TAG_GX_COORD:
+ case TAG_COORD:
+ case TAG_KML22_COORD:
onCoordEnded();
break;
- case TAG_GX_VALUE:
- onExtendedDataValueEnd();
+ case TAG_VALUE:
+ case TAG_KML22_VALUE:
+ if (KMLTrackExporter.EXTENDED_DATA_TYPE_CATEGORY.equals(dataType)) {
+ if (content != null) {
+ category = content.trim();
+ }
+ } else {
+ onExtendedDataValueEnd();
+ }
break;
case TAG_NAME:
if (content != null) {
@@ -195,11 +222,6 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
icon = content.trim();
}
break;
- case TAG_VALUE:
- if (content != null) {
- category = content.trim();
- }
- break;
case TAG_WHEN:
if (content != null) {
try {
@@ -401,11 +423,6 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
return location;
}
-
- private void onExtendedDataStart(Attributes attributes) {
- extendedDataType = attributes.getValue(ATTRIBUTE_NAME);
- }
-
private void onExtendedDataValueEnd() throws SAXException {
Float value = null;
if (content != null) {
@@ -414,11 +431,11 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
try {
value = Float.parseFloat(content);
} catch (NumberFormatException e) {
- throw new SAXException(createErrorMessage("Unable to parse gx:value:" + content), e);
+ throw new SAXException(createErrorMessage("Unable to parse value:" + content), e);
}
}
}
- switch (extendedDataType) {
+ switch (dataType) {
case KMLTrackExporter.EXTENDED_DATA_TYPE_SPEED:
sensorSpeedList.add(value);
break;
@@ -447,7 +464,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
accuracyVertical.add(value);
break;
default:
- Log.w(TAG, "Data from extended data " + extendedDataType + " is not (yet) supported.");
+ Log.w(TAG, "Data from extended data " + dataType + " is not (yet) supported.");
}
}