mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
Fix comments for fd49d88ec658.
Also fixed the following: in uploadAllTrackPoints, introduce a "readCount" variable rather than using the zero based index "i". in prepareAndUploadPoints, add a lastBatch parameter so can include the (Part 1) marker if there is more than one segment. in prepareTrackSegment, set a new segment's stop time to the last location's time.
This commit is contained in:
@@ -44,20 +44,20 @@ public abstract class Constants {
|
||||
public static final int GET_MAP = 1;
|
||||
public static final int SHOW_TRACK = 2;
|
||||
public static final int AUTHENTICATE_TO_MAPS = 3;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 5;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 6;
|
||||
public static final int SHARE_GPX_FILE = 7;
|
||||
public static final int SHARE_KML_FILE = 8;
|
||||
public static final int SHARE_CSV_FILE = 9;
|
||||
public static final int SHARE_TCX_FILE = 10;
|
||||
public static final int SAVE_GPX_FILE = 11;
|
||||
public static final int SAVE_KML_FILE = 12;
|
||||
public static final int SAVE_CSV_FILE = 13;
|
||||
public static final int SAVE_TCX_FILE = 14;
|
||||
public static final int SHOW_WAYPOINT = 15;
|
||||
public static final int WELCOME = 16;
|
||||
public static final int CHOOSE_ACCOUNT = 17;
|
||||
public static final int SEND_FUSION_TABLES = 18;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 4;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 5;
|
||||
public static final int SHARE_GPX_FILE = 6;
|
||||
public static final int SHARE_KML_FILE = 7;
|
||||
public static final int SHARE_CSV_FILE = 8;
|
||||
public static final int SHARE_TCX_FILE = 9;
|
||||
public static final int SAVE_GPX_FILE = 10;
|
||||
public static final int SAVE_KML_FILE = 11;
|
||||
public static final int SAVE_CSV_FILE = 12;
|
||||
public static final int SAVE_TCX_FILE = 13;
|
||||
public static final int SHOW_WAYPOINT = 14;
|
||||
public static final int WELCOME = 15;
|
||||
public static final int CHOOSE_ACCOUNT = 16;
|
||||
public static final int SEND_FUSION_TABLES = 17;
|
||||
|
||||
/*
|
||||
* Menu ids:
|
||||
|
||||
@@ -374,9 +374,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
private SendState authenticateToFusionTables() {
|
||||
tracker.trackPageView("/send/fusion_tables");
|
||||
Intent intent = new Intent(this, SendFusionTablesActivity.class);
|
||||
intent.putExtra(SendFusionTablesActivity.ACCOUNT, account);
|
||||
intent.putExtra(SendFusionTablesActivity.TRACK_ID, sendTrackId);
|
||||
Intent intent = new Intent(this, SendFusionTablesActivity.class)
|
||||
.putExtra(SendFusionTablesActivity.ACCOUNT, account)
|
||||
.putExtra(SendFusionTablesActivity.TRACK_ID, sendTrackId);
|
||||
startActivityForResult(intent, Constants.SEND_FUSION_TABLES);
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
@@ -440,9 +440,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
String mapsUrl = sendToMaps && sendToMapsSuccess
|
||||
? MapsFacade.buildMapUrl(sendToMapsMapId)
|
||||
: null;
|
||||
Track track = providerUtils.getTrack(sendTrackId);
|
||||
String fusionTablesUrl = sendToFusionTables && sendToFusionTablesSuccess
|
||||
? SendFusionTablesUtils.getMapUrl(track)
|
||||
? SendFusionTablesUtils.getMapUrl(providerUtils.getTrack(sendTrackId))
|
||||
: null;
|
||||
Intent intent = new Intent(this, UploadResultActivity.class)
|
||||
.putExtra(UploadResultActivity.HAS_MAPS_RESULT, sendToMaps)
|
||||
|
||||
+15
-589
@@ -15,52 +15,15 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.api.client.googleapis.GoogleHeaders;
|
||||
import com.google.api.client.googleapis.MethodOverride;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpRequestFactory;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.InputStreamContent;
|
||||
import com.google.api.client.util.Strings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An activity to send a track to Google Fusion Tables.
|
||||
@@ -87,12 +50,8 @@ public class SendFusionTablesActivity extends Activity {
|
||||
public static final String SUCCESS = "success";
|
||||
public static final String TABLE_ID = "tableId";
|
||||
|
||||
private static final String TAG = SendFusionTablesActivity.class.getSimpleName();
|
||||
private static final int PROGRESS_DIALOG = 1;
|
||||
|
||||
private Account account;
|
||||
private long trackId;
|
||||
|
||||
private SendFusionTablesAsyncTask asyncTask;
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
@@ -101,15 +60,15 @@ public class SendFusionTablesActivity extends Activity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = getIntent();
|
||||
account = intent.getParcelableExtra(ACCOUNT);
|
||||
trackId = intent.getLongExtra(TRACK_ID, -1L);
|
||||
Account account = intent.getParcelableExtra(ACCOUNT);
|
||||
long trackId = intent.getLongExtra(TRACK_ID, -1L);
|
||||
|
||||
Object retained = getLastNonConfigurationInstance();
|
||||
if (retained instanceof SendFusionTablesAsyncTask) {
|
||||
asyncTask = (SendFusionTablesAsyncTask) retained;
|
||||
asyncTask.setActivity(this);
|
||||
} else {
|
||||
asyncTask = new SendFusionTablesAsyncTask(this);
|
||||
asyncTask = new SendFusionTablesAsyncTask(this, account, trackId);
|
||||
asyncTask.execute();
|
||||
}
|
||||
}
|
||||
@@ -152,558 +111,25 @@ public class SendFusionTablesActivity extends Activity {
|
||||
* @param success true if success
|
||||
* @param tableId tableId if available
|
||||
*/
|
||||
private void onAsyncTaskCompleted(boolean success, String tableId) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(SUCCESS, success);
|
||||
intent.putExtra(TABLE_ID, tableId);
|
||||
public void onAsyncTaskCompleted(boolean success, String tableId) {
|
||||
Intent intent = new Intent().putExtra(SUCCESS, success).putExtra(TABLE_ID, tableId);
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* AsyncTask to send a track to Google Fusion Tables.
|
||||
*
|
||||
* @author jshih@google.com (Jimmy Shih)
|
||||
* Shows the progress dialog.
|
||||
*/
|
||||
private class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
public void showProgressDialog() {
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
}
|
||||
|
||||
private static final String APP_NAME_PREFIX = "Google-My-Tracks-";
|
||||
private static final String SQL_KEY = "sql=";
|
||||
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
|
||||
private static final String SERVICE_ID = "fusiontables";
|
||||
private static final String FUSION_TABLES_BASE_URL =
|
||||
"https://www.google.com/fusiontables/api/query";
|
||||
private static final int MAX_POINTS_PER_UPLOAD = 2048;
|
||||
private static final String GDATA_VERSION = "2";
|
||||
|
||||
private static final int PROGRESS_CREATE_TABLE = 0;
|
||||
private static final int PROGRESS_UNLIST_TABLE = 5;
|
||||
private static final int PROGRESS_UPLOAD_DATA_MIN = 10;
|
||||
private static final int PROGRESS_UPLOAD_DATA_MAX = 90;
|
||||
private static final int PROGRESS_UPLOAD_WAYPOINTS = 95;
|
||||
private static final int PROGRESS_COMPLETE = 100;
|
||||
|
||||
private static final String MARKER_TYPE_START = "large_green";
|
||||
private static final String MARKER_TYPE_END = "large_red";
|
||||
private static final String MARKER_TYPE_WAYPOINT = "large_yellow";
|
||||
|
||||
private SendFusionTablesActivity activity;
|
||||
|
||||
private final Context context;
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
private final HttpRequestFactory httpRequestFactory;
|
||||
|
||||
private boolean canRetry; // true if can retry the upload
|
||||
private boolean completed; // true if the AsyncTask has completed
|
||||
|
||||
// The following variables are for per upload states
|
||||
private String authToken;
|
||||
private boolean success;
|
||||
private String tableId;
|
||||
int currentSegment;
|
||||
|
||||
public SendFusionTablesAsyncTask(SendFusionTablesActivity activity) {
|
||||
this.activity = activity;
|
||||
|
||||
context = activity.getApplicationContext();
|
||||
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
|
||||
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
||||
|
||||
canRetry = true;
|
||||
completed = false;
|
||||
}
|
||||
|
||||
// The following methods interact with the activity
|
||||
|
||||
/**
|
||||
* Sets the activity associated with this AyncTask.
|
||||
*
|
||||
* @param activity the activity.
|
||||
*/
|
||||
public void setActivity(SendFusionTablesActivity activity) {
|
||||
this.activity = activity;
|
||||
if (completed) {
|
||||
activity.onAsyncTaskCompleted(success, tableId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
activity.showDialog(SendFusionTablesActivity.PROGRESS_DIALOG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
return doUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
if (activity != null) {
|
||||
activity.progressDialog.setProgress(values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
completed = true;
|
||||
if (success) {
|
||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||
if (track != null) {
|
||||
track.setTableId(tableId);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
} else {
|
||||
Log.d(TAG, "No track");
|
||||
}
|
||||
}
|
||||
if (activity != null) {
|
||||
activity.onAsyncTaskCompleted(success, tableId);
|
||||
}
|
||||
}
|
||||
|
||||
// The following methods send a track to Google Fusion Tables
|
||||
|
||||
/**
|
||||
* Uploads a track to Google Fusion Tables.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean doUpload() {
|
||||
// Reset the per upload states
|
||||
authToken = null;
|
||||
success = false;
|
||||
tableId = null;
|
||||
currentSegment = 1;
|
||||
|
||||
try {
|
||||
authToken = AccountManager.get(context).blockingGetAuthToken(account, SERVICE_ID, false);
|
||||
} catch (OperationCanceledException e) {
|
||||
return retryUpload();
|
||||
} catch (AuthenticatorException e) {
|
||||
return retryUpload();
|
||||
} catch (IOException e) {
|
||||
return retryUpload();
|
||||
}
|
||||
|
||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.d(TAG, "Track is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new table
|
||||
publishProgress(PROGRESS_CREATE_TABLE);
|
||||
if (!createNewTable(track)) {
|
||||
|
||||
// Retry upload in case the auth token is invalid
|
||||
return retryUpload();
|
||||
}
|
||||
|
||||
// Unlist table
|
||||
publishProgress(PROGRESS_UNLIST_TABLE);
|
||||
if (!unlistTable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload all the track points plus the start and end markers
|
||||
publishProgress(PROGRESS_UPLOAD_DATA_MIN);
|
||||
if (!uploadAllTrackPoints(track)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload all the waypoints
|
||||
publishProgress(PROGRESS_UPLOAD_WAYPOINTS);
|
||||
if (!uploadWaypoints()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
publishProgress(PROGRESS_COMPLETE);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retries upload. Invalidates the authToken. If can retry, invokes
|
||||
* {@link SendFusionTablesAsyncTask#doUpload()}. Returns false if cannot
|
||||
* retry.
|
||||
*/
|
||||
private boolean retryUpload() {
|
||||
if (isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountManager.get(context).invalidateAuthToken(SERVICE_ID, authToken);
|
||||
if (canRetry) {
|
||||
canRetry = false;
|
||||
return doUpload();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewTable(Track track) {
|
||||
String query = "CREATE TABLE '" + SendFusionTablesUtils.escapeSqlString(track.getName())
|
||||
+ "' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
|
||||
return sendQuery(query, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlists a table.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean unlistTable() {
|
||||
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads all the points in a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean uploadAllTrackPoints(Track track) {
|
||||
Cursor locationsCursor = null;
|
||||
try {
|
||||
SharedPreferences prefs = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
boolean metricUnits = prefs.getBoolean(context.getString(R.string.metric_units_key), true);
|
||||
|
||||
locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false);
|
||||
if (locationsCursor == null) {
|
||||
Log.d(TAG, "Location cursor is null");
|
||||
return false;
|
||||
}
|
||||
int locationsCount = locationsCursor.getCount();
|
||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||
Location lastLocation = null;
|
||||
|
||||
// Limit the number of elevation readings. Ideally we would want around
|
||||
// 250.
|
||||
int elevationSamplingFrequency = Math.max(1, (int) (locationsCount / 250.0));
|
||||
double totalDistance = 0;
|
||||
DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||
Vector<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
|
||||
for (int i = 0; i < locationsCount; i++) {
|
||||
locationsCursor.moveToPosition(i);
|
||||
|
||||
Location location = myTracksProviderUtils.createLocation(locationsCursor);
|
||||
locations.add(location);
|
||||
|
||||
if (i == 0) {
|
||||
// Create a start marker
|
||||
String name = getString(R.string.marker_label_start, track.getName());
|
||||
if (!createNewPoint(name, "", location, MARKER_TYPE_START)) {
|
||||
Log.d(TAG, "Unable to create the start marker");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the distances and elevations vectors
|
||||
if (LocationUtils.isValidLocation(location)) {
|
||||
// All points go into the smoothing buffer
|
||||
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
||||
: location.getAltitude() * UnitConversions.M_TO_FT);
|
||||
if (lastLocation != null) {
|
||||
totalDistance += (double) lastLocation.distanceTo(location);
|
||||
}
|
||||
if (i % elevationSamplingFrequency == 0) {
|
||||
distances.add(totalDistance);
|
||||
elevations.add(elevationBuffer.getAverage());
|
||||
}
|
||||
}
|
||||
|
||||
// Upload periodically
|
||||
if (i % MAX_POINTS_PER_UPLOAD == MAX_POINTS_PER_UPLOAD) {
|
||||
if (!prepareAndUploadPoints(track, locations)) {
|
||||
Log.d(TAG, "Unable to upload points");
|
||||
return false;
|
||||
}
|
||||
updateProgress(i + 1, locationsCount);
|
||||
locations.clear();
|
||||
}
|
||||
lastLocation = location;
|
||||
}
|
||||
|
||||
// Do a final upload with the remaining locations
|
||||
if (!prepareAndUploadPoints(track, locations)) {
|
||||
Log.d(TAG, "Unable to upload points");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an end marker
|
||||
if (lastLocation != null) {
|
||||
StringUtils stringUtils = new StringUtils(context);
|
||||
track.setDescription("<p>" + track.getDescription() + "</p><p>"
|
||||
+ stringUtils.generateTrackDescription(track, distances, elevations) + "</p>");
|
||||
String name = getString(R.string.marker_label_end, track.getName());
|
||||
if (!createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END)) {
|
||||
Log.d(TAG, "Unable to create the end marker");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
if (locationsCursor != null) {
|
||||
locationsCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares and uploads a list of locations from a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param locations the locations from the track
|
||||
*/
|
||||
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
|
||||
int numLocations = locations.size();
|
||||
if (numLocations < 2) {
|
||||
Log.d(TAG, "Not preparing/uploading, too few points");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepare locations
|
||||
ArrayList<Track> splitTracks = prepareLocations(track, locations);
|
||||
|
||||
// Upload segments
|
||||
for (Track splitTrack : splitTracks) {
|
||||
if (currentSegment > 1) {
|
||||
splitTrack.setName(getString(
|
||||
R.string.send_google_track_part_label, splitTrack.getName(), currentSegment));
|
||||
}
|
||||
if (!createNewLineString(splitTrack)) {
|
||||
Log.d(TAG, "Upload points failed");
|
||||
return false;
|
||||
}
|
||||
currentSegment++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a list of locations to send to Google Fusion Tables.
|
||||
* Splits the locations into segments if necessary.
|
||||
*
|
||||
* @param track the track
|
||||
* @param locations the list of locations
|
||||
* @return an array of split segments.
|
||||
*/
|
||||
private ArrayList<Track> prepareLocations(Track track, List<Location> locations) {
|
||||
ArrayList<Track> splitTracks = new ArrayList<Track>();
|
||||
|
||||
// Create a new segment
|
||||
Track segment = new Track();
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
segment.setId(track.getId());
|
||||
segment.setName(track.getName());
|
||||
segment.setDescription("");
|
||||
segment.setCategory(track.getCategory());
|
||||
segmentStats.setStartTime(trackStats.getStartTime());
|
||||
segmentStats.setStopTime(trackStats.getStopTime());
|
||||
boolean startNewTrackSegment = false;
|
||||
for (Location loc : locations) {
|
||||
if (loc.getLatitude() > 90) {
|
||||
startNewTrackSegment = true;
|
||||
}
|
||||
|
||||
if (startNewTrackSegment) {
|
||||
// Close the last segment
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
startNewTrackSegment = false;
|
||||
segment = new Track();
|
||||
segment.setId(track.getId());
|
||||
segment.setName(track.getName());
|
||||
segment.setDescription("");
|
||||
segment.setCategory(track.getCategory());
|
||||
}
|
||||
|
||||
if (loc.getLatitude() <= 90) {
|
||||
segment.addLocation(loc);
|
||||
if (segmentStats.getStartTime() < 0) {
|
||||
segmentStats.setStartTime(loc.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
return splitTracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a track segment for sending to Google Fusion Tables. The main
|
||||
* steps are:
|
||||
* <ul>
|
||||
* <li>correct the end time</li>
|
||||
* <li>decimate locations precision</li>
|
||||
* </ul>
|
||||
* The prepared track will be added to the splitTracks.
|
||||
*
|
||||
* @param segment the track segment
|
||||
* @param splitTracks an array of track segments
|
||||
*/
|
||||
private void prepareTrackSegment(Track segment, ArrayList<Track> splitTracks) {
|
||||
// Correct the end time
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
if (segmentStats.getStopTime() < 0 && segment.getLocations().size() > 0) {
|
||||
segmentStats.setStopTime(segment.getLocations().size() - 1);
|
||||
}
|
||||
|
||||
// Decimate to 2 meter precision. Fusion Tables doesn't like too many
|
||||
// points.
|
||||
LocationUtils.decimate(segment, 2.0);
|
||||
splitTracks.add(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads all the waypoints.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean uploadWaypoints() {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = myTracksProviderUtils.getWaypointsCursor(
|
||||
trackId, 0, Constants.MAX_LOADED_WAYPOINTS_POINTS);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// This will skip the first waypoint (it carries the stats for the
|
||||
// track).
|
||||
while (cursor.moveToNext()) {
|
||||
Waypoint wpt = myTracksProviderUtils.createWaypoint(cursor);
|
||||
if (!createNewPoint(
|
||||
wpt.getName(), wpt.getDescription(), wpt.getLocation(), MARKER_TYPE_WAYPOINT)) {
|
||||
Log.d(TAG, "Upload waypoints failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row in Google Fusion Tables representing a marker as a
|
||||
* point.
|
||||
*
|
||||
* @param name the marker name
|
||||
* @param description the marker description
|
||||
* @param location the marker location
|
||||
* @param type the marker type
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewPoint(
|
||||
String name, String description, Location location, String type) {
|
||||
String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
|
||||
+ SendFusionTablesUtils.formatSqlValues(
|
||||
name, description, SendFusionTablesUtils.getKmlPoint(location), type);
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row in Google Fusion Tables representing the track as a
|
||||
* line segment.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewLineString(Track track) {
|
||||
String query = "INSERT INTO " + tableId + " (name,description,geometry) VALUES "
|
||||
+ SendFusionTablesUtils.formatSqlValues(track.getName(), track.getDescription(),
|
||||
SendFusionTablesUtils.getKmlLineString(track.getLocations()));
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a query to Google Fusion Tables.
|
||||
*
|
||||
* @param query the Fusion Tables SQL query
|
||||
* @param setTableId true to set the table id
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean sendQuery(String query, boolean setTableId) {
|
||||
Log.d(TAG, "SendQuery: " + query);
|
||||
|
||||
if (isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GenericUrl url = new GenericUrl(FUSION_TABLES_BASE_URL);
|
||||
String sql = SQL_KEY + URLEncoder.encode(query);
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
|
||||
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
|
||||
HttpRequest request;
|
||||
try {
|
||||
request = httpRequestFactory.buildPostRequest(url, inputStreamContent);
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
GoogleHeaders headers = new GoogleHeaders();
|
||||
headers.setApplicationName(APP_NAME_PREFIX + SystemUtils.getMyTracksVersion(context));
|
||||
headers.gdataVersion = GDATA_VERSION;
|
||||
headers.setGoogleLogin(authToken);
|
||||
headers.setContentType(CONTENT_TYPE);
|
||||
request.setHeaders(headers);
|
||||
|
||||
HttpResponse response;
|
||||
try {
|
||||
response = request.execute();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
success = response.isSuccessStatusCode();
|
||||
if (success) {
|
||||
InputStream content;
|
||||
try {
|
||||
content = response.getContent();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
if (setTableId) {
|
||||
tableId = SendFusionTablesUtils.getTableId(content);
|
||||
if (tableId == null) {
|
||||
Log.d(TAG, "tableId is null");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG,
|
||||
"sendQuery failed: " + response.getStatusMessage() + ": " + response.getStatusCode());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the progress based on the number of locations uploaded.
|
||||
*
|
||||
* @param uploaded the number of uploaded locations
|
||||
* @param total the number of total locations
|
||||
*/
|
||||
private void updateProgress(int uploaded, int total) {
|
||||
double totalPercentage = uploaded / total;
|
||||
double scaledPercentage = totalPercentage
|
||||
* (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN;
|
||||
publishProgress((int) scaledPercentage);
|
||||
/**
|
||||
* Sets the progress dialog value.
|
||||
*/
|
||||
public void setProgressDialogValue(int value) {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setProgress(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+614
@@ -0,0 +1,614 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.api.client.googleapis.GoogleHeaders;
|
||||
import com.google.api.client.googleapis.MethodOverride;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpRequestFactory;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.InputStreamContent;
|
||||
import com.google.api.client.util.Strings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* AsyncTask to send a track to Google Fusion Tables.
|
||||
*
|
||||
* @author jshih@google.com (Jimmy Shih)
|
||||
*/
|
||||
public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
|
||||
private static final String APP_NAME_PREFIX = "Google-My-Tracks-";
|
||||
private static final String SQL_KEY = "sql=";
|
||||
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
|
||||
private static final String SERVICE_ID = "fusiontables";
|
||||
private static final String FUSION_TABLES_BASE_URL =
|
||||
"https://www.google.com/fusiontables/api/query";
|
||||
private static final int MAX_POINTS_PER_UPLOAD = 2048;
|
||||
private static final String GDATA_VERSION = "2";
|
||||
|
||||
private static final int PROGRESS_CREATE_TABLE = 0;
|
||||
private static final int PROGRESS_UNLIST_TABLE = 5;
|
||||
private static final int PROGRESS_UPLOAD_DATA_MIN = 10;
|
||||
private static final int PROGRESS_UPLOAD_DATA_MAX = 90;
|
||||
private static final int PROGRESS_UPLOAD_WAYPOINTS = 95;
|
||||
private static final int PROGRESS_COMPLETE = 100;
|
||||
|
||||
// See http://support.google.com/fusiontables/bin/answer.py?hl=en&answer=185991
|
||||
private static final String MARKER_TYPE_START = "large_green";
|
||||
private static final String MARKER_TYPE_END = "large_red";
|
||||
private static final String MARKER_TYPE_WAYPOINT = "large_yellow";
|
||||
|
||||
private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
|
||||
|
||||
private SendFusionTablesActivity activity;
|
||||
|
||||
private final Context context;
|
||||
private final Account account;
|
||||
private final long trackId;
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
private final HttpRequestFactory httpRequestFactory;
|
||||
|
||||
private boolean canRetry; // true if can retry the upload
|
||||
private boolean completed; // true if the AsyncTask has completed
|
||||
|
||||
// The following variables are for per upload states
|
||||
private String authToken;
|
||||
private boolean success;
|
||||
private String tableId;
|
||||
int currentSegment;
|
||||
|
||||
public SendFusionTablesAsyncTask(
|
||||
SendFusionTablesActivity activity, Account account, long trackId) {
|
||||
this.activity = activity;
|
||||
this.account = account;
|
||||
this.trackId = trackId;
|
||||
|
||||
context = activity.getApplicationContext();
|
||||
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
|
||||
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
||||
|
||||
canRetry = true;
|
||||
completed = false;
|
||||
}
|
||||
|
||||
// The following methods interact with the activity
|
||||
|
||||
/**
|
||||
* Sets the activity associated with this AyncTask.
|
||||
*
|
||||
* @param activity the activity.
|
||||
*/
|
||||
public void setActivity(SendFusionTablesActivity activity) {
|
||||
this.activity = activity;
|
||||
if (completed) {
|
||||
activity.onAsyncTaskCompleted(success, tableId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
activity.showProgressDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
return doUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
if (activity != null) {
|
||||
activity.setProgressDialogValue(values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
completed = true;
|
||||
if (success) {
|
||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||
if (track != null) {
|
||||
track.setTableId(tableId);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
} else {
|
||||
Log.d(TAG, "No track");
|
||||
}
|
||||
}
|
||||
if (activity != null) {
|
||||
activity.onAsyncTaskCompleted(success, tableId);
|
||||
}
|
||||
}
|
||||
|
||||
// The following methods send a track to Google Fusion Tables
|
||||
|
||||
/**
|
||||
* Uploads a track to Google Fusion Tables.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean doUpload() {
|
||||
// Reset the per upload states
|
||||
authToken = null;
|
||||
success = false;
|
||||
tableId = null;
|
||||
currentSegment = 1;
|
||||
|
||||
try {
|
||||
authToken = AccountManager.get(context).blockingGetAuthToken(account, SERVICE_ID, false);
|
||||
} catch (OperationCanceledException e) {
|
||||
return retryUpload();
|
||||
} catch (AuthenticatorException e) {
|
||||
return retryUpload();
|
||||
} catch (IOException e) {
|
||||
return retryUpload();
|
||||
}
|
||||
|
||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.d(TAG, "Track is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new table
|
||||
publishProgress(PROGRESS_CREATE_TABLE);
|
||||
if (!createNewTable(track)) {
|
||||
// Retry upload in case the auth token is invalid
|
||||
return retryUpload();
|
||||
}
|
||||
|
||||
// Unlist table
|
||||
publishProgress(PROGRESS_UNLIST_TABLE);
|
||||
if (!unlistTable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload all the track points plus the start and end markers
|
||||
publishProgress(PROGRESS_UPLOAD_DATA_MIN);
|
||||
if (!uploadAllTrackPoints(track)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Upload all the waypoints
|
||||
publishProgress(PROGRESS_UPLOAD_WAYPOINTS);
|
||||
if (!uploadWaypoints()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
publishProgress(PROGRESS_COMPLETE);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retries upload. Invalidates the authToken. If can retry, invokes
|
||||
* {@link SendFusionTablesAsyncTask#doUpload()}. Returns false if cannot
|
||||
* retry.
|
||||
*/
|
||||
private boolean retryUpload() {
|
||||
if (isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountManager.get(context).invalidateAuthToken(SERVICE_ID, authToken);
|
||||
if (canRetry) {
|
||||
canRetry = false;
|
||||
return doUpload();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewTable(Track track) {
|
||||
String query = "CREATE TABLE '" + SendFusionTablesUtils.escapeSqlString(track.getName())
|
||||
+ "' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
|
||||
return sendQuery(query, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlists a table.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean unlistTable() {
|
||||
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads all the points in a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean uploadAllTrackPoints(Track track) {
|
||||
Cursor locationsCursor = null;
|
||||
try {
|
||||
SharedPreferences prefs = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
boolean metricUnits = prefs.getBoolean(context.getString(R.string.metric_units_key), true);
|
||||
|
||||
locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false);
|
||||
if (locationsCursor == null) {
|
||||
Log.d(TAG, "Location cursor is null");
|
||||
return false;
|
||||
}
|
||||
int locationsCount = locationsCursor.getCount();
|
||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||
Location lastLocation = null;
|
||||
|
||||
// Limit the number of elevation readings. Ideally we would want around
|
||||
// 250.
|
||||
int elevationSamplingFrequency = Math.max(1, (int) (locationsCount / 250.0));
|
||||
double totalDistance = 0;
|
||||
DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||
Vector<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
|
||||
for (int i = 0; i < locationsCount; i++) {
|
||||
locationsCursor.moveToPosition(i);
|
||||
|
||||
Location location = myTracksProviderUtils.createLocation(locationsCursor);
|
||||
locations.add(location);
|
||||
|
||||
int readCount = i + 1;
|
||||
|
||||
if (readCount == 1) {
|
||||
// Create a start marker
|
||||
String name = context.getString(R.string.marker_label_start, track.getName());
|
||||
if (!createNewPoint(name, "", location, MARKER_TYPE_START)) {
|
||||
Log.d(TAG, "Unable to create the start marker");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the distances and elevations vectors
|
||||
if (LocationUtils.isValidLocation(location)) {
|
||||
// All points go into the smoothing buffer
|
||||
elevationBuffer.setNext(metricUnits ? location.getAltitude()
|
||||
: location.getAltitude() * UnitConversions.M_TO_FT);
|
||||
if (lastLocation != null) {
|
||||
totalDistance += (double) lastLocation.distanceTo(location);
|
||||
}
|
||||
if (readCount % elevationSamplingFrequency == 0) {
|
||||
distances.add(totalDistance);
|
||||
elevations.add(elevationBuffer.getAverage());
|
||||
}
|
||||
}
|
||||
|
||||
// Upload periodically
|
||||
if (readCount % MAX_POINTS_PER_UPLOAD == MAX_POINTS_PER_UPLOAD) {
|
||||
if (!prepareAndUploadPoints(track, locations, false)) {
|
||||
Log.d(TAG, "Unable to upload points");
|
||||
return false;
|
||||
}
|
||||
updateProgress(readCount, locationsCount);
|
||||
locations.clear();
|
||||
}
|
||||
lastLocation = location;
|
||||
}
|
||||
|
||||
// Do a final upload with the remaining locations
|
||||
if (!prepareAndUploadPoints(track, locations, true)) {
|
||||
Log.d(TAG, "Unable to upload points");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an end marker
|
||||
if (lastLocation != null) {
|
||||
StringUtils stringUtils = new StringUtils(context);
|
||||
track.setDescription("<p>" + track.getDescription() + "</p><p>"
|
||||
+ stringUtils.generateTrackDescription(track, distances, elevations) + "</p>");
|
||||
String name = context.getString(R.string.marker_label_end, track.getName());
|
||||
if (!createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END)) {
|
||||
Log.d(TAG, "Unable to create the end marker");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
if (locationsCursor != null) {
|
||||
locationsCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares and uploads a list of locations from a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param locations the locations from the track
|
||||
* @param lastBatch true if it is the last batch of locations
|
||||
*/
|
||||
private boolean prepareAndUploadPoints(Track track, List<Location> locations, boolean lastBatch) {
|
||||
int numLocations = locations.size();
|
||||
if (numLocations < 2) {
|
||||
Log.d(TAG, "Not preparing/uploading, too few points");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepare locations
|
||||
ArrayList<Track> splitTracks = prepareLocations(track, locations);
|
||||
|
||||
boolean onlyOneSegment = lastBatch && currentSegment == 1 && splitTracks.size() == 1;
|
||||
|
||||
// Upload segments
|
||||
for (Track splitTrack : splitTracks) {
|
||||
if (!onlyOneSegment) {
|
||||
splitTrack.setName(context.getString(
|
||||
R.string.send_google_track_part_label, splitTrack.getName(), currentSegment));
|
||||
}
|
||||
if (!createNewLineString(splitTrack)) {
|
||||
Log.d(TAG, "Upload points failed");
|
||||
return false;
|
||||
}
|
||||
currentSegment++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a list of locations to send to Google Fusion Tables.
|
||||
* Splits the locations into segments if necessary.
|
||||
*
|
||||
* @param track the track
|
||||
* @param locations the list of locations
|
||||
* @return an array of split segments.
|
||||
*/
|
||||
private ArrayList<Track> prepareLocations(Track track, List<Location> locations) {
|
||||
ArrayList<Track> splitTracks = new ArrayList<Track>();
|
||||
|
||||
// Create a new segment
|
||||
Track segment = new Track();
|
||||
segment.setId(track.getId());
|
||||
segment.setName(track.getName());
|
||||
segment.setDescription("");
|
||||
segment.setCategory(track.getCategory());
|
||||
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
segmentStats.setStartTime(trackStats.getStartTime());
|
||||
segmentStats.setStopTime(trackStats.getStopTime());
|
||||
boolean startNewTrackSegment = false;
|
||||
for (Location loc : locations) {
|
||||
// Latitude is greater than 90 if the location is invalid. Do not add to the
|
||||
// segment.
|
||||
if (loc.getLatitude() > 90) {
|
||||
startNewTrackSegment = true;
|
||||
}
|
||||
|
||||
if (startNewTrackSegment) {
|
||||
// Close the last segment
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
startNewTrackSegment = false;
|
||||
segment = new Track();
|
||||
segment.setId(track.getId());
|
||||
segment.setName(track.getName());
|
||||
segment.setDescription("");
|
||||
segment.setCategory(track.getCategory());
|
||||
segmentStats = segment.getStatistics();
|
||||
}
|
||||
|
||||
if (loc.getLatitude() <= 90) {
|
||||
segment.addLocation(loc);
|
||||
|
||||
// For a new segment, sets its start time using the first available
|
||||
// location time.
|
||||
if (segmentStats.getStartTime() < 0) {
|
||||
segmentStats.setStartTime(loc.getTime());
|
||||
}
|
||||
segmentStats.setStopTime(loc.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
return splitTracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a track segment for sending to Google Fusion Tables. The main
|
||||
* steps are:
|
||||
* <ul>
|
||||
* <li>set the stop time</li>
|
||||
* <li>decimate locations precision</li>
|
||||
* </ul>
|
||||
* The prepared track will be added to the splitTracks.
|
||||
*
|
||||
* @param segment the track segment
|
||||
* @param splitTracks an array of track segments
|
||||
*/
|
||||
private void prepareTrackSegment(Track segment, ArrayList<Track> splitTracks) {
|
||||
// For a new segment, sets it stop time
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
ArrayList<Location> locations = segment.getLocations();
|
||||
if (segmentStats.getStopTime() < 0 && locations.size() > 0) {
|
||||
Location lastLocation = locations.get(locations.size() - 1);
|
||||
segmentStats.setStopTime(lastLocation.getTime());
|
||||
}
|
||||
|
||||
// Decimate to 2 meter precision. Fusion Tables doesn't like too many
|
||||
// points.
|
||||
LocationUtils.decimate(segment, 2.0);
|
||||
splitTracks.add(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads all the waypoints.
|
||||
*
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean uploadWaypoints() {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = myTracksProviderUtils.getWaypointsCursor(
|
||||
trackId, 0, Constants.MAX_LOADED_WAYPOINTS_POINTS);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// This will skip the first waypoint (it carries the stats for the
|
||||
// track).
|
||||
while (cursor.moveToNext()) {
|
||||
Waypoint wpt = myTracksProviderUtils.createWaypoint(cursor);
|
||||
if (!createNewPoint(
|
||||
wpt.getName(), wpt.getDescription(), wpt.getLocation(), MARKER_TYPE_WAYPOINT)) {
|
||||
Log.d(TAG, "Upload waypoints failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row in Google Fusion Tables representing a marker as a
|
||||
* point.
|
||||
*
|
||||
* @param name the marker name
|
||||
* @param description the marker description
|
||||
* @param location the marker location
|
||||
* @param type the marker type
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewPoint(
|
||||
String name, String description, Location location, String type) {
|
||||
String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
|
||||
+ SendFusionTablesUtils.formatSqlValues(
|
||||
name, description, SendFusionTablesUtils.getKmlPoint(location), type);
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row in Google Fusion Tables representing the track as a
|
||||
* line segment.
|
||||
*
|
||||
* @param track the track
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean createNewLineString(Track track) {
|
||||
String query = "INSERT INTO " + tableId + " (name,description,geometry) VALUES "
|
||||
+ SendFusionTablesUtils.formatSqlValues(track.getName(), track.getDescription(),
|
||||
SendFusionTablesUtils.getKmlLineString(track.getLocations()));
|
||||
return sendQuery(query, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a query to Google Fusion Tables.
|
||||
*
|
||||
* @param query the Fusion Tables SQL query
|
||||
* @param setTableId true to set the table id
|
||||
* @return true if success.
|
||||
*/
|
||||
private boolean sendQuery(String query, boolean setTableId) {
|
||||
Log.d(TAG, "SendQuery: " + query);
|
||||
|
||||
if (isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GenericUrl url = new GenericUrl(FUSION_TABLES_BASE_URL);
|
||||
String sql = SQL_KEY + URLEncoder.encode(query);
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
|
||||
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
|
||||
HttpRequest request;
|
||||
try {
|
||||
request = httpRequestFactory.buildPostRequest(url, inputStreamContent);
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
GoogleHeaders headers = new GoogleHeaders();
|
||||
headers.setApplicationName(APP_NAME_PREFIX + SystemUtils.getMyTracksVersion(context));
|
||||
headers.gdataVersion = GDATA_VERSION;
|
||||
headers.setGoogleLogin(authToken);
|
||||
headers.setContentType(CONTENT_TYPE);
|
||||
request.setHeaders(headers);
|
||||
|
||||
HttpResponse response;
|
||||
try {
|
||||
response = request.execute();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
success = response.isSuccessStatusCode();
|
||||
if (success) {
|
||||
InputStream content;
|
||||
try {
|
||||
content = response.getContent();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
if (setTableId) {
|
||||
tableId = SendFusionTablesUtils.getTableId(content);
|
||||
if (tableId == null) {
|
||||
Log.d(TAG, "tableId is null");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG,
|
||||
"sendQuery failed: " + response.getStatusMessage() + ": " + response.getStatusCode());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the progress based on the number of locations uploaded.
|
||||
*
|
||||
* @param uploaded the number of uploaded locations
|
||||
* @param total the number of total locations
|
||||
*/
|
||||
private void updateProgress(int uploaded, int total) {
|
||||
double totalPercentage = uploaded / total;
|
||||
double scaledPercentage = totalPercentage
|
||||
* (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN;
|
||||
publishProgress((int) scaledPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user