forked from upstream-mirrors/OpenTracks
Upgrade send to fusion table to Fusion Table api v1.
This commit is contained in:
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.io.drive;
|
|||||||
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.io.sendtogoogle.AbstractSendAsyncTask;
|
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
|
||||||
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||||
import com.google.android.gms.auth.GoogleAuthException;
|
import com.google.android.gms.auth.GoogleAuthException;
|
||||||
import com.google.android.gms.auth.UserRecoverableAuthException;
|
import com.google.android.gms.auth.UserRecoverableAuthException;
|
||||||
@@ -69,8 +70,8 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean performTask() {
|
protected boolean performTask() {
|
||||||
try {
|
try {
|
||||||
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
|
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
|
||||||
context, account.name);
|
context, account.name, SendToGoogleUtils.DRIVE_SCOPE);
|
||||||
if (credential == null) {
|
if (credential == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -102,16 +103,18 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
addPermission(drive, id);
|
addPermission(drive, id);
|
||||||
return true;
|
return true;
|
||||||
} catch (UserRecoverableAuthIOException e) {
|
|
||||||
SyncUtils.sendNotification(context, account.name, e.getIntent());
|
|
||||||
return false;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return retryTask();
|
|
||||||
} catch (UserRecoverableAuthException e) {
|
} catch (UserRecoverableAuthException e) {
|
||||||
SyncUtils.sendNotification(context, account.name, e.getIntent());
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
return false;
|
return false;
|
||||||
} catch (GoogleAuthException e) {
|
} catch (GoogleAuthException e) {
|
||||||
return retryTask();
|
return retryTask();
|
||||||
|
} catch (UserRecoverableAuthIOException e) {
|
||||||
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return retryTask();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+152
-255
@@ -11,39 +11,33 @@ import com.google.android.apps.mytracks.content.Waypoint;
|
|||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
|
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.gms.auth.GoogleAuthException;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.gms.auth.UserRecoverableAuthException;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.api.client.googleapis.GoogleHeaders;
|
import com.google.api.client.extensions.android.http.AndroidHttp;
|
||||||
import com.google.api.client.googleapis.MethodOverride;
|
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||||
import com.google.api.client.http.GenericUrl;
|
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
|
||||||
import com.google.api.client.http.HttpRequest;
|
import com.google.api.client.json.gson.GsonFactory;
|
||||||
import com.google.api.client.http.HttpRequestFactory;
|
import com.google.api.services.fusiontables.Fusiontables;
|
||||||
import com.google.api.client.http.HttpResponse;
|
import com.google.api.services.fusiontables.Fusiontables.Query.Sql;
|
||||||
import com.google.api.client.http.HttpTransport;
|
import com.google.api.services.fusiontables.model.Column;
|
||||||
import com.google.api.client.http.InputStreamContent;
|
import com.google.api.services.fusiontables.model.PointStyle;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.api.services.fusiontables.model.StyleFunction;
|
||||||
|
import com.google.api.services.fusiontables.model.StyleSetting;
|
||||||
|
import com.google.api.services.fusiontables.model.Table;
|
||||||
|
import com.google.api.services.fusiontables.model.Template;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AuthenticatorException;
|
|
||||||
import android.accounts.OperationCanceledException;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AsyncTask to send a track to Google Fusion Tables.
|
* AsyncTask to send a track to Google Fusion Tables.
|
||||||
@@ -52,20 +46,10 @@ import java.util.Vector;
|
|||||||
*/
|
*/
|
||||||
public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
||||||
|
|
||||||
@VisibleForTesting
|
private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
|
||||||
public static final String APP_NAME_PREFIX = "Google-MyTracks-";
|
|
||||||
private static final String SQL_KEY = "sql=";
|
|
||||||
@VisibleForTesting
|
|
||||||
public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
|
|
||||||
@VisibleForTesting
|
|
||||||
public 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 int MAX_POINTS_PER_UPLOAD = 2048;
|
||||||
@VisibleForTesting
|
|
||||||
public static final String GDATA_VERSION = "2";
|
|
||||||
|
|
||||||
private static final int PROGRESS_CREATE_TABLE = 0;
|
private static final int PROGRESS_CREATE_TABLE = 0;
|
||||||
private static final int PROGRESS_UNLIST_TABLE = 5;
|
private static final int PROGRESS_SET_STYLE = 5;
|
||||||
private static final int PROGRESS_UPLOAD_DATA_MIN = 10;
|
private static final int PROGRESS_UPLOAD_DATA_MIN = 10;
|
||||||
private static final int PROGRESS_UPLOAD_DATA_MAX = 90;
|
private static final int PROGRESS_UPLOAD_DATA_MAX = 90;
|
||||||
private static final int PROGRESS_UPLOAD_WAYPOINTS = 95;
|
private static final int PROGRESS_UPLOAD_WAYPOINTS = 95;
|
||||||
@@ -78,17 +62,11 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
private static final String MARKER_TYPE_WAYPOINT = "large_blue";
|
private static final String MARKER_TYPE_WAYPOINT = "large_blue";
|
||||||
private static final String MARKER_TYPE_STATISTICS = "large_yellow";
|
private static final String MARKER_TYPE_STATISTICS = "large_yellow";
|
||||||
|
|
||||||
private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final long trackId;
|
private final long trackId;
|
||||||
private final Account account;
|
private final Account account;
|
||||||
|
private final Context context;
|
||||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||||
private final HttpRequestFactory httpRequestFactory;
|
|
||||||
|
|
||||||
// The following variables are for per upload states
|
|
||||||
private String authToken;
|
|
||||||
private String tableId;
|
|
||||||
int currentSegment;
|
int currentSegment;
|
||||||
|
|
||||||
public SendFusionTablesAsyncTask(
|
public SendFusionTablesAsyncTask(
|
||||||
@@ -96,119 +74,131 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
super(activity);
|
super(activity);
|
||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
||||||
context = activity.getApplicationContext();
|
context = activity.getApplicationContext();
|
||||||
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
HttpTransport transport = ApiAdapterFactory.getApiAdapter().getHttpTransport();
|
|
||||||
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeConnection() {
|
protected void closeConnection() {}
|
||||||
// No action needed for Google Fusion Tables
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveResult() {
|
protected void saveResult() {}
|
||||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
|
||||||
if (track == null) {
|
|
||||||
Log.d(TAG, "No track for " + trackId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
track.setTableId(tableId);
|
|
||||||
myTracksProviderUtils.updateTrack(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean performTask() {
|
protected boolean performTask() {
|
||||||
// Reset the per upload states
|
|
||||||
authToken = null;
|
|
||||||
tableId = null;
|
|
||||||
currentSegment = 1;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
authToken = AccountManager.get(context)
|
// Reset the per upload states
|
||||||
.blockingGetAuthToken(account, SendFusionTablesUtils.SERVICE, false);
|
currentSegment = 1;
|
||||||
} catch (OperationCanceledException e) {
|
|
||||||
Log.d(TAG, "Unable to get auth token", e);
|
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
|
||||||
return retryTask();
|
context, account.name, SendToGoogleUtils.FUSION_TABLES_SCOPE);
|
||||||
} catch (AuthenticatorException e) {
|
if (credential == null) {
|
||||||
Log.d(TAG, "Unable to get auth token", e);
|
return false;
|
||||||
|
}
|
||||||
|
Fusiontables fusiontables = new Fusiontables.Builder(
|
||||||
|
AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential).build();
|
||||||
|
|
||||||
|
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||||
|
if (track == null) {
|
||||||
|
Log.d(TAG, "No track for " + trackId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new table
|
||||||
|
publishProgress(PROGRESS_CREATE_TABLE);
|
||||||
|
String tableId = createNewTable(fusiontables, track);
|
||||||
|
if (tableId == null) {
|
||||||
|
return retryTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
publishProgress(PROGRESS_SET_STYLE);
|
||||||
|
setStyle(fusiontables, tableId);
|
||||||
|
setTemplate(fusiontables, tableId);
|
||||||
|
|
||||||
|
// Upload all the track points plus the start and end markers
|
||||||
|
publishProgress(PROGRESS_UPLOAD_DATA_MIN);
|
||||||
|
if (!uploadAllTrackPoints(fusiontables, tableId, track)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload all the waypoints
|
||||||
|
publishProgress(PROGRESS_UPLOAD_WAYPOINTS);
|
||||||
|
if (!uploadWaypoints(fusiontables, tableId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
track.setTableId(tableId);
|
||||||
|
myTracksProviderUtils.updateTrack(track);
|
||||||
|
|
||||||
|
publishProgress(PROGRESS_COMPLETE);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (UserRecoverableAuthException e) {
|
||||||
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.FUSION_TABLES_NOTIFICATION_ID);
|
||||||
|
return false;
|
||||||
|
} catch (GoogleAuthException e) {
|
||||||
return retryTask();
|
return retryTask();
|
||||||
|
} catch (UserRecoverableAuthIOException e) {
|
||||||
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.FUSION_TABLES_NOTIFICATION_ID);
|
||||||
|
return false;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(TAG, "Unable to get auth token", e);
|
|
||||||
return retryTask();
|
return retryTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
|
||||||
if (track == null) {
|
|
||||||
Log.d(TAG, "No track for " + trackId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new table
|
|
||||||
publishProgress(PROGRESS_CREATE_TABLE);
|
|
||||||
if (!createNewTable(track)) {
|
|
||||||
// Retry upload in case the auth token is invalid
|
|
||||||
return retryTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void invalidateToken() {
|
protected void invalidateToken() {}
|
||||||
AccountManager.get(context).invalidateAuthToken(Constants.ACCOUNT_TYPE, authToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new table.
|
* Creates a new table.
|
||||||
*
|
*
|
||||||
|
* @param fusiontables fusion tables
|
||||||
* @param track the track
|
* @param track the track
|
||||||
* @return true if success.
|
* @return the table id if success.
|
||||||
*/
|
*/
|
||||||
private boolean createNewTable(Track track) {
|
private String createNewTable(Fusiontables fusiontables, Track track) throws IOException {
|
||||||
String query = "CREATE TABLE '" + SendFusionTablesUtils.escapeSqlString(track.getName())
|
Table table = new Table();
|
||||||
+ "' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
|
table.setName(track.getName());
|
||||||
return sendQuery(query, true);
|
table.setDescription(track.getDescription());
|
||||||
|
table.setIsExportable(true);
|
||||||
|
table.setColumns(Arrays.asList(new Column().setName("name").setType("STRING"),
|
||||||
|
new Column().setName("description").setType("STRING"),
|
||||||
|
new Column().setName("geometry").setType("LOCATION"),
|
||||||
|
new Column().setName("icon").setType("STRING")));
|
||||||
|
return fusiontables.table().insert(table).execute().getTableId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStyle(Fusiontables fusiontables, String tableId) throws IOException {
|
||||||
|
StyleFunction styleFunction = new StyleFunction();
|
||||||
|
styleFunction.setColumnName("icon");
|
||||||
|
PointStyle pointStyle = new PointStyle();
|
||||||
|
pointStyle.setIconStyler(styleFunction);
|
||||||
|
StyleSetting styleSetting = new StyleSetting();
|
||||||
|
styleSetting.setTableId(tableId);
|
||||||
|
styleSetting.setMarkerOptions(pointStyle);
|
||||||
|
|
||||||
|
fusiontables.style().insert(tableId, styleSetting).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTemplate(Fusiontables fusiontables, String tableId) throws IOException {
|
||||||
|
Template template = new Template();
|
||||||
|
template.setTableId(tableId);
|
||||||
|
template.setAutomaticColumnNames(Arrays.asList("name", "description"));
|
||||||
|
fusiontables.template().insert(tableId, template).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlists a table.
|
* Uploads all the points in a track. *
|
||||||
*
|
|
||||||
* @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 fusiontables fusion tables
|
||||||
|
* @param tableId the table id
|
||||||
* @param track the track
|
* @param track the track
|
||||||
* @return true if success.
|
* @return true if success.
|
||||||
*/
|
*/
|
||||||
private boolean uploadAllTrackPoints(Track track) {
|
private boolean uploadAllTrackPoints(Fusiontables fusiontables, String tableId, Track track)
|
||||||
|
throws IOException {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = myTracksProviderUtils.getTrackPointCursor(trackId, -1L, -1, false);
|
cursor = myTracksProviderUtils.getTrackPointCursor(trackId, -1L, -1, false);
|
||||||
@@ -221,15 +211,6 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||||
Location lastLocation = null;
|
Location lastLocation = null;
|
||||||
|
|
||||||
// For chart server, limit the number of elevation readings to 250.
|
|
||||||
int elevationSamplingFrequency = Math.max(1, (int) (count / 250.0));
|
|
||||||
Vector<Double> distances = new Vector<Double>();
|
|
||||||
Vector<Double> elevations = new Vector<Double>();
|
|
||||||
TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(
|
|
||||||
track.getTripStatistics().getStartTime());
|
|
||||||
int minRecordingDistance = PreferencesUtils.getInt(context,
|
|
||||||
R.string.min_recording_distance_key, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
cursor.moveToPosition(i);
|
cursor.moveToPosition(i);
|
||||||
|
|
||||||
@@ -239,17 +220,9 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// Create a start marker
|
// Create a start marker
|
||||||
String name = context.getString(R.string.marker_label_start, track.getName());
|
String name = context.getString(R.string.marker_label_start, track.getName());
|
||||||
if (!createNewPoint(name, "", location, MARKER_TYPE_START)) {
|
createNewPoint(fusiontables, tableId, name, "", location, MARKER_TYPE_START);
|
||||||
Log.d(TAG, "Unable to create the start marker");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tripStatisticsUpdater.addLocation(location, minRecordingDistance);
|
|
||||||
if (i % elevationSamplingFrequency == 0) {
|
|
||||||
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
|
||||||
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
|
||||||
}
|
|
||||||
if (LocationUtils.isValidLocation(location)) {
|
if (LocationUtils.isValidLocation(location)) {
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
}
|
}
|
||||||
@@ -257,7 +230,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
// Upload periodically
|
// Upload periodically
|
||||||
int readCount = i + 1;
|
int readCount = i + 1;
|
||||||
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
||||||
if (!prepareAndUploadPoints(track, locations, false)) {
|
if (!prepareAndUploadPoints(fusiontables, tableId, track, locations, false)) {
|
||||||
Log.d(TAG, "Unable to upload points");
|
Log.d(TAG, "Unable to upload points");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -267,25 +240,18 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do a final upload with the remaining locations
|
// Do a final upload with the remaining locations
|
||||||
if (!prepareAndUploadPoints(track, locations, true)) {
|
if (!prepareAndUploadPoints(fusiontables, tableId, track, locations, true)) {
|
||||||
Log.d(TAG, "Unable to upload points");
|
Log.d(TAG, "Unable to upload points");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an end marker
|
// Create an end marker
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
|
||||||
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
|
||||||
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
|
||||||
track.setDescription(
|
|
||||||
descriptionGenerator.generateTrackDescription(track, distances, elevations, true));
|
|
||||||
String name = context.getString(R.string.marker_label_end, track.getName());
|
String name = context.getString(R.string.marker_label_end, track.getName());
|
||||||
if (!createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END)) {
|
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
||||||
Log.d(TAG, "Unable to create the end marker");
|
String description = descriptionGenerator.generateTrackDescription(track, null, null, true);
|
||||||
return false;
|
createNewPoint(fusiontables, tableId, name, description, lastLocation, MARKER_TYPE_END);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
@@ -297,11 +263,14 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
/**
|
/**
|
||||||
* Prepares and uploads a list of locations from a track.
|
* Prepares and uploads a list of locations from a track.
|
||||||
*
|
*
|
||||||
|
* @param fusiontables fusion tables
|
||||||
|
* @param tableId the table id
|
||||||
* @param track the track
|
* @param track the track
|
||||||
* @param locations the locations from the track
|
* @param locations the locations from the track
|
||||||
* @param lastBatch true if it is the last batch of locations
|
* @param lastBatch true if it is the last batch of locations
|
||||||
*/
|
*/
|
||||||
private boolean prepareAndUploadPoints(Track track, List<Location> locations, boolean lastBatch) {
|
private boolean prepareAndUploadPoints(Fusiontables fusiontables, String tableId, Track track,
|
||||||
|
List<Location> locations, boolean lastBatch) throws IOException {
|
||||||
// Prepare locations
|
// Prepare locations
|
||||||
ArrayList<Track> splitTracks = SendToGoogleUtils.prepareLocations(track, locations);
|
ArrayList<Track> splitTracks = SendToGoogleUtils.prepareLocations(track, locations);
|
||||||
|
|
||||||
@@ -312,10 +281,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
splitTrack.setName(context.getString(
|
splitTrack.setName(context.getString(
|
||||||
R.string.send_google_track_part_label, splitTrack.getName(), currentSegment));
|
R.string.send_google_track_part_label, splitTrack.getName(), currentSegment));
|
||||||
}
|
}
|
||||||
if (!createNewLineString(splitTrack)) {
|
createNewLineString(fusiontables, tableId, splitTrack);
|
||||||
Log.d(TAG, "Upload points failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
currentSegment++;
|
currentSegment++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -324,24 +290,28 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
/**
|
/**
|
||||||
* Uploads all the waypoints.
|
* Uploads all the waypoints.
|
||||||
*
|
*
|
||||||
|
* @param fusiontables fusion tables
|
||||||
|
* @param tableId the table id
|
||||||
* @return true if success.
|
* @return true if success.
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private boolean uploadWaypoints() {
|
private boolean uploadWaypoints(Fusiontables fusiontables, String tableId) throws IOException {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = myTracksProviderUtils.getWaypointCursor(
|
cursor = myTracksProviderUtils.getWaypointCursor(
|
||||||
trackId, -1L, Constants.MAX_LOADED_WAYPOINTS_POINTS);
|
trackId, -1L, Constants.MAX_LOADED_WAYPOINTS_POINTS);
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
// This will skip the first waypoint (it carries the stats for the
|
/*
|
||||||
// track).
|
* This will skip the first waypoint (it carries the stats for the
|
||||||
|
* track).
|
||||||
|
*/
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
Waypoint wpt = myTracksProviderUtils.createWaypoint(cursor);
|
Waypoint wpt = myTracksProviderUtils.createWaypoint(cursor);
|
||||||
String type = wpt.getType() == WaypointType.STATISTICS ? MARKER_TYPE_STATISTICS
|
String type = wpt.getType() == WaypointType.STATISTICS ? MARKER_TYPE_STATISTICS
|
||||||
: MARKER_TYPE_WAYPOINT;
|
: MARKER_TYPE_WAYPOINT;
|
||||||
if (!createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(), type)) {
|
String description = wpt.getDescription().replaceAll("\n", "<br>");
|
||||||
Log.d(TAG, "Upload waypoints failed");
|
createNewPoint(
|
||||||
return false;
|
fusiontables, tableId, wpt.getName(), description, wpt.getLocation(), type);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -355,110 +325,37 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
/**
|
/**
|
||||||
* Creates a new row in Google Fusion Tables representing a marker as a point.
|
* Creates a new row in Google Fusion Tables representing a marker as a point.
|
||||||
*
|
*
|
||||||
|
* @param fusiontables fusion tables
|
||||||
|
* @param tableId the table id
|
||||||
* @param name the marker name
|
* @param name the marker name
|
||||||
* @param description the marker description
|
* @param description the marker description
|
||||||
* @param location the marker location
|
* @param location the marker location
|
||||||
* @param type the marker type
|
* @param type the marker type
|
||||||
* @return true if success.
|
|
||||||
*/
|
*/
|
||||||
private boolean createNewPoint(String name, String description, Location location, String type) {
|
private void createNewPoint(Fusiontables fusiontables, String tableId, String name,
|
||||||
String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
|
String description, Location location, String type) throws IOException {
|
||||||
+ SendFusionTablesUtils.formatSqlValues(
|
String values = SendFusionTablesUtils.formatSqlValues(
|
||||||
name, description, SendFusionTablesUtils.getKmlPoint(location), type);
|
name, description, SendFusionTablesUtils.getKmlPoint(location), type);
|
||||||
return sendQuery(query, false);
|
Sql sql = fusiontables.query()
|
||||||
|
.sql("INSERT INTO " + tableId + " (name,description,geometry,icon) VALUES " + values);
|
||||||
|
sql.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new row in Google Fusion Tables representing the track as a line
|
* Creates a new row in Google Fusion Tables representing the track as a line
|
||||||
* segment.
|
* segment.
|
||||||
*
|
*
|
||||||
|
* @param fusiontables fusion tables
|
||||||
|
* @param tableId the table id
|
||||||
* @param track the track
|
* @param track the track
|
||||||
* @return true if success.
|
|
||||||
*/
|
*/
|
||||||
private boolean createNewLineString(Track track) {
|
private void createNewLineString(Fusiontables fusiontables, String tableId, Track track)
|
||||||
String query = "INSERT INTO " + tableId
|
throws IOException {
|
||||||
+ " (name,description,geometry) VALUES " + SendFusionTablesUtils.formatSqlValues(
|
String values = SendFusionTablesUtils.formatSqlValues(track.getName(), track.getDescription(),
|
||||||
track.getName(), track.getDescription(),
|
SendFusionTablesUtils.getKmlLineString(track.getLocations()));
|
||||||
SendFusionTablesUtils.getKmlLineString(track.getLocations()));
|
Sql sql = fusiontables.query()
|
||||||
return sendQuery(query, false);
|
.sql("INSERT INTO " + tableId + " (name,description,geometry) VALUES " + values);
|
||||||
}
|
sql.execute();
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
try {
|
|
||||||
sql = SQL_KEY + URLEncoder.encode(query, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e1) {
|
|
||||||
Log.d(TAG, "Unable to encode query", e1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(sql.getBytes());
|
|
||||||
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
|
|
||||||
HttpRequest request;
|
|
||||||
try {
|
|
||||||
request = httpRequestFactory.buildPostRequest(url, inputStreamContent);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "Unable to build request", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GoogleHeaders headers = new GoogleHeaders();
|
|
||||||
headers.setApplicationName(APP_NAME_PREFIX + SystemUtils.getMyTracksVersion(context));
|
|
||||||
headers.setGDataVersion(GDATA_VERSION);
|
|
||||||
headers.setGoogleLogin(authToken);
|
|
||||||
headers.setContentType(CONTENT_TYPE);
|
|
||||||
request.setHeaders(headers);
|
|
||||||
|
|
||||||
HttpResponse response;
|
|
||||||
try {
|
|
||||||
response = request.execute();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "Unable to execute request", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
boolean isSuccess = response.isSuccessStatusCode();
|
|
||||||
if (isSuccess) {
|
|
||||||
InputStream content = null;
|
|
||||||
try {
|
|
||||||
content = response.getContent();
|
|
||||||
if (setTableId) {
|
|
||||||
tableId = SendFusionTablesUtils.getTableId(content);
|
|
||||||
if (tableId == null) {
|
|
||||||
Log.d(TAG, "tableId is null");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "Unable to get response", e);
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
if (content != null) {
|
|
||||||
try {
|
|
||||||
content.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "Unable to close content", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG,
|
|
||||||
"sendQuery failed: " + response.getStatusMessage() + ": " + response.getStatusCode());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-45
@@ -22,9 +22,6 @@ import com.google.common.annotations.VisibleForTesting;
|
|||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -107,7 +104,8 @@ public class SendFusionTablesUtils {
|
|||||||
* @param string the string
|
* @param string the string
|
||||||
* @return the escaped string.
|
* @return the escaped string.
|
||||||
*/
|
*/
|
||||||
public static String escapeSqlString(String string) {
|
@VisibleForTesting
|
||||||
|
static String escapeSqlString(String string) {
|
||||||
return string.replaceAll("'", "''");
|
return string.replaceAll("'", "''");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,45 +158,4 @@ public class SendFusionTablesUtils {
|
|||||||
builder.append(location.getAltitude());
|
builder.append(location.getAltitude());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the table id from an input streawm.
|
|
||||||
*
|
|
||||||
* @param inputStream input stream
|
|
||||||
* @return table id or null if not available.
|
|
||||||
*/
|
|
||||||
public static String getTableId(InputStream inputStream) {
|
|
||||||
if (inputStream == null) {
|
|
||||||
Log.d(TAG, "inputStream is null");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte[] result = new byte[1024];
|
|
||||||
int read;
|
|
||||||
try {
|
|
||||||
read = inputStream.read(result);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "Unable to read result", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (read == -1) {
|
|
||||||
Log.d(TAG, "no data read");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String s;
|
|
||||||
try {
|
|
||||||
s = new String(result, 0, read, UTF8);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
Log.d(TAG, "Unable to parse result", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] lines = s.split("\n");
|
|
||||||
if (lines.length > 1 && lines[0].equals(TABLE_ID)) {
|
|
||||||
// returns the next line
|
|
||||||
return lines[1];
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Response is not valid: " + s);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-46
@@ -20,13 +20,11 @@ import com.google.android.apps.mytracks.Constants;
|
|||||||
import com.google.android.apps.mytracks.io.docs.SendDocsActivity;
|
import com.google.android.apps.mytracks.io.docs.SendDocsActivity;
|
||||||
import com.google.android.apps.mytracks.io.drive.SendDriveActivity;
|
import com.google.android.apps.mytracks.io.drive.SendDriveActivity;
|
||||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
|
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
|
||||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils;
|
|
||||||
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
|
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
|
||||||
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
|
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
|
||||||
import com.google.android.apps.mytracks.io.gdata.maps.MapsConstants;
|
import com.google.android.apps.mytracks.io.gdata.maps.MapsConstants;
|
||||||
import com.google.android.apps.mytracks.io.maps.ChooseMapActivity;
|
import com.google.android.apps.mytracks.io.maps.ChooseMapActivity;
|
||||||
import com.google.android.apps.mytracks.io.maps.SendMapsActivity;
|
import com.google.android.apps.mytracks.io.maps.SendMapsActivity;
|
||||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -76,16 +74,16 @@ public class AccountChooserActivity extends Activity {
|
|||||||
if (accounts.length == 1) {
|
if (accounts.length == 1) {
|
||||||
sendRequest.setAccount(accounts[0]);
|
sendRequest.setAccount(accounts[0]);
|
||||||
PreferencesUtils.setString(this, R.string.google_account_key, accounts[0].name);
|
PreferencesUtils.setString(this, R.string.google_account_key, accounts[0].name);
|
||||||
checkDrivePermission(accounts[0].name);
|
checkDrivePermission();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String googleAccount = PreferencesUtils.getString(this, R.string.google_account_key,
|
String googleAccount = PreferencesUtils.getString(
|
||||||
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
this, R.string.google_account_key, PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
||||||
for (int i = 0; i < accounts.length; i++) {
|
for (int i = 0; i < accounts.length; i++) {
|
||||||
if (accounts[i].name.equals(googleAccount)) {
|
if (accounts[i].name.equals(googleAccount)) {
|
||||||
sendRequest.setAccount(accounts[i]);
|
sendRequest.setAccount(accounts[i]);
|
||||||
checkDrivePermission(accounts[i].name);
|
checkDrivePermission();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,14 +93,22 @@ public class AccountChooserActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case SyncUtils.DRIVE_PERMISSION_REQUEST_CODE:
|
case SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE:
|
||||||
SyncUtils.cancelNotification(this);
|
SendToGoogleUtils.cancelNotification(this, SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
driveCallback.onSuccess();
|
driveCallback.onSuccess();
|
||||||
} else {
|
} else {
|
||||||
driveCallback.onFailure();
|
driveCallback.onFailure();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SendToGoogleUtils.FUSION_TABLES_PERMISSION_REQUEST_CODE:
|
||||||
|
SendToGoogleUtils.cancelNotification(this, SendToGoogleUtils.FUSION_TABLES_NOTIFICATION_ID);
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
fusionTablesCallback.onSuccess();
|
||||||
|
} else {
|
||||||
|
fusionTablesCallback.onFailure();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
@@ -112,22 +118,18 @@ public class AccountChooserActivity extends Activity {
|
|||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case DIALOG_NO_ACCOUNT_ID:
|
case DIALOG_NO_ACCOUNT_ID:
|
||||||
return new AlertDialog.Builder(this)
|
return new AlertDialog.Builder(this).setCancelable(true)
|
||||||
.setCancelable(true)
|
|
||||||
.setMessage(R.string.send_google_no_account_message)
|
.setMessage(R.string.send_google_no_account_message)
|
||||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(DialogInterface dialog) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
})
|
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||||
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
})
|
}).setTitle(R.string.send_google_no_account_title).create();
|
||||||
.setTitle(R.string.send_google_no_account_title)
|
|
||||||
.create();
|
|
||||||
case DIALOG_CHOOSER_ID:
|
case DIALOG_CHOOSER_ID:
|
||||||
return createChooserDialog();
|
return createChooserDialog();
|
||||||
default:
|
default:
|
||||||
@@ -143,98 +145,110 @@ public class AccountChooserActivity extends Activity {
|
|||||||
for (int i = 0; i < accounts.length; i++) {
|
for (int i = 0; i < accounts.length; i++) {
|
||||||
choices[i] = accounts[i].name;
|
choices[i] = accounts[i].name;
|
||||||
}
|
}
|
||||||
return new AlertDialog.Builder(this)
|
return new AlertDialog.Builder(this).setCancelable(true)
|
||||||
.setCancelable(true)
|
|
||||||
.setNegativeButton(R.string.generic_cancel, new DialogInterface.OnClickListener() {
|
.setNegativeButton(R.string.generic_cancel, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
})
|
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
@Override
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(DialogInterface dialog) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
})
|
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||||
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
Account account = accounts[position];
|
Account account = accounts[position];
|
||||||
PreferencesUtils.setString(
|
PreferencesUtils.setString(
|
||||||
AccountChooserActivity.this, R.string.google_account_key, account.name);
|
AccountChooserActivity.this, R.string.google_account_key, account.name);
|
||||||
sendRequest.setAccount(account);
|
sendRequest.setAccount(account);
|
||||||
checkDrivePermission(account.name);
|
checkDrivePermission();
|
||||||
}
|
}
|
||||||
})
|
}).setSingleChoiceItems(choices, 0, null)
|
||||||
.setSingleChoiceItems(choices, 0, null)
|
.setTitle(R.string.send_google_choose_account_title).create();
|
||||||
.setTitle(R.string.send_google_choose_account_title)
|
|
||||||
.create();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the Drive permission.
|
* Checks the Drive permission.
|
||||||
*
|
|
||||||
* @param accountName the account name
|
|
||||||
*/
|
*/
|
||||||
private void checkDrivePermission(String accountName) {
|
private void checkDrivePermission() {
|
||||||
if (sendRequest.isSendDrive()) {
|
if (sendRequest.isSendDrive()) {
|
||||||
SyncUtils.checkPermissionByActivity(this, accountName, driveCallback);
|
SendToGoogleUtils.checkPermissionByActivity(this, sendRequest.getAccount().name,
|
||||||
|
SendToGoogleUtils.DRIVE_SCOPE, SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE,
|
||||||
|
driveCallback);
|
||||||
} else {
|
} else {
|
||||||
driveCallback.onSuccess();
|
driveCallback.onSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Fusion Tables permission.
|
||||||
|
*/
|
||||||
|
private void checkFusionTablesPermission() {
|
||||||
|
if (sendRequest.isSendFusionTables()) {
|
||||||
|
SendToGoogleUtils.checkPermissionByActivity(this, sendRequest.getAccount().name,
|
||||||
|
SendToGoogleUtils.FUSION_TABLES_SCOPE,
|
||||||
|
SendToGoogleUtils.FUSION_TABLES_PERMISSION_REQUEST_CODE, fusionTablesCallback);
|
||||||
|
} else {
|
||||||
|
fusionTablesCallback.onSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PermissionCallback spreadsheetsCallback = new PermissionCallback() {
|
private PermissionCallback spreadsheetsCallback = new PermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
startNextActivity();
|
startNextActivity();
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
handleNoAccountPermission();
|
handleNoAccountPermission();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private PermissionCallback docsCallback = new PermissionCallback() {
|
private PermissionCallback docsCallback = new PermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
getPermission(SpreadsheetsClient.SERVICE, sendRequest.isSendDocs(), spreadsheetsCallback);
|
getPermission(SpreadsheetsClient.SERVICE, sendRequest.isSendDocs(), spreadsheetsCallback);
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
handleNoAccountPermission();
|
handleNoAccountPermission();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private PermissionCallback fusionTablesCallback = new PermissionCallback() {
|
private PermissionCallback fusionTablesCallback = new PermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
getPermission(DocumentsClient.SERVICE, sendRequest.isSendDocs(), docsCallback);
|
getPermission(DocumentsClient.SERVICE, sendRequest.isSendDocs(), docsCallback);
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
handleNoAccountPermission();
|
handleNoAccountPermission();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private PermissionCallback mapsCallback = new PermissionCallback() {
|
private PermissionCallback mapsCallback = new PermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
getPermission(
|
checkFusionTablesPermission();
|
||||||
SendFusionTablesUtils.SERVICE, sendRequest.isSendFusionTables(), fusionTablesCallback);
|
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
handleNoAccountPermission();
|
handleNoAccountPermission();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private PermissionCallback driveCallback = new PermissionCallback() {
|
private PermissionCallback driveCallback = new PermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
|
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
public void onFailure() {
|
public void onFailure() {
|
||||||
handleNoAccountPermission();
|
handleNoAccountPermission();
|
||||||
}
|
}
|
||||||
@@ -252,7 +266,7 @@ public class AccountChooserActivity extends Activity {
|
|||||||
if (needPermission) {
|
if (needPermission) {
|
||||||
AccountManager.get(this).getAuthToken(sendRequest.getAccount(), authTokenType, null, this,
|
AccountManager.get(this).getAuthToken(sendRequest.getAccount(), authTokenType, null, this,
|
||||||
new AccountManagerCallback<Bundle>() {
|
new AccountManagerCallback<Bundle>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(AccountManagerFuture<Bundle> future) {
|
public void run(AccountManagerFuture<Bundle> future) {
|
||||||
try {
|
try {
|
||||||
if (future.getResult().getString(AccountManager.KEY_AUTHTOKEN) != null) {
|
if (future.getResult().getString(AccountManager.KEY_AUTHTOKEN) != null) {
|
||||||
@@ -290,7 +304,6 @@ public class AccountChooserActivity extends Activity {
|
|||||||
* !sendMaps && !sendFusionTables && sendDocs -> {@link SendDocsActivity}
|
* !sendMaps && !sendFusionTables && sendDocs -> {@link SendDocsActivity}
|
||||||
* <p>
|
* <p>
|
||||||
* !sendMaps && !sendFusionTables && !sendDocs -> {@link UploadResultActivity}
|
* !sendMaps && !sendFusionTables && !sendDocs -> {@link UploadResultActivity}
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private void startNextActivity() {
|
private void startNextActivity() {
|
||||||
Class<?> next;
|
Class<?> next;
|
||||||
|
|||||||
@@ -19,11 +19,25 @@ package com.google.android.apps.mytracks.io.sendtogoogle;
|
|||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
|
import com.google.android.gms.auth.GoogleAuthException;
|
||||||
|
import com.google.android.gms.auth.UserRecoverableAuthException;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||||
|
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
|
||||||
|
import com.google.api.services.drive.DriveScopes;
|
||||||
|
import com.google.api.services.fusiontables.FusiontablesScopes;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -36,6 +50,16 @@ public class SendToGoogleUtils {
|
|||||||
|
|
||||||
private static final String TAG = SendToGoogleUtils.class.getSimpleName();
|
private static final String TAG = SendToGoogleUtils.class.getSimpleName();
|
||||||
|
|
||||||
|
// Request code to obtain Drive permission
|
||||||
|
public static final int DRIVE_PERMISSION_REQUEST_CODE = 1;
|
||||||
|
public static final String DRIVE_SCOPE = DriveScopes.DRIVE;
|
||||||
|
public static final int DRIVE_NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
|
// Request code to obtain Fusion Tables permission
|
||||||
|
public static final int FUSION_TABLES_PERMISSION_REQUEST_CODE = 2;
|
||||||
|
public static final String FUSION_TABLES_SCOPE = FusiontablesScopes.FUSIONTABLES;
|
||||||
|
public static final int FUSION_TABLES_NOTIFICATION_ID = 2;
|
||||||
|
|
||||||
private SendToGoogleUtils() {}
|
private SendToGoogleUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,4 +139,105 @@ public class SendToGoogleUtils {
|
|||||||
splitTracks.add(segment);
|
splitTracks.add(segment);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the google account credential.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param accountName the account name
|
||||||
|
* @param scope the scope
|
||||||
|
*/
|
||||||
|
public static GoogleAccountCredential getGoogleAccountCredential(
|
||||||
|
Context context, String accountName, String scope) throws IOException, GoogleAuthException {
|
||||||
|
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(context, scope);
|
||||||
|
credential.setSelectedAccountName(accountName);
|
||||||
|
credential.getToken();
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks permission by an activity. Will start an activity to request
|
||||||
|
* permission using the request code.
|
||||||
|
*
|
||||||
|
* @param activity the activity
|
||||||
|
* @param accountName the account name
|
||||||
|
* @param scope the scope
|
||||||
|
* @param requestCode the request code
|
||||||
|
* @param permissionCallback the permission callback
|
||||||
|
*/
|
||||||
|
public static void checkPermissionByActivity(final Activity activity, final String accountName,
|
||||||
|
final String scope, final int requestCode, final PermissionCallback permissionCallback) {
|
||||||
|
Thread thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
getGoogleAccountCredential(activity, accountName, scope);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
permissionCallback.onSuccess();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (UserRecoverableAuthException e) {
|
||||||
|
activity.startActivityForResult(e.getIntent(), requestCode);
|
||||||
|
} catch (GoogleAuthException e) {
|
||||||
|
Log.e(TAG, "GoogleAuthException", e);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
permissionCallback.onFailure();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (UserRecoverableAuthIOException e) {
|
||||||
|
activity.startActivityForResult(e.getIntent(), requestCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "IOException", e);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
permissionCallback.onFailure();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a notification to request permission.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param accountName the account name
|
||||||
|
* @param intent the intent
|
||||||
|
* @param notificaitonId the notification id
|
||||||
|
*/
|
||||||
|
public static void sendNotification(
|
||||||
|
Context context, String accountName, Intent intent, int notificaitonId) {
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_FROM_BACKGROUND);
|
||||||
|
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||||
|
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setAutoCancel(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setContentText(context.getString(R.string.permission_request_message, accountName))
|
||||||
|
.setContentTitle(context.getString(R.string.permission_request_title))
|
||||||
|
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
.setTicker(context.getString(R.string.permission_request_title));
|
||||||
|
NotificationManager notificationManager = (NotificationManager) context.getSystemService(
|
||||||
|
Context.NOTIFICATION_SERVICE);
|
||||||
|
notificationManager.notify(notificaitonId, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels any notification to request a permission.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param notificationId the notification id
|
||||||
|
*/
|
||||||
|
public static void cancelNotification(Context context, int notificationId) {
|
||||||
|
NotificationManager notificationManager = (NotificationManager) context.getSystemService(
|
||||||
|
Context.NOTIFICATION_SERVICE);
|
||||||
|
notificationManager.cancel(notificationId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.io.sync;
|
|||||||
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.io.file.KmlImporter;
|
import com.google.android.apps.mytracks.io.file.KmlImporter;
|
||||||
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.gms.auth.GoogleAuthException;
|
import com.google.android.gms.auth.GoogleAuthException;
|
||||||
import com.google.android.gms.auth.UserRecoverableAuthException;
|
import com.google.android.gms.auth.UserRecoverableAuthException;
|
||||||
@@ -101,8 +102,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
|
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
|
||||||
context, account.name);
|
context, account.name, SendToGoogleUtils.DRIVE_SCOPE);
|
||||||
if (credential == null) {
|
if (credential == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -125,11 +126,13 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
|||||||
}
|
}
|
||||||
insertNewTracks(folderId);
|
insertNewTracks(folderId);
|
||||||
} catch (UserRecoverableAuthException e) {
|
} catch (UserRecoverableAuthException e) {
|
||||||
SyncUtils.sendNotification(context, account.name, e.getIntent());
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
} catch (GoogleAuthException e) {
|
} catch (GoogleAuthException e) {
|
||||||
Log.e(TAG, "GoogleAuthException", e);
|
Log.e(TAG, "GoogleAuthException", e);
|
||||||
} catch (UserRecoverableAuthIOException e) {
|
} catch (UserRecoverableAuthIOException e) {
|
||||||
SyncUtils.sendNotification(context, account.name, e.getIntent());
|
SendToGoogleUtils.sendNotification(
|
||||||
|
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "IOException", e);
|
Log.e(TAG, "IOException", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,8 @@ import com.google.android.apps.mytracks.content.Track;
|
|||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.PermissionCallback;
|
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.gms.auth.GoogleAuthException;
|
|
||||||
import com.google.android.gms.auth.UserRecoverableAuthException;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.api.client.extensions.android.http.AndroidHttp;
|
import com.google.api.client.extensions.android.http.AndroidHttp;
|
||||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||||
@@ -35,7 +32,6 @@ import com.google.api.client.http.FileContent;
|
|||||||
import com.google.api.client.json.gson.GsonFactory;
|
import com.google.api.client.json.gson.GsonFactory;
|
||||||
import com.google.api.services.drive.Drive;
|
import com.google.api.services.drive.Drive;
|
||||||
import com.google.api.services.drive.Drive.Files.List;
|
import com.google.api.services.drive.Drive.Files.List;
|
||||||
import com.google.api.services.drive.DriveScopes;
|
|
||||||
import com.google.api.services.drive.model.File;
|
import com.google.api.services.drive.model.File;
|
||||||
import com.google.api.services.drive.model.FileList;
|
import com.google.api.services.drive.model.FileList;
|
||||||
import com.google.api.services.drive.model.ParentReference;
|
import com.google.api.services.drive.model.ParentReference;
|
||||||
@@ -43,14 +39,9 @@ import com.google.common.annotations.VisibleForTesting;
|
|||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -70,9 +61,6 @@ import java.util.Locale;
|
|||||||
*/
|
*/
|
||||||
public class SyncUtils {
|
public class SyncUtils {
|
||||||
|
|
||||||
// Request code to obtain Drive permission
|
|
||||||
public static final int DRIVE_PERMISSION_REQUEST_CODE = 1;
|
|
||||||
|
|
||||||
// Get tracks with drive id
|
// Get tracks with drive id
|
||||||
public static final String DRIVE_ID_TRACKS_QUERY = TracksColumns.DRIVEID + " IS NOT NULL AND "
|
public static final String DRIVE_ID_TRACKS_QUERY = TracksColumns.DRIVEID + " IS NOT NULL AND "
|
||||||
+ TracksColumns.DRIVEID + "!=''";
|
+ TracksColumns.DRIVEID + "!=''";
|
||||||
@@ -103,106 +91,9 @@ public class SyncUtils {
|
|||||||
|
|
||||||
private static final String TAG = SyncUtils.class.getSimpleName();
|
private static final String TAG = SyncUtils.class.getSimpleName();
|
||||||
private static final String SYNC_AUTHORITY = "com.google.android.maps.mytracks";
|
private static final String SYNC_AUTHORITY = "com.google.android.maps.mytracks";
|
||||||
private static final int NOTIFICATION_ID = 0;
|
|
||||||
|
|
||||||
private SyncUtils() {}
|
private SyncUtils() {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the google account credential.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param accountName the account name
|
|
||||||
*/
|
|
||||||
public static GoogleAccountCredential getGoogleAccountCredential(
|
|
||||||
Context context, String accountName) throws IOException, GoogleAuthException {
|
|
||||||
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
|
|
||||||
context, DriveScopes.DRIVE);
|
|
||||||
credential.setSelectedAccountName(accountName);
|
|
||||||
credential.getToken();
|
|
||||||
return credential;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks permission by an activity. Will start an activity to request
|
|
||||||
* permission with request code {@link #DRIVE_PERMISSION_REQUEST_CODE}.
|
|
||||||
*
|
|
||||||
* @param activity the activity
|
|
||||||
* @param accountName the account name
|
|
||||||
* @param permissionCallback the permission callback
|
|
||||||
*/
|
|
||||||
public static void checkPermissionByActivity(final Activity activity, final String accountName,
|
|
||||||
final PermissionCallback permissionCallback) {
|
|
||||||
Thread thread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
getGoogleAccountCredential(activity, accountName);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
permissionCallback.onSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (UserRecoverableAuthException e) {
|
|
||||||
activity.startActivityForResult(e.getIntent(), DRIVE_PERMISSION_REQUEST_CODE);
|
|
||||||
} catch (GoogleAuthException e) {
|
|
||||||
Log.e(TAG, "GoogleAuthException", e);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
permissionCallback.onFailure();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (UserRecoverableAuthIOException e) {
|
|
||||||
activity.startActivityForResult(e.getIntent(), DRIVE_PERMISSION_REQUEST_CODE);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "IOException", e);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
permissionCallback.onFailure();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a notification to request permission.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param accountName the account name
|
|
||||||
* @param intent the intent
|
|
||||||
*/
|
|
||||||
public static void sendNotification(Context context, String accountName, Intent intent) {
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_FROM_BACKGROUND);
|
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
|
||||||
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setContentText(context.getString(R.string.permission_request_message, accountName))
|
|
||||||
.setContentTitle(context.getString(R.string.permission_request_title))
|
|
||||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
|
||||||
.setTicker(context.getString(R.string.permission_request_title));
|
|
||||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(
|
|
||||||
Context.NOTIFICATION_SERVICE);
|
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels any notification to request drive permission.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
*/
|
|
||||||
public static void cancelNotification(Context context) {
|
|
||||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(
|
|
||||||
Context.NOTIFICATION_SERVICE);
|
|
||||||
notificationManager.cancel(NOTIFICATION_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syncs now for the current account.
|
* Syncs now for the current account.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.Constants;
|
|||||||
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.io.sendtogoogle.PermissionCallback;
|
import com.google.android.apps.mytracks.io.sendtogoogle.PermissionCallback;
|
||||||
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
@@ -143,8 +144,8 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case SyncUtils.DRIVE_PERMISSION_REQUEST_CODE:
|
case SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE:
|
||||||
SyncUtils.cancelNotification(this);
|
SendToGoogleUtils.cancelNotification(this, SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
permissionCallback.onSuccess();
|
permissionCallback.onSuccess();
|
||||||
} else {
|
} else {
|
||||||
@@ -173,8 +174,9 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity {
|
|||||||
String googleAccount = PreferencesUtils.getString(
|
String googleAccount = PreferencesUtils.getString(
|
||||||
GoogleSettingsActivity.this, R.string.google_account_key,
|
GoogleSettingsActivity.this, R.string.google_account_key,
|
||||||
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
||||||
SyncUtils.checkPermissionByActivity(
|
SendToGoogleUtils.checkPermissionByActivity(GoogleSettingsActivity.this,
|
||||||
GoogleSettingsActivity.this, googleAccount, permissionCallback);
|
googleAccount, SendToGoogleUtils.DRIVE_SCOPE,
|
||||||
|
SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE, permissionCallback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|||||||
-60
@@ -20,8 +20,6 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
|
|||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
@@ -225,62 +223,4 @@ public class SendFusionTablesUtilsTest extends TestCase {
|
|||||||
SendFusionTablesUtils.appendLocation(location, builder);
|
SendFusionTablesUtils.appendLocation(location, builder);
|
||||||
assertEquals("10.1,20.2,30.3", builder.toString());
|
assertEquals("10.1,20.2,30.3", builder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with a null
|
|
||||||
* inputstream.
|
|
||||||
*/
|
|
||||||
public void testGetTableId_null() {
|
|
||||||
assertEquals(null, SendFusionTablesUtils.getTableId(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an
|
|
||||||
* inputstream containing no data.
|
|
||||||
*/
|
|
||||||
public void testGetTableId_no_data() {
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(new byte[0]);
|
|
||||||
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an empty
|
|
||||||
* inputstream.
|
|
||||||
*/
|
|
||||||
public void testGetTableId_empty() {
|
|
||||||
String string = "";
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
|
|
||||||
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an one
|
|
||||||
* line inputstream.
|
|
||||||
*/
|
|
||||||
public void testGetTableId_one_line() {
|
|
||||||
String string = "tableid";
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
|
|
||||||
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with an
|
|
||||||
* inputstream not containing "tableid".
|
|
||||||
*/
|
|
||||||
public void testGetTableId_no_table_id() {
|
|
||||||
String string = "error\n123";
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(string.getBytes());
|
|
||||||
assertEquals(null, SendFusionTablesUtils.getTableId(inputStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link SendFusionTablesUtils#getTableId(InputStream)} with a valid
|
|
||||||
* inputstream.
|
|
||||||
*/
|
|
||||||
public void testGetTableId() {
|
|
||||||
String string = "tableid\n123";
|
|
||||||
InputStream inputStream = null;
|
|
||||||
inputStream = new ByteArrayInputStream(string.getBytes());
|
|
||||||
assertEquals("123", SendFusionTablesUtils.getTableId(inputStream));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+10
-5
@@ -17,7 +17,6 @@ package com.google.android.apps.mytracks.endtoendtest;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.io.docs.SendDocsUtils;
|
import com.google.android.apps.mytracks.io.docs.SendDocsUtils;
|
||||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesAsyncTask;
|
|
||||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils;
|
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils;
|
||||||
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
||||||
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
|
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
|
||||||
@@ -63,11 +62,17 @@ import java.util.Locale;
|
|||||||
* @author Youtao Liu
|
* @author Youtao Liu
|
||||||
*/
|
*/
|
||||||
public class GoogleUtils {
|
public class GoogleUtils {
|
||||||
|
|
||||||
public static final String DOCUMENT_NAME_PREFIX = "My Tracks";
|
public static final String DOCUMENT_NAME_PREFIX = "My Tracks";
|
||||||
public static final String ACCOUNT_NAME_1 = "mytrackstest@gmail.com";
|
public static final String ACCOUNT_NAME_1 = "mytrackstest@gmail.com";
|
||||||
public static final String ACCOUNT_NAME_2 = "mytrackstest2@gmail.com";
|
public static final String ACCOUNT_NAME_2 = "mytrackstest2@gmail.com";
|
||||||
public static final String SPREADSHEET_NAME = DOCUMENT_NAME_PREFIX + "-" + EndToEndTestUtils.activityType;
|
public static final String SPREADSHEET_NAME = DOCUMENT_NAME_PREFIX + "-" + EndToEndTestUtils.activityType;
|
||||||
|
|
||||||
|
private static final String APP_NAME_PREFIX = "Google-MyTracks-";
|
||||||
|
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
|
||||||
|
private static final String FUSION_TABLES_BASE_URL = "https://www.google.com/fusiontables/api/query";
|
||||||
|
private static final String GDATA_VERSION = "2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the account to access Google Services.
|
* Gets the account to access Google Services.
|
||||||
*
|
*
|
||||||
@@ -408,7 +413,7 @@ public class GoogleUtils {
|
|||||||
String fusionTableAuthToken = AccountManager.get(context).blockingGetAuthToken(getAccount(context),
|
String fusionTableAuthToken = AccountManager.get(context).blockingGetAuthToken(getAccount(context),
|
||||||
SendFusionTablesUtils.SERVICE, false);
|
SendFusionTablesUtils.SERVICE, false);
|
||||||
|
|
||||||
GenericUrl url = new GenericUrl(SendFusionTablesAsyncTask.FUSION_TABLES_BASE_URL);
|
GenericUrl url = new GenericUrl(FUSION_TABLES_BASE_URL);
|
||||||
String sql = "sql=" + query;
|
String sql = "sql=" + query;
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(sql.getBytes());
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(sql.getBytes());
|
||||||
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
|
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
|
||||||
@@ -418,11 +423,11 @@ public class GoogleUtils {
|
|||||||
.createRequestFactory(new MethodOverride())).buildPostRequest(url, inputStreamContent);
|
.createRequestFactory(new MethodOverride())).buildPostRequest(url, inputStreamContent);
|
||||||
|
|
||||||
GoogleHeaders headers = new GoogleHeaders();
|
GoogleHeaders headers = new GoogleHeaders();
|
||||||
headers.setApplicationName(SendFusionTablesAsyncTask.APP_NAME_PREFIX
|
headers.setApplicationName(APP_NAME_PREFIX
|
||||||
+ SystemUtils.getMyTracksVersion(context));
|
+ SystemUtils.getMyTracksVersion(context));
|
||||||
headers.setGDataVersion(SendFusionTablesAsyncTask.GDATA_VERSION);
|
headers.setGDataVersion(GDATA_VERSION);
|
||||||
headers.setGoogleLogin(fusionTableAuthToken);
|
headers.setGoogleLogin(fusionTableAuthToken);
|
||||||
headers.setContentType(SendFusionTablesAsyncTask.CONTENT_TYPE);
|
headers.setContentType(CONTENT_TYPE);
|
||||||
request.setHeaders(headers);
|
request.setHeaders(headers);
|
||||||
|
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
|
|||||||
+3
-2
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.endtoendtest.sync;
|
|||||||
import com.google.android.apps.mytracks.TrackListActivity;
|
import com.google.android.apps.mytracks.TrackListActivity;
|
||||||
import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils;
|
import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils;
|
||||||
import com.google.android.apps.mytracks.endtoendtest.GoogleUtils;
|
import com.google.android.apps.mytracks.endtoendtest.GoogleUtils;
|
||||||
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.gms.auth.GoogleAuthException;
|
import com.google.android.gms.auth.GoogleAuthException;
|
||||||
@@ -119,8 +120,8 @@ public class SyncTestUtils {
|
|||||||
public static Drive getGoogleDrive(Context context) throws IOException, GoogleAuthException {
|
public static Drive getGoogleDrive(Context context) throws IOException, GoogleAuthException {
|
||||||
String googleAccount = PreferencesUtils.getString(
|
String googleAccount = PreferencesUtils.getString(
|
||||||
context, R.string.google_account_key, PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
context, R.string.google_account_key, PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
|
||||||
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
|
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
|
||||||
context, googleAccount);
|
context, googleAccount, SendToGoogleUtils.DRIVE_SCOPE);
|
||||||
return SyncUtils.getDriveService(credential);
|
return SyncUtils.getDriveService(credential);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user