forked from upstream-mirrors/OpenTracks
Merging my maps code to head.
This commit is contained in:
@@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.google.android.maps.mytracks"
|
package="com.google.android.maps.mytracks"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="25"
|
android:versionCode="26"
|
||||||
android:versionName="1.1.3rc1">
|
android:versionName="1.1.3">
|
||||||
<application android:icon="@drawable/arrow_icon"
|
<application android:icon="@drawable/arrow_icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ package com.google.android.apps.mytracks.io;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
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.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
|
||||||
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
|
||||||
|
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ import java.io.PrintWriter;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,20 +40,35 @@ import java.util.TimeZone;
|
|||||||
* As defined by:
|
* As defined by:
|
||||||
* http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2
|
* http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2
|
||||||
*
|
*
|
||||||
|
* The TCX file written by this class has been verified as compatible with
|
||||||
|
* Garmin Training Center 3.5.3.
|
||||||
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class TcxTrackWriter implements TrackFormatWriter {
|
public class TcxTrackWriter implements TrackFormatWriter {
|
||||||
|
protected static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||||
|
|
||||||
|
// These are the only sports allowed by the TCX v2 specification for fields
|
||||||
|
// of type Sport_t.
|
||||||
|
private static final String TCX_SPORT_BIKING = "Biking";
|
||||||
|
private static final String TCX_SPORT_RUNNING = "Running";
|
||||||
|
private static final String TCX_SPORT_OTHER = "Other";
|
||||||
|
|
||||||
|
// Values for fields of type Build_t/Type.
|
||||||
|
private static final String TCX_TYPE_RELEASE = "Release";
|
||||||
|
private static final String TCX_TYPE_INTERNAL = "Internal";
|
||||||
|
|
||||||
|
private final SimpleDateFormat timestampFormatter;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
private PrintWriter pw = null;
|
private PrintWriter pw = null;
|
||||||
private Track track;
|
private Track track;
|
||||||
|
|
||||||
static final SimpleDateFormat TIMESTAMP_FORMAT =
|
public TcxTrackWriter(Context context) {
|
||||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
this.context = context;
|
||||||
static {
|
|
||||||
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public TcxTrackWriter() {
|
timestampFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
|
||||||
|
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,16 +111,13 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
if (pw == null) {
|
if (pw == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String startTime = timestampFormatter.format(track.getStatistics().getStartTime());
|
||||||
|
|
||||||
pw.println(" <Activities>");
|
pw.println(" <Activities>");
|
||||||
pw.print(" <Activity Sport=\"");
|
pw.format(" <Activity Sport=\"%s\">\n", categoryToTcxSport(track.getCategory()));
|
||||||
if (track.getCategory() != null) {
|
pw.format(" <Id>%s</Id>\n", startTime);
|
||||||
pw.print(track.getCategory());
|
pw.format(" <Lap StartTime=\"%s\">\n", startTime);
|
||||||
}
|
|
||||||
pw.println("\">");
|
|
||||||
pw.print(" <Id>");
|
|
||||||
pw.print(TIMESTAMP_FORMAT.format(track.getStatistics().getStartTime()));
|
|
||||||
pw.println("</Id>");
|
|
||||||
pw.println(" <Lap>");
|
|
||||||
pw.print(" <TotalTimeSeconds>");
|
pw.print(" <TotalTimeSeconds>");
|
||||||
pw.print(track.getStatistics().getTotalTime() / 1000);
|
pw.print(track.getStatistics().getTotalTime() / 1000);
|
||||||
pw.println("</TotalTimeSeconds>");
|
pw.println("</TotalTimeSeconds>");
|
||||||
@@ -113,7 +128,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
// Calories are a required element just put in 0.
|
// Calories are a required element just put in 0.
|
||||||
pw.print("<Calories>0</Calories>");
|
pw.print("<Calories>0</Calories>");
|
||||||
pw.println("<Intensity>Active</Intensity>");
|
pw.println("<Intensity>Active</Intensity>");
|
||||||
pw.println("<TriggerMethod>Manual</TriggerMethod>)");
|
pw.println("<TriggerMethod>Manual</TriggerMethod>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -130,7 +145,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
}
|
}
|
||||||
pw.println(" <Trackpoint>");
|
pw.println(" <Trackpoint>");
|
||||||
Date d = new Date(location.getTime());
|
Date d = new Date(location.getTime());
|
||||||
pw.println(" <Time>" + TIMESTAMP_FORMAT.format(d) + "</Time>");
|
pw.println(" <Time>" + timestampFormatter.format(d) + "</Time>");
|
||||||
pw.println(" <Position>");
|
pw.println(" <Position>");
|
||||||
|
|
||||||
pw.print(" <LatitudeDegrees>");
|
pw.print(" <LatitudeDegrees>");
|
||||||
@@ -194,10 +209,18 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
}
|
}
|
||||||
pw.println(" </Lap>");
|
pw.println(" </Lap>");
|
||||||
pw.print(" <Creator xsi:type=\"Device_t\">");
|
pw.print(" <Creator xsi:type=\"Device_t\">");
|
||||||
pw.print("<Name>");
|
pw.format("<Name>%s</Name>\n", Build.MODEL);
|
||||||
pw.print(Build.MODEL);
|
|
||||||
pw.print("</Name>");
|
// The following code is correct. ID is inconsistently capitalized in the
|
||||||
pw.println("</Creator>)");
|
// TCX schema.
|
||||||
|
pw.println("<UnitId>0</UnitId>");
|
||||||
|
pw.println("<ProductID>0</ProductID>");
|
||||||
|
|
||||||
|
pw.println("<Version>");
|
||||||
|
pw.println("<VersionMajor>0</VersionMajor>");
|
||||||
|
pw.println("<VersionMinor>0</VersionMinor>");
|
||||||
|
pw.println("</Version>");
|
||||||
|
pw.println("</Creator>");
|
||||||
pw.println(" </Activity>");
|
pw.println(" </Activity>");
|
||||||
pw.println(" </Activities>");
|
pw.println(" </Activities>");
|
||||||
}
|
}
|
||||||
@@ -207,8 +230,24 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
if (pw == null) {
|
if (pw == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pw.print(" <Author xsi:type=\"Application_t\">");
|
pw.println(" <Author xsi:type=\"Application_t\">");
|
||||||
pw.print("<Name>My Tracks by Google</Name>");
|
|
||||||
|
// We put the version in the name because there isn't a better place for
|
||||||
|
// it. The TCX schema tightly defined the Version tag, so we can't put it
|
||||||
|
// there. They've similarly constrained the PartNumber tag, so it can't go
|
||||||
|
// there either.
|
||||||
|
pw.format("<Name>My Tracks %s by Google</Name>\n", MyTracksUtils.getMyTracksVersion(context));
|
||||||
|
|
||||||
|
pw.println("<Build>");
|
||||||
|
pw.println("<Version>");
|
||||||
|
pw.format("<VersionMajor>%d</VersionMajor>\n", MyTracksUtils.getMyTracksVersionCode(context));
|
||||||
|
pw.println("<VersionMinor>0</VersionMinor>");
|
||||||
|
pw.println("</Version>");
|
||||||
|
pw.format("<Type>%s</Type>\n", MyTracksUtils.isRelease(context) ? TCX_TYPE_RELEASE
|
||||||
|
: TCX_TYPE_INTERNAL);
|
||||||
|
pw.println("</Build>");
|
||||||
|
pw.format("<LangID>%s</LangID>\n", Locale.getDefault().getLanguage());
|
||||||
|
pw.println("<PartNumber>000-00000-00</PartNumber>");
|
||||||
pw.println("</Author>");
|
pw.println("</Author>");
|
||||||
pw.println("</TrainingCenterDatabase>");
|
pw.println("</TrainingCenterDatabase>");
|
||||||
}
|
}
|
||||||
@@ -217,4 +256,15 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
|||||||
public void writeWaypoint(Waypoint waypoint) {
|
public void writeWaypoint(Waypoint waypoint) {
|
||||||
// TODO Write out the waypoints somewhere.
|
// TODO Write out the waypoints somewhere.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String categoryToTcxSport(String category) {
|
||||||
|
category = category.trim();
|
||||||
|
if (category.equalsIgnoreCase(TCX_SPORT_RUNNING)) {
|
||||||
|
return TCX_SPORT_RUNNING;
|
||||||
|
} else if (category.equalsIgnoreCase(TCX_SPORT_BIKING)) {
|
||||||
|
return TCX_SPORT_BIKING;
|
||||||
|
} else {
|
||||||
|
return TCX_SPORT_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class TrackWriterFactory {
|
|||||||
TCX {
|
TCX {
|
||||||
@Override
|
@Override
|
||||||
public TrackFormatWriter newFormatWriter(Context context) {
|
public TrackFormatWriter newFormatWriter(Context context) {
|
||||||
return new TcxTrackWriter();
|
return new TcxTrackWriter(context);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.google.android.apps.mytracks.util;
|
|||||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
|
||||||
import com.google.android.maps.GeoPoint;
|
import com.google.android.maps.GeoPoint;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -259,17 +258,17 @@ public class MyTracksUtils {
|
|||||||
* Returns whether or not this is a release build.
|
* Returns whether or not this is a release build.
|
||||||
*/
|
*/
|
||||||
public static boolean isRelease(Context context) {
|
public static boolean isRelease(Context context) {
|
||||||
try {
|
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_SIGNATURES);
|
||||||
Signature [] sigs = context.getPackageManager().getPackageInfo(
|
if (packageInfo == null) {
|
||||||
context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
|
return false;
|
||||||
for (Signature sig : sigs) {
|
|
||||||
if (sig.hashCode() == RELEASE_SIGNATURE_HASHCODE) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
Log.e(MyTracksConstants.TAG, "Unable to get signatures", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Signature sig : packageInfo.signatures) {
|
||||||
|
if (sig.hashCode() == RELEASE_SIGNATURE_HASHCODE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,14 +278,31 @@ public class MyTracksUtils {
|
|||||||
* @return the version, or an empty string in case of failure.
|
* @return the version, or an empty string in case of failure.
|
||||||
*/
|
*/
|
||||||
public static String getMyTracksVersion(Context context) {
|
public static String getMyTracksVersion(Context context) {
|
||||||
|
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_META_DATA);
|
||||||
|
return packageInfo == null ? "" : packageInfo.versionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the My Tracks version code from the manifest.
|
||||||
|
*
|
||||||
|
* @return the version code, or an empty string in case of failure.
|
||||||
|
*/
|
||||||
|
public static int getMyTracksVersionCode(Context context) {
|
||||||
|
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_META_DATA);
|
||||||
|
return packageInfo == null ? -1 : packageInfo.versionCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PackageInfo getPackageInfo(Context context, int flags) {
|
||||||
|
if (context == null) {
|
||||||
|
Log.w(MyTracksConstants.TAG, "No context found when attempting to get PackageInfo");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
PackageInfo pi = context.getPackageManager().getPackageInfo(
|
return context.getPackageManager().getPackageInfo(
|
||||||
"com.google.android.maps.mytracks",
|
"com.google.android.maps.mytracks", flags);
|
||||||
PackageManager.GET_META_DATA);
|
|
||||||
return pi.versionName;
|
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Log.w(MyTracksConstants.TAG, "Failed to get version info.", e);
|
Log.w(MyTracksConstants.TAG, "Failed to get version info.", e);
|
||||||
return "";
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,32 @@ package com.google.android.apps.mytracks.io;
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the GPX track exporter.
|
* Tests for the GPX track exporter.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||||
|
private DateFormat timestampFormatter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
timestampFormatter = new SimpleDateFormat(TcxTrackWriter.TIMESTAMP_FORMAT);
|
||||||
|
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testXmlOutput() throws Exception {
|
public void testXmlOutput() throws Exception {
|
||||||
TrackFormatWriter writer = new TcxTrackWriter();
|
TrackFormatWriter writer = new TcxTrackWriter(null);
|
||||||
String result = writeTrack(writer);
|
String result = writeTrack(writer);
|
||||||
Document doc = parseXmlDocument(result);
|
Document doc = parseXmlDocument(result);
|
||||||
|
|
||||||
@@ -58,8 +69,8 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
|||||||
getChildTextValue(posTag, "LatitudeDegrees"));
|
getChildTextValue(posTag, "LatitudeDegrees"));
|
||||||
assertEquals(Double.toString(loc.getLongitude()),
|
assertEquals(Double.toString(loc.getLongitude()),
|
||||||
getChildTextValue(posTag, "LongitudeDegrees"));
|
getChildTextValue(posTag, "LongitudeDegrees"));
|
||||||
assertEquals(
|
|
||||||
TcxTrackWriter.TIMESTAMP_FORMAT.format(new Date(loc.getTime())),
|
assertEquals(timestampFormatter.format(loc.getTime()),
|
||||||
getChildTextValue(tag, "Time"));
|
getChildTextValue(tag, "Time"));
|
||||||
assertEquals(Double.toString(loc.getAltitude()),
|
assertEquals(Double.toString(loc.getAltitude()),
|
||||||
getChildTextValue(tag, "AltitudeMeters"));
|
getChildTextValue(tag, "AltitudeMeters"));
|
||||||
|
|||||||
Reference in New Issue
Block a user