forked from upstream-mirrors/OpenTracks
File formats: removed CSV and TCX.
This commit is contained in:
-90
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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 com.google.android.apps.mytracks.io.file.exporter;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.CsvTrackWriter;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link CsvTrackWriter}.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class CsvTrackWriterTest extends TrackWriterTest {
|
|
||||||
|
|
||||||
private static final String BEGIN_TAG = "\"";
|
|
||||||
private static final String END_TAG = "\"\n";
|
|
||||||
private static final String SEPARATOR = "\",\"";
|
|
||||||
|
|
||||||
public void testCsvOutput() throws Exception {
|
|
||||||
String expectedTrackHeader = getExpectedLine(
|
|
||||||
"Name", "Activity type", "Description");
|
|
||||||
String expectedTrack = getExpectedLine(TRACK_NAME, TRACK_CATEGORY, TRACK_DESCRIPTION);
|
|
||||||
String expectedMarkerHeader = getExpectedLine("Name",
|
|
||||||
"Marker type",
|
|
||||||
"Description",
|
|
||||||
"Latitude (deg)",
|
|
||||||
"Longitude (deg)",
|
|
||||||
"Altitude (m)",
|
|
||||||
"Bearing (deg)",
|
|
||||||
"Accuracy (m)",
|
|
||||||
"Speed (m/s)",
|
|
||||||
"Time");
|
|
||||||
String expectedMarker1 = getExpectedLine(WAYPOINT1_NAME, WAYPOINT1_CATEGORY,
|
|
||||||
WAYPOINT1_DESCRIPTION, "1.0", "-1.0", "10.0", "100.0", "1,000", "10,000",
|
|
||||||
"1970-01-01T00:01:40.000Z");
|
|
||||||
String expectedMarker2 = getExpectedLine(WAYPOINT2_NAME, WAYPOINT2_CATEGORY,
|
|
||||||
WAYPOINT2_DESCRIPTION, "2.0", "-2.0", "20.0", "200.0", "2,000", "20,000",
|
|
||||||
"1970-01-01T00:03:20.000Z");
|
|
||||||
String expectedPointHeader = getExpectedLine("Segment", "Point", "Latitude (deg)",
|
|
||||||
"Longitude (deg)", "Altitude (m)", "Bearing (deg)", "Accuracy (m)", "Speed (m/s)", "Time",
|
|
||||||
"Power (W)", "Cadence (rpm)", "Heart rate (bpm)");
|
|
||||||
String expectedPoint1 = getExpectedLine("1", "1", "0.0", "0.0", "0.0", "0.0", "0", "0",
|
|
||||||
"1970-01-01T00:00:00.000Z", "100.0", "200.0", "300.0");
|
|
||||||
String expectedPoint2 = getExpectedLine("1", "2", "1.0", "-1.0", "10.0", "100.0", "1,000",
|
|
||||||
"10,000", "1970-01-01T00:01:40.000Z", "101.0", "201.0", "301.0");
|
|
||||||
String expectedPoint3 = getExpectedLine("2", "1", "2.0", "-2.0", "20.0", "200.0", "2,000",
|
|
||||||
"20,000", "1970-01-01T00:03:20.000Z", "102.0", "202.0", "302.0");
|
|
||||||
String expectedPoint4 = getExpectedLine("2", "2", "3.0", "-3.0", "30.0", "300.0", "3,000",
|
|
||||||
"30,000", "1970-01-01T00:05:00.000Z", "103.0", "203.0", "303.0");
|
|
||||||
String expected = expectedTrackHeader + expectedTrack + "\n"
|
|
||||||
+ expectedMarkerHeader + expectedMarker1 + expectedMarker2 + "\n"
|
|
||||||
+ expectedPointHeader + expectedPoint1 + expectedPoint2 + expectedPoint3 + expectedPoint4;
|
|
||||||
|
|
||||||
CsvTrackWriter csvTrackWriter = new CsvTrackWriter(getContext());
|
|
||||||
assertEquals(expected, writeTrack(csvTrackWriter));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the expected CSV line from a list of expected values.
|
|
||||||
*
|
|
||||||
* @param values expected values
|
|
||||||
*/
|
|
||||||
private String getExpectedLine(String... values) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append(BEGIN_TAG);
|
|
||||||
boolean first = true;
|
|
||||||
for (String value : values) {
|
|
||||||
if (!first) {
|
|
||||||
builder.append(SEPARATOR);
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
builder.append(value);
|
|
||||||
}
|
|
||||||
builder.append(END_TAG);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-97
@@ -1,97 +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 com.google.android.apps.mytracks.io.file.exporter;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.TcxTrackWriter;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link TcxTrackWriter}.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
public class TcxTrackWriterTest extends TrackWriterTest {
|
|
||||||
|
|
||||||
public void testXmlOutput() throws Exception {
|
|
||||||
TcxTrackWriter tcxTrackWriter = new TcxTrackWriter(getContext());
|
|
||||||
String result = writeTrack(tcxTrackWriter);
|
|
||||||
Document doc = parseXmlDocument(result);
|
|
||||||
|
|
||||||
Element root = getChildElement(doc, "TrainingCenterDatabase");
|
|
||||||
Element activitiesTag = getChildElement(root, "Activities");
|
|
||||||
Element activityTag = getChildElement(activitiesTag, "Activity");
|
|
||||||
Element lapTag = getChildElement(activityTag, "Lap");
|
|
||||||
|
|
||||||
List<Element> segmentTags = getChildElements(lapTag, "Track", 2);
|
|
||||||
Element segment1Tag = segmentTags.get(0);
|
|
||||||
Element segment2Tag = segmentTags.get(1);
|
|
||||||
List<Element> seg1PointTags = getChildElements(segment1Tag, "Trackpoint", 2);
|
|
||||||
List<Element> seg2PointTags = getChildElements(segment2Tag, "Trackpoint", 2);
|
|
||||||
assertTagsMatchPoints(seg1PointTags, location1, location2);
|
|
||||||
assertTagsMatchPoints(seg2PointTags, location3, location4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that the given tags describe the given locations in the same order.
|
|
||||||
*
|
|
||||||
* @param tags list of tags
|
|
||||||
* @param locations list of locations
|
|
||||||
*/
|
|
||||||
private void assertTagsMatchPoints(List<Element> tags, MyTracksLocation... locations) {
|
|
||||||
assertEquals(locations.length, tags.size());
|
|
||||||
for (int i = 0; i < locations.length; i++) {
|
|
||||||
assertTagMatchesLocation(tags.get(i), locations[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that the given tag describes the given location.
|
|
||||||
*
|
|
||||||
* @param tag the tag
|
|
||||||
* @param location the location
|
|
||||||
*/
|
|
||||||
private void assertTagMatchesLocation(Element tag, MyTracksLocation location) {
|
|
||||||
assertEquals(StringUtils.formatDateTimeIso8601(location.getTime()), getChildTextValue(tag, "Time"));
|
|
||||||
|
|
||||||
Element positionTag = getChildElement(tag, "Position");
|
|
||||||
assertEquals(
|
|
||||||
Double.toString(location.getLatitude()), getChildTextValue(positionTag, "LatitudeDegrees"));
|
|
||||||
assertEquals(Double.toString(location.getLongitude()),
|
|
||||||
getChildTextValue(positionTag, "LongitudeDegrees"));
|
|
||||||
|
|
||||||
assertEquals(Double.toString(location.getAltitude()), getChildTextValue(tag, "AltitudeMeters"));
|
|
||||||
assertTrue(location.getSensorDataSet() != null);
|
|
||||||
Sensor.SensorDataSet sds = location.getSensorDataSet();
|
|
||||||
|
|
||||||
List<Element> heartRate = getChildElements(tag, "HeartRateBpm", 1);
|
|
||||||
assertEquals(Integer.toString(sds.getHeartRate().getValue()),
|
|
||||||
getChildTextValue(heartRate.get(0), "Value"));
|
|
||||||
|
|
||||||
List<Element> extensions = getChildElements(tag, "Extensions", 1);
|
|
||||||
List<Element> tpx = getChildElements(extensions.get(0), "TPX", 1);
|
|
||||||
assertEquals(
|
|
||||||
Integer.toString(sds.getCadence().getValue()), getChildTextValue(tpx.get(0), "RunCadence"));
|
|
||||||
assertEquals(
|
|
||||||
Integer.toString(sds.getPower().getValue()), getChildTextValue(tpx.get(0), "Watts"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.google.android.apps.mytracks.io.file;
|
package com.google.android.apps.mytracks.io.file;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.CsvTrackWriter;
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.GpxTrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.GpxTrackWriter;
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.KmlTrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.KmlTrackWriter;
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.TcxTrackWriter;
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -27,18 +25,6 @@ public enum TrackFileFormat implements Parcelable {
|
|||||||
public TrackWriter newTrackWriter(Context context, boolean multiple, boolean playTrack) {
|
public TrackWriter newTrackWriter(Context context, boolean multiple, boolean playTrack) {
|
||||||
return new GpxTrackWriter(context);
|
return new GpxTrackWriter(context);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
CSV {
|
|
||||||
@Override
|
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple, boolean playTrack) {
|
|
||||||
return new CsvTrackWriter(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TCX {
|
|
||||||
@Override
|
|
||||||
public TrackWriter newTrackWriter(Context context, boolean multiple, boolean playTrack) {
|
|
||||||
return new TcxTrackWriter(context);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
-249
@@ -1,249 +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 com.google.android.apps.mytracks.io.file.exporter;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorData;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.location.Location;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write track as CSV to a file. See RFC 4180 for info on CSV. Output three
|
|
||||||
* tables.<br>
|
|
||||||
* The first table contains the track info. Its columns are:<br>
|
|
||||||
* "Track name","Activity type","Track description" <br>
|
|
||||||
* <br>
|
|
||||||
* The second table contains the markers. Its columns are:<br>
|
|
||||||
* "Marker name","Marker type","Marker description","Latitude (deg)","Longitude
|
|
||||||
* (deg)","Altitude (m)","Bearing (deg)","Accuracy (m)","Speed (m/s)","Time"<br>
|
|
||||||
* <br>
|
|
||||||
* The thrid table contains the points. Its columns are:<br>
|
|
||||||
* "Segment","Point","Latitude (deg)","Longitude (deg)","Altitude (m)","Bearing
|
|
||||||
* (deg)","Accuracy (m)","Speed (m/s)","Time","Power (W)","Cadence (rpm)","Heart
|
|
||||||
* rate (bpm)","Battery level (%)"<br>
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class CsvTrackWriter implements TrackWriter {
|
|
||||||
|
|
||||||
private static final NumberFormat SHORT_FORMAT = NumberFormat.getInstance(Locale.US);
|
|
||||||
|
|
||||||
static {
|
|
||||||
SHORT_FORMAT.setMaximumFractionDigits(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private PrintWriter printWriter;
|
|
||||||
private int segmentIndex;
|
|
||||||
private int pointIndex;
|
|
||||||
|
|
||||||
public CsvTrackWriter(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getExtension() {
|
|
||||||
return TrackFileFormat.CSV.getExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepare(OutputStream outputStream) {
|
|
||||||
printWriter = new PrintWriter(outputStream);
|
|
||||||
segmentIndex = 0;
|
|
||||||
pointIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.flush();
|
|
||||||
printWriter = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeHeader(Track[] tracks) {
|
|
||||||
writeCommaSeparatedLine(context.getString(R.string.generic_name),
|
|
||||||
context.getString(R.string.track_edit_activity_type_hint),
|
|
||||||
context.getString(R.string.generic_description));
|
|
||||||
Track track = tracks[0];
|
|
||||||
writeCommaSeparatedLine(track.getName(), track.getCategory(), track.getDescription());
|
|
||||||
writeCommaSeparatedLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeFooter() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginWaypoints(Track track) {
|
|
||||||
writeCommaSeparatedLine(context.getString(R.string.generic_name),
|
|
||||||
context.getString(R.string.marker_edit_marker_type_hint),
|
|
||||||
context.getString(R.string.generic_description),
|
|
||||||
context.getString(R.string.description_location_latitude),
|
|
||||||
context.getString(R.string.description_location_longitude),
|
|
||||||
context.getString(R.string.description_location_altitude),
|
|
||||||
context.getString(R.string.description_location_bearing),
|
|
||||||
context.getString(R.string.description_location_accuracy),
|
|
||||||
context.getString(R.string.description_location_speed),
|
|
||||||
context.getString(R.string.description_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndWaypoints() {
|
|
||||||
writeCommaSeparatedLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeWaypoint(Waypoint waypoint) {
|
|
||||||
Location location = waypoint.getLocation();
|
|
||||||
writeCommaSeparatedLine(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(),
|
|
||||||
Double.toString(location.getLatitude()), Double.toString(location.getLongitude()),
|
|
||||||
getAltitude(location), getBearing(location), getAccuracy(location), getSpeed(location),
|
|
||||||
StringUtils.formatDateTimeIso8601(location.getTime()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginTracks() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndTracks() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginTrack(Track track, Location startLocation) {
|
|
||||||
writeCommaSeparatedLine(context.getString(R.string.description_track_segment),
|
|
||||||
context.getString(R.string.description_track_point),
|
|
||||||
context.getString(R.string.description_location_latitude),
|
|
||||||
context.getString(R.string.description_location_longitude),
|
|
||||||
context.getString(R.string.description_location_altitude),
|
|
||||||
context.getString(R.string.description_location_bearing),
|
|
||||||
context.getString(R.string.description_location_accuracy),
|
|
||||||
context.getString(R.string.description_location_speed),
|
|
||||||
context.getString(R.string.description_time),
|
|
||||||
context.getString(R.string.description_sensor_power),
|
|
||||||
context.getString(R.string.description_sensor_cadence),
|
|
||||||
context.getString(R.string.description_sensor_heart_rate));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndTrack(Track track, Location endLocation) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeOpenSegment() {
|
|
||||||
segmentIndex++;
|
|
||||||
pointIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeCloseSegment() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeLocation(Location location) {
|
|
||||||
String power = null;
|
|
||||||
String cadence = null;
|
|
||||||
String heartRate = null;
|
|
||||||
if (location instanceof MyTracksLocation) {
|
|
||||||
SensorDataSet sensorDataSet = ((MyTracksLocation) location).getSensorDataSet();
|
|
||||||
|
|
||||||
if (sensorDataSet != null) {
|
|
||||||
if (sensorDataSet.hasPower()) {
|
|
||||||
SensorData sensorData = sensorDataSet.getPower();
|
|
||||||
if (sensorData.hasValue() && sensorData.getState() == Sensor.SensorState.SENDING) {
|
|
||||||
power = Double.toString(sensorData.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sensorDataSet.hasCadence()) {
|
|
||||||
SensorData sensorData = sensorDataSet.getCadence();
|
|
||||||
if (sensorData.hasValue() && sensorData.getState() == Sensor.SensorState.SENDING) {
|
|
||||||
cadence = Double.toString(sensorData.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sensorDataSet.hasHeartRate()) {
|
|
||||||
SensorData sensorData = sensorDataSet.getHeartRate();
|
|
||||||
if (sensorData.hasValue() && sensorData.getState() == Sensor.SensorState.SENDING) {
|
|
||||||
heartRate = Double.toString(sensorData.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pointIndex++;
|
|
||||||
writeCommaSeparatedLine(Integer.toString(segmentIndex), Integer.toString(pointIndex),
|
|
||||||
Double.toString(location.getLatitude()), Double.toString(location.getLongitude()),
|
|
||||||
getAltitude(location), getBearing(location), getAccuracy(location), getSpeed(location),
|
|
||||||
StringUtils.formatDateTimeIso8601(location.getTime()), power, cadence, heartRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getAltitude(Location location) {
|
|
||||||
return location.hasAltitude() ? Double.toString(location.getAltitude()) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getBearing(Location location) {
|
|
||||||
return location.hasBearing() ? Double.toString(location.getBearing()) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getAccuracy(Location location) {
|
|
||||||
return location.hasAccuracy() ? SHORT_FORMAT.format(location.getAccuracy()) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSpeed(Location location) {
|
|
||||||
return location.hasSpeed() ? SHORT_FORMAT.format(location.getSpeed()) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a single line of a CSV file.
|
|
||||||
*
|
|
||||||
* @param values the values to be written as CSV
|
|
||||||
*/
|
|
||||||
private void writeCommaSeparatedLine(String... values) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
boolean isFirst = true;
|
|
||||||
for (String value : values) {
|
|
||||||
if (!isFirst) {
|
|
||||||
builder.append(',');
|
|
||||||
}
|
|
||||||
isFirst = false;
|
|
||||||
|
|
||||||
builder.append('"');
|
|
||||||
if (value != null) {
|
|
||||||
builder.append(value.replaceAll("\"", "\"\""));
|
|
||||||
}
|
|
||||||
builder.append('"');
|
|
||||||
}
|
|
||||||
printWriter.println(builder.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-342
@@ -1,342 +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 com.google.android.apps.mytracks.io.file.exporter;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.location.Location;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write track as TCX to a file. See http://developer.garmin.com/schemas/tcx/v2/
|
|
||||||
* for info on TCX. <br>
|
|
||||||
* The TCX file output is verified by uploading the file to
|
|
||||||
* http://connect.garmin.com/.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
* @author Dominik Rttsches
|
|
||||||
*/
|
|
||||||
public class TcxTrackWriter implements TrackWriter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCX sport type. See the TCX spec.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private enum SportType {
|
|
||||||
RUNNING("Running"),
|
|
||||||
BIKING("Biking"),
|
|
||||||
OTHER("Other");
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private SportType(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of the sport type
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// My Tracks categories that are considered as TCX biking sport type.
|
|
||||||
private static final int TCX_SPORT_BIKING_IDS[] = {
|
|
||||||
R.string.activity_type_cycling,
|
|
||||||
R.string.activity_type_dirt_bike,
|
|
||||||
R.string.activity_type_mountain_biking,
|
|
||||||
R.string.activity_type_road_biking,
|
|
||||||
R.string.activity_type_track_cycling };
|
|
||||||
|
|
||||||
// My Tracks categories that are considered as TCX running sport type.
|
|
||||||
private static final int TCX_SPORT_RUNNING_IDS[] = {
|
|
||||||
R.string.activity_type_running,
|
|
||||||
R.string.activity_type_speed_walking,
|
|
||||||
R.string.activity_type_street_running,
|
|
||||||
R.string.activity_type_track_running,
|
|
||||||
R.string.activity_type_trail_running,
|
|
||||||
R.string.activity_type_walking };
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private PrintWriter printWriter;
|
|
||||||
private SportType sportType;
|
|
||||||
|
|
||||||
public TcxTrackWriter(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepare(OutputStream outputStream) {
|
|
||||||
this.printWriter = new PrintWriter(outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.flush();
|
|
||||||
printWriter = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getExtension() {
|
|
||||||
return TrackFileFormat.TCX.getExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeHeader(Track[] tracks) {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
|
||||||
printWriter.println("<TrainingCenterDatabase"
|
|
||||||
+ " xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\"");
|
|
||||||
printWriter.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
|
|
||||||
printWriter.println("xsi:schemaLocation="
|
|
||||||
+ "\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
|
|
||||||
+ " http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeFooter() {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("<Author xsi:type=\"Application_t\">");
|
|
||||||
printWriter.println("<Name>"
|
|
||||||
+ StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", ""))
|
|
||||||
+ "</Name>");
|
|
||||||
// <Build>, <LangID>, and <PartNumber> are required by type=Application_t.
|
|
||||||
printWriter.println("<Build>");
|
|
||||||
writeVersion();
|
|
||||||
printWriter.println("</Build>");
|
|
||||||
printWriter.println("<LangID>" + Locale.getDefault().getLanguage() + "</LangID>");
|
|
||||||
printWriter.println("<PartNumber>000-00000-00</PartNumber>");
|
|
||||||
printWriter.println("</Author>");
|
|
||||||
printWriter.println("</TrainingCenterDatabase>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginWaypoints(Track track) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndWaypoints() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeWaypoint(Waypoint waypoint) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginTracks() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndTracks() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeBeginTrack(Track track, Location startLocation) {
|
|
||||||
sportType = getSportType(track.getCategory());
|
|
||||||
if (printWriter != null) {
|
|
||||||
String startTime = StringUtils.formatDateTimeIso8601(
|
|
||||||
track.getTripStatistics().getStartTime());
|
|
||||||
long totalTimeInSeconds = (long) (track.getTripStatistics().getTotalTime()
|
|
||||||
* UnitConversions.MS_TO_S);
|
|
||||||
|
|
||||||
printWriter.println("<Activities>");
|
|
||||||
printWriter.println("<Activity Sport=\"" + sportType.getName() + "\">");
|
|
||||||
printWriter.println("<Id>" + startTime + "</Id>");
|
|
||||||
printWriter.println("<Lap StartTime=\"" + startTime + "\">");
|
|
||||||
printWriter.println("<TotalTimeSeconds>" + totalTimeInSeconds + "</TotalTimeSeconds>");
|
|
||||||
printWriter.println("<DistanceMeters>" + track.getTripStatistics().getTotalDistance()
|
|
||||||
+ "</DistanceMeters>");
|
|
||||||
// <Calories> is required, just put in 0.
|
|
||||||
printWriter.println("<Calories>0</Calories>");
|
|
||||||
printWriter.println("<Intensity>Active</Intensity>");
|
|
||||||
printWriter.println("<TriggerMethod>Manual</TriggerMethod>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeEndTrack(Track track, Location endLocation) {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("</Lap>");
|
|
||||||
printWriter.println("<Notes>" + StringUtils.formatCData(track.getDescription()) + "</Notes>");
|
|
||||||
printWriter.println("<Creator xsi:type=\"Device_t\">");
|
|
||||||
printWriter.println("<Name>"
|
|
||||||
+ StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", ""))
|
|
||||||
+ "</Name>");
|
|
||||||
// <UnitId>, <ProductID>, and <Version> are required for type=Device_t.
|
|
||||||
printWriter.println("<UnitId>0</UnitId>");
|
|
||||||
printWriter.println("<ProductID>0</ProductID>");
|
|
||||||
writeVersion();
|
|
||||||
printWriter.println("</Creator>");
|
|
||||||
printWriter.println("</Activity>");
|
|
||||||
printWriter.println("</Activities>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeOpenSegment() {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("<Track>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeCloseSegment() {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("</Track>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeLocation(Location location) {
|
|
||||||
if (printWriter != null) {
|
|
||||||
printWriter.println("<Trackpoint>");
|
|
||||||
printWriter.println("<Time>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</Time>");
|
|
||||||
printWriter.println("<Position>");
|
|
||||||
printWriter.println("<LatitudeDegrees>" + location.getLatitude() + "</LatitudeDegrees>");
|
|
||||||
printWriter.println("<LongitudeDegrees>" + location.getLongitude() + "</LongitudeDegrees>");
|
|
||||||
printWriter.println("</Position>");
|
|
||||||
if (location.hasAltitude()) {
|
|
||||||
printWriter.println("<AltitudeMeters>" + location.getAltitude() + "</AltitudeMeters>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (location instanceof MyTracksLocation) {
|
|
||||||
SensorDataSet sensorDataSet = ((MyTracksLocation) location).getSensorDataSet();
|
|
||||||
if (sensorDataSet != null) {
|
|
||||||
boolean heartRateAvailable = sensorDataSet.hasHeartRate()
|
|
||||||
&& sensorDataSet.getHeartRate().hasValue()
|
|
||||||
&& sensorDataSet.getHeartRate().getState() == Sensor.SensorState.SENDING;
|
|
||||||
boolean cadenceAvailable = sensorDataSet.hasCadence()
|
|
||||||
&& sensorDataSet.getCadence().hasValue()
|
|
||||||
&& sensorDataSet.getCadence().getState() == Sensor.SensorState.SENDING;
|
|
||||||
boolean powerAvailable = sensorDataSet.hasPower()
|
|
||||||
&& sensorDataSet.getPower().hasValue()
|
|
||||||
&& sensorDataSet.getPower().getState() == Sensor.SensorState.SENDING;
|
|
||||||
|
|
||||||
if (heartRateAvailable) {
|
|
||||||
printWriter.println("<HeartRateBpm>");
|
|
||||||
printWriter.println("<Value>" + sensorDataSet.getHeartRate().getValue() + "</Value>");
|
|
||||||
printWriter.println("</HeartRateBpm>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// <Cadence> needs to be put before <Extensions>.
|
|
||||||
// According to the TCX spec, <Cadence> is only for the biking sport
|
|
||||||
// type. For others, use <RunCadence> in <Extensions>.
|
|
||||||
if (cadenceAvailable && sportType == SportType.BIKING) {
|
|
||||||
// The spec requires the max value be 254.
|
|
||||||
printWriter.println(
|
|
||||||
"<Cadence>" + Math.min(254, sensorDataSet.getCadence().getValue()) + "</Cadence>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cadenceAvailable && sportType != SportType.BIKING) || powerAvailable) {
|
|
||||||
printWriter.println("<Extensions>");
|
|
||||||
printWriter.println(
|
|
||||||
"<TPX xmlns=\"http://www.garmin.com/xmlschemas/ActivityExtension/v2\">");
|
|
||||||
|
|
||||||
// <RunCadence> needs to be put before <Watts>.
|
|
||||||
if (cadenceAvailable && sportType != SportType.BIKING) {
|
|
||||||
// The spec requires the max value to be 254.
|
|
||||||
printWriter.println("<RunCadence>"
|
|
||||||
+ Math.min(254, sensorDataSet.getCadence().getValue()) + "</RunCadence>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (powerAvailable) {
|
|
||||||
printWriter.println("<Watts>" + sensorDataSet.getPower().getValue() + "</Watts>");
|
|
||||||
}
|
|
||||||
printWriter.println("</TPX>");
|
|
||||||
printWriter.println("</Extensions>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printWriter.println("</Trackpoint>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the TCX Version.
|
|
||||||
*/
|
|
||||||
private void writeVersion() {
|
|
||||||
// Split the My Tracks version code into VersionMajor, VersionMinor, and,
|
|
||||||
// BuildMajor to fit the integer type requirement for these fields in the
|
|
||||||
// TCX spec.
|
|
||||||
String[] versionComponents = SystemUtils.getMyTracksVersion(context).split("\\.");
|
|
||||||
int versionMajor = versionComponents.length > 0 ? Integer.valueOf(versionComponents[0]) : 0;
|
|
||||||
int versionMinor = versionComponents.length > 1 ? Integer.valueOf(versionComponents[1]) : 0;
|
|
||||||
int buildMajor = versionComponents.length > 2 ? Integer.valueOf(versionComponents[2]) : 0;
|
|
||||||
|
|
||||||
printWriter.println("<Version>");
|
|
||||||
printWriter.println("<VersionMajor>" + versionMajor + "</VersionMajor>");
|
|
||||||
printWriter.println("<VersionMinor>" + versionMinor + "</VersionMinor>");
|
|
||||||
// According to TCX spec, these are optional. But http://connect.garmin.com
|
|
||||||
// requires them.
|
|
||||||
printWriter.println("<BuildMajor>" + buildMajor + "</BuildMajor>");
|
|
||||||
printWriter.println("<BuildMinor>0</BuildMinor>");
|
|
||||||
printWriter.println("</Version>");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the sport type from the category.
|
|
||||||
*
|
|
||||||
* @param category the category
|
|
||||||
*/
|
|
||||||
private SportType getSportType(String category) {
|
|
||||||
category = category.trim();
|
|
||||||
|
|
||||||
// For tracks with localized category.
|
|
||||||
for (int i : TCX_SPORT_RUNNING_IDS) {
|
|
||||||
if (category.equalsIgnoreCase(context.getString(i))) {
|
|
||||||
return SportType.RUNNING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i : TCX_SPORT_BIKING_IDS) {
|
|
||||||
if (category.equalsIgnoreCase(context.getString(i))) {
|
|
||||||
return SportType.BIKING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For tracks without localized category.
|
|
||||||
if (category.equalsIgnoreCase(SportType.RUNNING.getName())) {
|
|
||||||
return SportType.RUNNING;
|
|
||||||
} else if (category.equalsIgnoreCase(SportType.BIKING.getName())) {
|
|
||||||
return SportType.BIKING;
|
|
||||||
} else {
|
|
||||||
return SportType.OTHER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user