File formats: removed CSV and TCX.

This commit is contained in:
Dennis Guse
2019-06-25 05:48:14 +02:00
parent 1c26dd109a
commit 8255fef72d
5 changed files with 0 additions and 792 deletions
@@ -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();
}
}
@@ -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;
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.KmlTrackWriter;
import com.google.android.apps.mytracks.io.file.exporter.TcxTrackWriter;
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
import android.content.Context;
@@ -27,18 +25,6 @@ public enum TrackFileFormat implements Parcelable {
public TrackWriter newTrackWriter(Context context, boolean multiple, boolean playTrack) {
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
@@ -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());
}
}
@@ -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 Ršttsches
*/
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;
}
}
}