forked from upstream-mirrors/OpenTracks
Fixing issue 190 (second step: refactoring mymaps uploading)
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user