Fixing issue 190 (second step: refactoring mymaps uploading)

This commit is contained in:
Rodrigo Damazio
2010-10-14 18:35:51 -03:00
parent 8353a01082
commit 352b851e9c
3 changed files with 240 additions and 227 deletions
@@ -26,6 +26,7 @@ import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.GpxImporter; import com.google.android.apps.mytracks.io.GpxImporter;
import com.google.android.apps.mytracks.io.SendToDocs; import com.google.android.apps.mytracks.io.SendToDocs;
import com.google.android.apps.mytracks.io.SendToMyMaps; import com.google.android.apps.mytracks.io.SendToMyMaps;
import com.google.android.apps.mytracks.io.SendToMyMaps.OnSendCompletedListener;
import com.google.android.apps.mytracks.io.TrackWriter; import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory; import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat; import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
@@ -55,6 +56,8 @@ import android.location.LocationManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -523,8 +526,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (results.hasExtra("mapid")) { if (results.hasExtra("mapid")) {
sendToMyMapsMapId = results.getStringExtra("mapid"); sendToMyMapsMapId = results.getStringExtra("mapid");
} }
setProgressMessage(getString( setProgressMessage(
R.string.progress_message_authenticating_mymaps)); R.string.progress_message_authenticating_mymaps);
authenticate(results, MyTracksConstants.SEND_TO_GOOGLE, authenticate(results, MyTracksConstants.SEND_TO_GOOGLE,
MyMapsConstants.MAPSHOP_SERVICE); MyMapsConstants.MAPSHOP_SERVICE);
} else { } else {
@@ -590,7 +593,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
setProgressValue(0); setProgressValue(0);
setProgressMessage( setProgressMessage(
getString(R.string.progress_message_authenticating_docs)); R.string.progress_message_authenticating_docs);
authenticate(results, authenticate(results,
MyTracksConstants.AUTHENTICATE_TO_TRIX, "writely"); MyTracksConstants.AUTHENTICATE_TO_TRIX, "writely");
} else { } else {
@@ -602,7 +605,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
setProgressValue(30); setProgressValue(30);
setProgressMessage( setProgressMessage(
getString(R.string.progress_message_authenticating_docs)); R.string.progress_message_authenticating_docs);
authenticate(results, MyTracksConstants.SEND_TO_DOCS, "wise"); authenticate(results, MyTracksConstants.SEND_TO_DOCS, "wise");
} else { } else {
dismissDialogSafely(DIALOG_PROGRESS); dismissDialogSafely(DIALOG_PROGRESS);
@@ -613,7 +616,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
Log.d(MyTracksConstants.TAG, "Sending to Docs...."); Log.d(MyTracksConstants.TAG, "Sending to Docs....");
setProgressValue(50); setProgressValue(50);
setProgressMessage(getString(R.string.progress_message_sending_docs)); setProgressMessage(R.string.progress_message_sending_docs);
final long trackId = results.getLongExtra("trackid", selectedTrackId); final long trackId = results.getLongExtra("trackid", selectedTrackId);
final SendToDocs sender = new SendToDocs(this, authMap.get("wise"), final SendToDocs sender = new SendToDocs(this, authMap.get("wise"),
authMap.get("writely"), trackId); authMap.get("writely"), trackId);
@@ -644,30 +647,30 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
case MyTracksConstants.SEND_TO_GOOGLE: { case MyTracksConstants.SEND_TO_GOOGLE: {
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
final String mapid; final String mapId;
final long trackId; final long trackId;
if (results.hasExtra("mapid")) { if (results.hasExtra("mapid")) {
mapid = results.getStringExtra("mapid"); mapId = results.getStringExtra("mapid");
} else { } else {
mapid = "new"; mapId = "new";
} }
if (results.hasExtra("trackid")) { if (results.hasExtra("trackid")) {
trackId = results.getLongExtra("trackid", -1); trackId = results.getLongExtra("trackid", -1);
} else { } else {
trackId = selectedTrackId; trackId = selectedTrackId;
} }
final SendToMyMaps sender = new SendToMyMaps(this, mapid, auth,
trackId, this/*progressIndicator*/); OnSendCompletedListener onCompletion = new OnSendCompletedListener() {
Runnable onCompletion = new Runnable() { @Override
public void run() { public void onSendCompleted(String mapId, boolean success, int statusMessage) {
sendToMyMapsMessage = sender.getStatusMessage(); sendToMyMapsMessage = getString(statusMessage);
sendToMyMapsSuccess = sender.wasSuccess(); sendToMyMapsSuccess = success;
if (sendToMyMapsSuccess) { if (sendToMyMapsSuccess) {
sendToMyMapsMapId = sender.getMapId(); sendToMyMapsMapId = mapId;
// Update the map id for this track: // Update the map id for this track:
try { try {
Track track = providerUtils.getTrack(trackId); Track track = providerUtils.getTrack(trackId);
track.setMapId(sender.getMapId()); track.setMapId(mapId);
providerUtils.updateTrack(track); providerUtils.updateTrack(track);
} catch (RuntimeException e) { } catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but // If that fails whatever reasons we'll just log an error, but
@@ -688,8 +691,13 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
} }
}; };
sender.setOnCompletion(onCompletion); final SendToMyMaps sender = new SendToMyMaps(this, mapId, auth,
sender.run(); trackId, this/*progressIndicator*/, onCompletion);
HandlerThread handlerThread = new HandlerThread("SendToMyMaps");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(sender);
} else { } else {
dismissDialogSafely(DIALOG_PROGRESS); dismissDialogSafely(DIALOG_PROGRESS);
} }
@@ -953,18 +961,31 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}); });
} }
public void setProgressMessage(final String text) { // ProgressIndicator implementation
@Override
public void setProgressMessage(int resId) {
setProgressMessage(getString(resId));
}
private void setProgressMessage(final String message) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
synchronized (this) { synchronized (this) {
if (progressDialog != null) { if (progressDialog != null) {
progressDialog.setMessage(text); progressDialog.setMessage(message);
} }
} }
} }
}); });
} }
@Override
public void clearProgressMessage() {
setProgressMessage("");
}
@Override
public void setProgressValue(final int percent) { public void setProgressValue(final int percent) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
@@ -1278,7 +1299,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
return; return;
} }
setProgressValue(0); setProgressValue(0);
setProgressMessage(""); clearProgressMessage();
showDialogSafely(DIALOG_PROGRESS); showDialogSafely(DIALOG_PROGRESS);
if (sendToGoogleDialog.getSendToMyMaps()) { if (sendToGoogleDialog.getSendToMyMaps()) {
if (!sendToGoogleDialog.getCreateNewMap()) { if (!sendToGoogleDialog.getCreateNewMap()) {
@@ -1286,8 +1307,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
startActivityForResult(listIntent, MyTracksConstants.GET_MAP); startActivityForResult(listIntent, MyTracksConstants.GET_MAP);
} else { } else {
setProgressValue(0); setProgressValue(0);
setProgressMessage(getString( setProgressMessage(
R.string.progress_message_authenticating_mymaps)); R.string.progress_message_authenticating_mymaps);
authenticate(new Intent(), MyTracksConstants.SEND_TO_GOOGLE, authenticate(new Intent(), MyTracksConstants.SEND_TO_GOOGLE,
MyMapsConstants.MAPSHOP_SERVICE); MyMapsConstants.MAPSHOP_SERVICE);
} }
@@ -23,7 +23,8 @@ package com.google.android.apps.mytracks;
*/ */
public interface ProgressIndicator { public interface ProgressIndicator {
public void setProgressMessage(String text); public void setProgressMessage(int resId);
public void clearProgressMessage();
public void setProgressValue(int percent); public void setProgressValue(int percent);
@@ -25,7 +25,6 @@ import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.ProgressIndicator; import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackBuffer;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -44,53 +43,53 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.location.Location; import android.location.Location;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log; import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Vector; import java.util.Vector;
import org.xmlpull.v1.XmlPullParserException;
/** /**
* A helper class used to transmit tracks to Google MyMaps. * A helper class used to transmit tracks to Google MyMaps.
* A new instance should be used for each upload.
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public class SendToMyMaps { public class SendToMyMaps implements Runnable {
public static final String NEW_MAP_ID = "new";
private static final String END_ICON_URL = private static final String END_ICON_URL =
"http://maps.google.com/mapfiles/ms/micons/red-dot.png"; "http://maps.google.com/mapfiles/ms/micons/red-dot.png";
private static final String START_ICON_URL = private static final String START_ICON_URL =
"http://maps.google.com/mapfiles/ms/micons/green-dot.png"; "http://maps.google.com/mapfiles/ms/micons/green-dot.png";
private static final int MAX_POINTS_PER_UPLOAD = 2048;
private final Activity context; private final Activity context;
private final AuthManager auth; private final AuthManager auth;
private final long trackId; private final long trackId;
private final ProgressIndicator progressIndicator; private final ProgressIndicator progressIndicator;
private final OnSendCompletedListener onCompletion;
private final StringUtils stringUtils; private final StringUtils stringUtils;
private final MyTracksProviderUtils providerUtils; private final MyTracksProviderUtils providerUtils;
private String mapId; private String mapId;
private String statusMessage = ""; // GData service
private boolean success = true;
private Runnable onCompletion;
private HandlerThread handlerThread;
private Handler handler;
private String originalDescription;
private MyMapsGDataWrapper wrapper; private MyMapsGDataWrapper wrapper;
private MyMapsGDataConverter gdataConverter; private MyMapsGDataConverter gdataConverter;
private Location last = null; // Progress status
private int totalLocationsRead;
private int totalLocationsPrepared;
private int totalLocationsUploaded;
private int totalLocations;
private int totalSegmentsUploaded;
private Vector<Double> distances; public interface OnSendCompletedListener {
private Vector<Double> elevations; void onSendCompleted(String mapId, boolean success, int statusMessage);
private DoubleBuffer elevationBuffer; }
/** /**
* Prepares a buffer of locations for transmission to google maps. * Prepares a buffer of locations for transmission to google maps.
@@ -100,8 +99,8 @@ public class SendToMyMaps {
* @return an array of tracks each with a sub section of the points in the * @return an array of tracks each with a sub section of the points in the
* original buffer * original buffer
*/ */
private ArrayList<Track> prepareLocations(Track track, private ArrayList<Track> prepareLocations(
TrackBuffer buffer) { Track track, Iterable<Location> locations) {
ArrayList<Track> splitTracks = new ArrayList<Track>(); ArrayList<Track> splitTracks = new ArrayList<Track>();
// Create segments from each full track: // Create segments from each full track:
@@ -115,8 +114,10 @@ public class SendToMyMaps {
segmentStats.setStartTime(trackStats.getStartTime()); segmentStats.setStartTime(trackStats.getStartTime());
segmentStats.setStopTime(trackStats.getStopTime()); segmentStats.setStopTime(trackStats.getStopTime());
boolean startNewTrackSegment = false; boolean startNewTrackSegment = false;
for (int i = 0; i < buffer.getLocationsLoaded(); ++i) { for (Location loc : locations) {
Location loc = buffer.get(i); if (totalLocationsPrepared % 100 == 0) {
updateProgress();
}
if (loc.getLatitude() > 90) { if (loc.getLatitude() > 90) {
startNewTrackSegment = true; startNewTrackSegment = true;
} }
@@ -141,6 +142,7 @@ public class SendToMyMaps {
segmentStats.setStartTime(loc.getTime()); segmentStats.setStartTime(loc.getTime());
} }
} }
totalLocationsPrepared++;
} }
prepareTrackSegment(segment, splitTracks); prepareTrackSegment(segment, splitTracks);
@@ -222,44 +224,19 @@ public class SendToMyMaps {
/** /**
* Sets the current upload progress. * Sets the current upload progress.
*
* @param track The track being uploaded
* @param totalLocationsRead The total number of locations already read and
* uploaded
* @param segmentSize The percent of total that each segment corresponds to
* @param progressInSegment The approximate progress in this segment
*/ */
private void setProgress(final Track track, int totalLocationsRead, private void updateProgress() {
double segmentSize, double progressInSegment) {
long totalLocations = track.getStopId() - track.getStartId();
// The percent of the total that represents the completed part of this // The percent of the total that represents the completed part of this
// segment. // segment.
double percentSegmentInTotal = (segmentSize * progressInSegment); int totalPercentage =
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
int progress = (int) ((100.0 * totalLocationsRead / totalLocations) / (totalLocations * 3);
+ percentSegmentInTotal); totalPercentage = Math.min(99, totalPercentage);
progress = Math.min(99, progress); progressIndicator.setProgressValue(totalPercentage);
progressIndicator.setProgressValue(progress);
} }
private boolean uploadAllTrackPoints(final Track track) { private boolean uploadAllTrackPoints(
int totalLocationsRead = 0; final Track track, String originalDescription) {
// TODO: This might not actually be accurate.
long totalLocations = track.getStopId() - track.getStartId();
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
Log.d(MyTracksConstants.TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
Location lastLocation = null;
TrackBuffer buffer = new TrackBuffer((int) Math.min(2048, totalLocations));
int part = 1;
SharedPreferences preferences = context.getSharedPreferences( SharedPreferences preferences = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0); MyTracksSettings.SETTINGS_NAME, 0);
boolean metricUnits = true; boolean metricUnits = true;
@@ -269,100 +246,159 @@ public class SendToMyMaps {
true); true);
} }
// For the progress monitor: Cursor locationsCursor =
// For each track segment 33% = read, 33% = prep & 33% = upload providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
// Note: These numbers are very rough. try {
if (!locationsCursor.moveToFirst()) {
Log.w(MyTracksConstants.TAG, "Unable to get any points to upload");
return false;
}
// The size of each segment in the 100% progress totalLocationsRead = 0;
double segmentSize = buffer.getSize() * 100.0 / totalLocations; totalLocationsPrepared = 0;
while (success && buffer.getLastLocationRead() < track.getStopId()) { totalLocationsUploaded = 0;
setProgress(track, totalLocationsRead, segmentSize, 0.0); totalLocations = locationsCursor.getCount();
totalSegmentsUploaded = 0;
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
Log.d(MyTracksConstants.TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage( progressIndicator.setProgressMessage(
context.getString(R.string.progress_message_reading_track)); R.string.progress_message_reading_track);
Location lastLocation = null;
do {
if (totalLocationsRead % 100 == 0) {
updateProgress();
}
providerUtils.getTrackPoints(track, buffer); Location loc = providerUtils.createLocation(locationsCursor);
if (buffer.getLocationsLoaded() <= 0 || buffer.getSize() <= 0) { locations.add(loc);
continue;
}
if (totalLocationsRead == 0) {
// Put a marker at the first point of the first valid segment:
uploadMarker(track, buffer.get(0), true);
}
last = buffer.get(buffer.getLocationsLoaded() - 1);
// Extract the elevation profile. if (totalLocationsRead == 0) {
for (int i = 0; i < buffer.getLocationsLoaded(); i++) { // Put a marker at the first point of the first valid segment:
// Add all points to the smoothing buffer. uploadMarker(track, loc, true);
Location l = buffer.get(i); }
if (l != null && MyTracksUtils.isValidLocation(l)) {
elevationBuffer.setNext(metricUnits ? l.getAltitude() // Add to the elevation profile.
: l.getAltitude() * UnitConversions.M_TO_FT); if (loc != null && MyTracksUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
if (lastLocation != null) { if (lastLocation != null) {
double dist = lastLocation.distanceTo(l); double dist = lastLocation.distanceTo(loc);
totalDistance += dist; totalDistance += dist;
} }
lastLocation = l;
// Only add some data points to keep the url short. // ...but only a few points are really used to keep the url short.
if (i % elevationSamplingFrequency == 0) { if (totalLocationsRead % elevationSamplingFrequency == 0) {
distances.add(totalDistance); distances.add(totalDistance);
elevations.add(elevationBuffer.getAverage()); elevations.add(elevationBuffer.getAverage());
} }
} }
// If the location was not valid, it's a segment split, so make sure the
// distance between the previous segment and the new one is not accounted
// for in the next iteration.
lastLocation = loc;
// Every now and then, upload the accumulated points
if (totalLocationsRead % MAX_POINTS_PER_UPLOAD
== MAX_POINTS_PER_UPLOAD - 1) {
if (!prepareAndUploadPoints(track, locations)) {
return false;
}
}
totalLocationsRead++;
} while (locationsCursor.moveToNext());
// Do a final upload with what's left
if (!prepareAndUploadPoints(track, locations)) {
return false;
} }
setProgress(track, totalLocationsRead, segmentSize, 0.3333); // Put an end marker at the last point of the last valid segment:
progressIndicator.setProgressMessage( if (lastLocation != null) {
context.getString(R.string.progress_message_preparing_track)); track.setDescription("<p>" + originalDescription + "</p><p>"
+ stringUtils.generateTrackDescription(
ArrayList<Track> splitTracks = prepareLocations(track, buffer); track, distances, elevations)
+ "</p>");
int i = 0; return uploadMarker(track, lastLocation, false);
for (Track t : splitTracks) {
if (part > 1) {
t.setName(t.getName() + " "
+ String.format(context.getString(R.string.part), part));
}
part++;
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Prepared feature for upload w/ "
+ t.getLocations().size() + " points.");
//
// Transmit tracks via GData feed:
// -------------------------------
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!uploadTrackPoints(track, t,
totalLocationsRead, segmentSize)) {
success = false;
return false;
}
i++;
} }
totalLocationsRead += buffer.getLocationsLoaded();
return true;
} finally {
locationsCursor.close();
}
}
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
progressIndicator.setProgressMessage(
R.string.progress_message_preparing_track);
updateProgress();
int numLocations = locations.size();
if (numLocations < 2) {
Log.d(MyTracksConstants.TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations;
return true;
} }
// Prepare/pre-process the points
ArrayList<Track> splitTracks = prepareLocations(track, locations);
// Start uploading them
progressIndicator.setProgressMessage(
R.string.progress_message_sending_mymaps);
for (Track splitTrack : splitTracks) {
if (totalSegmentsUploaded > 1) {
splitTrack.setName(splitTrack.getName() + " "
+ String.format(
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!uploadTrackPoints(splitTrack)) {
Log.e(MyTracksConstants.TAG, "Uploading failed");
return false;
}
}
locations.clear();
totalLocationsUploaded += numLocations;
updateProgress();
return true; return true;
} }
/** /**
* Uploads a given list of tracks to Google MyMaps using the maps GData feed. * Uploads a given list of tracks to Google MyMaps using the maps GData feed.
*
* @param track the track meta-data is used for the map name
*/ */
private boolean uploadTrackPoints(final Track track, final Track currentTrack, private boolean uploadTrackPoints(final Track track) {
int totalLocationsRead, double segmentSize) {
setProgress(track, totalLocationsRead, segmentSize, 0.6666);
progressIndicator.setProgressMessage(
context.getString(R.string.progress_message_sending_mymaps));
return wrapper.runQuery(new QueryFunction() { return wrapper.runQuery(new QueryFunction() {
@Override @Override
public void query(MapsClient client) public void query(MapsClient client)
throws AuthenticationException, IOException, Exception { throws AuthenticationException, IOException, Exception {
String featureFeed = MapsClient.getFeaturesFeed(mapId); String featureFeed = MapsClient.getFeaturesFeed(mapId);
Log.d(MyTracksConstants.TAG, "Feature feed url: " + featureFeed); Log.d(MyTracksConstants.TAG, "Feature feed url: " + featureFeed);
uploadTrackPoints(track, currentTrack, client, featureFeed); uploadTrackPoints(track, client, featureFeed);
} }
}); });
} }
@@ -373,9 +409,9 @@ public class SendToMyMaps {
* @param track The track that will be uploaded to this map * @param track The track that will be uploaded to this map
* @return True on success. * @return True on success.
*/ */
private boolean createNewMap(final Track track) { private boolean createNewMap(final Track track, final String description) {
progressIndicator.setProgressMessage(context progressIndicator.setProgressMessage(
.getString(R.string.progress_message_creating_map)); R.string.progress_message_creating_map);
return wrapper.runQuery(new QueryFunction() { return wrapper.runQuery(new QueryFunction() {
@Override @Override
public void query(MapsClient client) throws IOException, Exception { public void query(MapsClient client) throws IOException, Exception {
@@ -384,7 +420,7 @@ public class SendToMyMaps {
Log.d(MyTracksConstants.TAG, "Map feed is " + mapFeed); Log.d(MyTracksConstants.TAG, "Map feed is " + mapFeed);
MyMapsMapMetadata metaData = new MyMapsMapMetadata(); MyMapsMapMetadata metaData = new MyMapsMapMetadata();
metaData.setTitle(track.getName()); metaData.setTitle(track.getName());
metaData.setDescription(originalDescription + " - " metaData.setDescription(description + " - "
+ track.getCategory() + " - " + track.getCategory() + " - "
+ context.getString(R.string.new_map_description)); + context.getString(R.string.new_map_description));
SharedPreferences preferences = context.getSharedPreferences( SharedPreferences preferences = context.getSharedPreferences(
@@ -404,15 +440,15 @@ public class SendToMyMaps {
}); });
} }
private boolean uploadTrackPoints(final Track track, private boolean uploadTrackPoints(Track splitTrack,
Track splitTrack,
MapsClient client, MapsClient client,
String featureFeed) String featureFeed)
throws IOException, Exception { throws IOException, Exception {
Entry entry = null; Entry entry = null;
if (splitTrack.getId() != track.getId() int numLocations = splitTrack.getLocations().size();
|| splitTrack.getLocations().size() < 2) { if (numLocations < 2) {
// Need at least two points for a polyline: // Need at least two points for a polyline:
Log.w(MyTracksConstants.TAG, "Not uploading too few points");
return true; return true;
} }
@@ -495,115 +531,67 @@ public class SendToMyMaps {
} }
public SendToMyMaps(Activity context, String mapId, AuthManager auth, public SendToMyMaps(Activity context, String mapId, AuthManager auth,
long trackId, ProgressIndicator progressIndicator) { long trackId, ProgressIndicator progressIndicator,
OnSendCompletedListener onCompletion) {
this.context = context; this.context = context;
this.mapId = mapId; this.mapId = mapId;
this.auth = auth; this.auth = auth;
this.trackId = trackId; this.trackId = trackId;
this.progressIndicator = progressIndicator; this.progressIndicator = progressIndicator;
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context); this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context); this.providerUtils = MyTracksProviderUtils.Factory.get(context);
Log.d(MyTracksConstants.TAG, "Sending to MyMap: trackId = " + trackId);
handlerThread = new HandlerThread("SendToMyMaps");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
} }
@Override
public void run() { public void run() {
handler.post(new Runnable() { Log.d(MyTracksConstants.TAG, "Sending to MyMaps: trackId = " + trackId);
@Override doUpload();
public void run() {
doUpload();
}
});
}
public void setOnCompletion(Runnable onCompletion) {
this.onCompletion = onCompletion;
}
public String getMapId() {
return mapId;
}
public boolean wasSuccess() {
return success;
}
public String getStatusMessage() {
return statusMessage;
} }
private void doUpload() { private void doUpload() {
statusMessage = context.getString(R.string.error_sending_to_mymap); int statusMessageId = R.string.error_sending_to_mymap;
success = true; boolean success = true;
try { try {
gdataConverter = new MyMapsGDataConverter(); gdataConverter = new MyMapsGDataConverter();
progressIndicator.setProgressValue(1); progressIndicator.setProgressValue(1);
progressIndicator.setProgressMessage( progressIndicator.setProgressMessage(
context.getString(R.string.progress_message_reading_track)); R.string.progress_message_reading_track);
// Get the track meta-data // Get the track meta-data
Track track = providerUtils.getTrack(trackId); Track track = providerUtils.getTrack(trackId);
originalDescription = track.getDescription(); String originalDescription = track.getDescription();
track.setDescription("<p>" + track.getDescription() + "</p><p>" track.setDescription("<p>" + track.getDescription() + "</p><p>"
+ stringUtils.generateTrackDescription(track, null, null) + "</p>"); + stringUtils.generateTrackDescription(track, null, null) + "</p>");
wrapper = new MyMapsGDataWrapper(context); wrapper = new MyMapsGDataWrapper(context);
wrapper.setAuthManager(auth); wrapper.setAuthManager(auth);
wrapper.setRetryOnAuthFailure(true); wrapper.setRetryOnAuthFailure(true);
distances = new Vector<Double>();
elevations = new Vector<Double>();
elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
// Create a new map if necessary: // Create a new map if necessary:
if (mapId.equals("new")) { boolean isNewMap = mapId.equals(NEW_MAP_ID);
if (!createNewMap(track)) { if (isNewMap) {
success = false; success = createNewMap(track, originalDescription);
}
} }
// Upload all of the segments of the track. // Upload all of the segments of the track plus start/end markers
if (success) { if (success) {
if (!uploadAllTrackPoints(track)) { success = uploadAllTrackPoints(track, originalDescription);
success = false;
}
}
// Start end end markers.
if (success) {
// Put an end marker at the last point of the last valid segment:
if (last != null) {
track.setDescription("<p>" + originalDescription + "</p><p>"
+ stringUtils.generateTrackDescription(
track, distances, elevations)
+ "</p>");
if (!uploadMarker(track, last, false)) {
success = false;
}
}
} }
// Put waypoints. // Put waypoints.
if (success) { if (success) {
if (!uploadWaypoints(track)) { success = uploadWaypoints(track);
if (!success) {
Log.w(MyTracksConstants.TAG, Log.w(MyTracksConstants.TAG,
"SendToMyMaps: upload waypoints failed."); "SendToMyMaps: upload waypoints failed.");
success = false;
} }
} }
if (success) { if (success) {
if (mapId.equals("new")) { statusMessageId = isNewMap
statusMessage = ? R.string.status_new_mymap_has_been_created
context.getString(R.string.status_new_mymap_has_been_created); : R.string.status_tracks_have_been_uploaded;
} else {
statusMessage =
context.getString(R.string.status_tracks_have_been_uploaded);
}
} }
Log.d(MyTracksConstants.TAG, "SendToMyMaps: Done: " + success); Log.d(MyTracksConstants.TAG, "SendToMyMaps: Done: " + success);
progressIndicator.setProgressValue(100); progressIndicator.setProgressValue(100);
@@ -614,10 +602,13 @@ public class SendToMyMaps {
wrapper.cleanUp(); wrapper.cleanUp();
} }
final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() { context.runOnUiThread(new Runnable() {
public void run() { public void run() {
if (onCompletion != null) { if (onCompletion != null) {
onCompletion.run(); onCompletion.onSendCompleted(
mapId, finalSuccess, finalStatusMessageId);
} }
} }
}); });