forked from upstream-mirrors/OpenTracks
Add play in earth with photo overlays
This commit is contained in:
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file;
|
|||||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
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.SensorData;
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||||
@@ -30,7 +31,9 @@ import com.google.android.maps.mytracks.R;
|
|||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -66,6 +69,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final DescriptionGenerator descriptionGenerator;
|
private final DescriptionGenerator descriptionGenerator;
|
||||||
|
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||||
private PrintWriter printWriter;
|
private PrintWriter printWriter;
|
||||||
private ArrayList<Integer> powerList = new ArrayList<Integer>();
|
private ArrayList<Integer> powerList = new ArrayList<Integer>();
|
||||||
private ArrayList<Integer> cadenceList = new ArrayList<Integer>();
|
private ArrayList<Integer> cadenceList = new ArrayList<Integer>();
|
||||||
@@ -82,6 +86,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
|||||||
KmlTrackWriter(Context context, DescriptionGenerator descriptionGenerator) {
|
KmlTrackWriter(Context context, DescriptionGenerator descriptionGenerator) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.descriptionGenerator = descriptionGenerator;
|
this.descriptionGenerator = descriptionGenerator;
|
||||||
|
this.myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,8 +163,15 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
|||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
String styleName = waypoint.getType() == WaypointType.STATISTICS ? STATISTICS_STYLE
|
String styleName = waypoint.getType() == WaypointType.STATISTICS ? STATISTICS_STYLE
|
||||||
: WAYPOINT_STYLE;
|
: WAYPOINT_STYLE;
|
||||||
writePlacemark(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(),
|
String photoUrl = waypoint.getPhotoUrl();
|
||||||
styleName, waypoint.getLocation());
|
if (photoUrl != null && !photoUrl.equals("")) {
|
||||||
|
float heading = getHeading(waypoint.getTrackId(), waypoint.getLocation());
|
||||||
|
writePhotoOverlay(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(),
|
||||||
|
styleName, waypoint.getLocation(), photoUrl, heading);
|
||||||
|
} else {
|
||||||
|
writePlacemark(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(),
|
||||||
|
styleName, waypoint.getLocation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +319,76 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a photo overlay.
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @param category the category
|
||||||
|
* @param description the description
|
||||||
|
* @param styleName the style name
|
||||||
|
* @param location the location
|
||||||
|
* @param photoUrl the photo url
|
||||||
|
* @param heading the heading
|
||||||
|
*/
|
||||||
|
private void writePhotoOverlay(String name, String category, String description, String styleName,
|
||||||
|
Location location, String photoUrl, float heading) {
|
||||||
|
if (location != null) {
|
||||||
|
printWriter.println("<PhotoOverlay>");
|
||||||
|
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
|
||||||
|
printWriter.println("<description>"
|
||||||
|
+ StringUtils.formatCData(StringUtils.getCategoryDescription(category, description))
|
||||||
|
+ "</description>");
|
||||||
|
printWriter.print("<Camera>");
|
||||||
|
printWriter.print("<longitude>" + location.getLongitude() + "</longitude>");
|
||||||
|
printWriter.print("<latitude>" + location.getLatitude() + "</latitude>");
|
||||||
|
printWriter.print("<altitude>20</altitude>");
|
||||||
|
printWriter.print("<heading>" + heading + "</heading>");
|
||||||
|
printWriter.print("<tilt>90</tilt>");
|
||||||
|
printWriter.println("</Camera>");
|
||||||
|
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
|
||||||
|
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
|
||||||
|
printWriter.print("<ViewVolume>");
|
||||||
|
printWriter.print("<near>10</near>");
|
||||||
|
printWriter.print("<leftFov>-60</leftFov>");
|
||||||
|
printWriter.print("<rightFov>60</rightFov>");
|
||||||
|
printWriter.print("<bottomFov>-45</bottomFov>");
|
||||||
|
printWriter.print("<topFov>45</topFov>");
|
||||||
|
printWriter.println("</ViewVolume>");
|
||||||
|
printWriter.println("<Point>");
|
||||||
|
printWriter.println("<coordinates>" + getCoordinates(location, ",") + "</coordinates>");
|
||||||
|
printWriter.println("</Point>");
|
||||||
|
printWriter.println("</PhotoOverlay>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the heading to a location.
|
||||||
|
*
|
||||||
|
* @param trackId the track id containing the location
|
||||||
|
* @param location the location
|
||||||
|
*/
|
||||||
|
private float getHeading(long trackId, Location location) {
|
||||||
|
long trackPointId = myTracksProviderUtils.getTrackPointId(trackId, location);
|
||||||
|
if (trackPointId == -1L) {
|
||||||
|
return location.getBearing();
|
||||||
|
}
|
||||||
|
Cursor cursor = null;
|
||||||
|
Location viewLocation;
|
||||||
|
try {
|
||||||
|
cursor = myTracksProviderUtils.getTrackPointCursor(trackId, trackPointId, 10, true);
|
||||||
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
|
return location.getBearing();
|
||||||
|
}
|
||||||
|
cursor.moveToPosition(cursor.getCount() - 1);
|
||||||
|
viewLocation = myTracksProviderUtils.createTrackPoint(cursor);
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return viewLocation.bearingTo(location);
|
||||||
|
}
|
||||||
|
|
||||||
private String getCoordinates(Location location, String separator) {
|
private String getCoordinates(Location location, String separator) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
buffer.append(location.getLongitude() + separator + location.getLatitude());
|
buffer.append(location.getLongitude() + separator + location.getLatitude());
|
||||||
|
|||||||
@@ -109,7 +109,8 @@ public class ListItemUtils {
|
|||||||
|
|
||||||
// Set category/description
|
// Set category/description
|
||||||
TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description);
|
TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description);
|
||||||
setTextView(descriptionTextView, getDescription(isRecording, category, description));
|
setTextView(descriptionTextView,
|
||||||
|
isRecording ? null : StringUtils.getCategoryDescription(category, description));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,30 +147,6 @@ public class ListItemUtils {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the description text.
|
|
||||||
*
|
|
||||||
* @param isRecording true if recording
|
|
||||||
* @param category the category
|
|
||||||
* @param description the description
|
|
||||||
*/
|
|
||||||
private static String getDescription(boolean isRecording, String category, String description) {
|
|
||||||
if (isRecording) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (category == null || category.length() == 0) {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
|
|
||||||
buffer.append("[" + category + "]");
|
|
||||||
if (description != null && description.length() != 0) {
|
|
||||||
buffer.append(" " + description);
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the start time text.
|
* Gets the start time text.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -228,6 +228,26 @@ public class StringUtils {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string for category and description.
|
||||||
|
*
|
||||||
|
* @param category the category
|
||||||
|
* @param description the description
|
||||||
|
*/
|
||||||
|
public static String getCategoryDescription(String category, String description) {
|
||||||
|
if (category == null || category.length() == 0) {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append("[" + category + "]");
|
||||||
|
if (description != null && description.length() != 0) {
|
||||||
|
buffer.append(" " + description);
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the given text as a XML CDATA element. This includes adding the
|
* Formats the given text as a XML CDATA element. This includes adding the
|
||||||
* starting and ending CDATA tags. Please notice that this may result in
|
* starting and ending CDATA tags. Please notice that this may result in
|
||||||
|
|||||||
@@ -237,6 +237,15 @@ public interface MyTracksProviderUtils {
|
|||||||
*/
|
*/
|
||||||
public long getLastTrackPointId(long trackId);
|
public long getLastTrackPointId(long trackId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the track point id of a location.
|
||||||
|
*
|
||||||
|
* @param trackId the track id
|
||||||
|
* @param location the location
|
||||||
|
* @return track point id if the location is in the track. -1L otherwise.
|
||||||
|
*/
|
||||||
|
public long getTrackPointId(long trackId, Location location);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first valid location for a track. Returns null if it doesn't
|
* Gets the first valid location for a track. Returns null if it doesn't
|
||||||
* exist.
|
* exist.
|
||||||
|
|||||||
+25
@@ -789,6 +789,31 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
|||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTrackPointId(long trackId, Location location) {
|
||||||
|
if (trackId < 0) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
String selection = TrackPointsColumns._ID + "=(select max(" + TrackPointsColumns._ID
|
||||||
|
+ ") from " + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID
|
||||||
|
+ "=? AND " + TrackPointsColumns.TIME + "=?)";
|
||||||
|
String[] selectionArgs = new String[] {
|
||||||
|
Long.toString(trackId), Long.toString(location.getTime()) };
|
||||||
|
cursor = getTrackPointCursor(new String[] { TrackPointsColumns._ID }, selection,
|
||||||
|
selectionArgs, TrackPointsColumns._ID);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return cursor.getLong(cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Location getFirstValidTrackPoint(long trackId) {
|
public Location getFirstValidTrackPoint(long trackId) {
|
||||||
if (trackId < 0) {
|
if (trackId < 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user