Upgrade send to fusion table to Fusion Table api v1.

This commit is contained in:
Jimmy Shih
2013-02-08 15:55:14 -08:00
parent 111cebf0ec
commit ab61869956
11 changed files with 391 additions and 554 deletions
@@ -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.Track;
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.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.UserRecoverableAuthException;
@@ -69,8 +70,8 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
@Override
protected boolean performTask() {
try {
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
context, account.name);
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
context, account.name, SendToGoogleUtils.DRIVE_SCOPE);
if (credential == null) {
return false;
}
@@ -102,16 +103,18 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
}
addPermission(drive, id);
return true;
} catch (UserRecoverableAuthIOException e) {
SyncUtils.sendNotification(context, account.name, e.getIntent());
return false;
} catch (IOException e) {
return retryTask();
} catch (UserRecoverableAuthException e) {
SyncUtils.sendNotification(context, account.name, e.getIntent());
SendToGoogleUtils.sendNotification(
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
return false;
} catch (GoogleAuthException e) {
return retryTask();
} catch (UserRecoverableAuthIOException e) {
SendToGoogleUtils.sendNotification(
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
return false;
} catch (IOException e) {
return retryTask();
}
}
@@ -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.io.sendtogoogle.AbstractSendAsyncTask;
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.PreferencesUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
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.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.common.annotations.VisibleForTesting;
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.UserRecoverableAuthIOException;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.fusiontables.Fusiontables;
import com.google.api.services.fusiontables.Fusiontables.Query.Sql;
import com.google.api.services.fusiontables.model.Column;
import com.google.api.services.fusiontables.model.PointStyle;
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.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
/**
* AsyncTask to send a track to Google Fusion Tables.
@@ -52,20 +46,10 @@ import java.util.Vector;
*/
public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
@VisibleForTesting
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 String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
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_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_MAX = 90;
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_STATISTICS = "large_yellow";
private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
private final Context context;
private final long trackId;
private final Account account;
private final Context context;
private final MyTracksProviderUtils myTracksProviderUtils;
private final HttpRequestFactory httpRequestFactory;
// The following variables are for per upload states
private String authToken;
private String tableId;
int currentSegment;
public SendFusionTablesAsyncTask(
@@ -96,119 +74,131 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
super(activity);
this.trackId = trackId;
this.account = account;
context = activity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
HttpTransport transport = ApiAdapterFactory.getApiAdapter().getHttpTransport();
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
}
@Override
protected void closeConnection() {
// No action needed for Google Fusion Tables
}
protected void closeConnection() {}
@Override
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);
}
protected void saveResult() {}
@Override
protected boolean performTask() {
// Reset the per upload states
authToken = null;
tableId = null;
currentSegment = 1;
try {
authToken = AccountManager.get(context)
.blockingGetAuthToken(account, SendFusionTablesUtils.SERVICE, false);
} catch (OperationCanceledException e) {
Log.d(TAG, "Unable to get auth token", e);
return retryTask();
} catch (AuthenticatorException e) {
Log.d(TAG, "Unable to get auth token", e);
// Reset the per upload states
currentSegment = 1;
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
context, account.name, SendToGoogleUtils.FUSION_TABLES_SCOPE);
if (credential == null) {
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();
} catch (UserRecoverableAuthIOException e) {
SendToGoogleUtils.sendNotification(
context, account.name, e.getIntent(), SendToGoogleUtils.FUSION_TABLES_NOTIFICATION_ID);
return false;
} catch (IOException e) {
Log.d(TAG, "Unable to get auth token", e);
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
protected void invalidateToken() {
AccountManager.get(context).invalidateAuthToken(Constants.ACCOUNT_TYPE, authToken);
}
protected void invalidateToken() {}
/**
* Creates a new table.
*
* @param fusiontables fusion tables
* @param track the track
* @return true if success.
* @return the table id 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);
private String createNewTable(Fusiontables fusiontables, Track track) throws IOException {
Table table = new Table();
table.setName(track.getName());
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.
*
* @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.
* Uploads all the points in a track. *
*
* @param fusiontables fusion tables
* @param tableId the table id
* @param track the track
* @return true if success.
*/
private boolean uploadAllTrackPoints(Track track) {
private boolean uploadAllTrackPoints(Fusiontables fusiontables, String tableId, Track track)
throws IOException {
Cursor cursor = null;
try {
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);
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++) {
cursor.moveToPosition(i);
@@ -239,17 +220,9 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
if (i == 0) {
// 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;
}
createNewPoint(fusiontables, tableId, name, "", location, MARKER_TYPE_START);
}
tripStatisticsUpdater.addLocation(location, minRecordingDistance);
if (i % elevationSamplingFrequency == 0) {
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
}
if (LocationUtils.isValidLocation(location)) {
lastLocation = location;
}
@@ -257,7 +230,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
// Upload periodically
int readCount = i + 1;
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");
return false;
}
@@ -267,25 +240,18 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
}
// 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");
return false;
}
// Create an end marker
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));
if (lastLocation != null) {
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;
}
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
String description = descriptionGenerator.generateTrackDescription(track, null, null, true);
createNewPoint(fusiontables, tableId, name, description, lastLocation, MARKER_TYPE_END);
}
return true;
} finally {
if (cursor != null) {
@@ -297,11 +263,14 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
/**
* Prepares and uploads a list of locations from a track.
*
* @param fusiontables fusion tables
* @param tableId the table id
* @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) {
private boolean prepareAndUploadPoints(Fusiontables fusiontables, String tableId, Track track,
List<Location> locations, boolean lastBatch) throws IOException {
// Prepare locations
ArrayList<Track> splitTracks = SendToGoogleUtils.prepareLocations(track, locations);
@@ -312,10 +281,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
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;
}
createNewLineString(fusiontables, tableId, splitTrack);
currentSegment++;
}
return true;
@@ -324,24 +290,28 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
/**
* Uploads all the waypoints.
*
* @param fusiontables fusion tables
* @param tableId the table id
* @return true if success.
* @throws IOException
*/
private boolean uploadWaypoints() {
private boolean uploadWaypoints(Fusiontables fusiontables, String tableId) throws IOException {
Cursor cursor = null;
try {
cursor = myTracksProviderUtils.getWaypointCursor(
trackId, -1L, Constants.MAX_LOADED_WAYPOINTS_POINTS);
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()) {
Waypoint wpt = myTracksProviderUtils.createWaypoint(cursor);
String type = wpt.getType() == WaypointType.STATISTICS ? MARKER_TYPE_STATISTICS
: MARKER_TYPE_WAYPOINT;
if (!createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(), type)) {
Log.d(TAG, "Upload waypoints failed");
return false;
}
String description = wpt.getDescription().replaceAll("\n", "<br>");
createNewPoint(
fusiontables, tableId, wpt.getName(), description, wpt.getLocation(), type);
}
}
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.
*
* @param fusiontables fusion tables
* @param tableId the table id
* @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);
private void createNewPoint(Fusiontables fusiontables, String tableId, String name,
String description, Location location, String type) throws IOException {
String values = SendFusionTablesUtils.formatSqlValues(
name, description, SendFusionTablesUtils.getKmlPoint(location), type);
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
* segment.
*
* @param fusiontables fusion tables
* @param tableId the table id
* @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;
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;
private void createNewLineString(Fusiontables fusiontables, String tableId, Track track)
throws IOException {
String values = SendFusionTablesUtils.formatSqlValues(track.getName(), track.getDescription(),
SendFusionTablesUtils.getKmlLineString(track.getLocations()));
Sql sql = fusiontables.query()
.sql("INSERT INTO " + tableId + " (name,description,geometry) VALUES " + values);
sql.execute();
}
/**
@@ -22,9 +22,6 @@ import com.google.common.annotations.VisibleForTesting;
import android.location.Location;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Locale;
@@ -107,7 +104,8 @@ public class SendFusionTablesUtils {
* @param string the string
* @return the escaped string.
*/
public static String escapeSqlString(String string) {
@VisibleForTesting
static String escapeSqlString(String string) {
return string.replaceAll("'", "''");
}
@@ -160,45 +158,4 @@ public class SendFusionTablesUtils {
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;
}
}
}
@@ -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.drive.SendDriveActivity;
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.SpreadsheetsClient;
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.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.PreferencesUtils;
import com.google.android.maps.mytracks.R;
@@ -50,12 +48,12 @@ import java.io.IOException;
/**
* A chooser to select an account.
*
*
* @author Jimmy Shih
*/
public class AccountChooserActivity extends Activity {
private static final String TAG = AccountChooserActivity.class.getSimpleName();
private static final String TAG = AccountChooserActivity.class.getSimpleName();
private static final int DIALOG_NO_ACCOUNT_ID = 0;
private static final int DIALOG_CHOOSER_ID = 1;
@@ -72,20 +70,20 @@ public class AccountChooserActivity extends Activity {
showDialog(DIALOG_NO_ACCOUNT_ID);
return;
}
if (accounts.length == 1) {
sendRequest.setAccount(accounts[0]);
PreferencesUtils.setString(this, R.string.google_account_key, accounts[0].name);
checkDrivePermission(accounts[0].name);
checkDrivePermission();
return;
}
String googleAccount = PreferencesUtils.getString(this, R.string.google_account_key,
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
String googleAccount = PreferencesUtils.getString(
this, R.string.google_account_key, PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
for (int i = 0; i < accounts.length; i++) {
if (accounts[i].name.equals(googleAccount)) {
sendRequest.setAccount(accounts[i]);
checkDrivePermission(accounts[i].name);
checkDrivePermission();
return;
}
}
@@ -95,39 +93,43 @@ public class AccountChooserActivity extends Activity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SyncUtils.DRIVE_PERMISSION_REQUEST_CODE:
SyncUtils.cancelNotification(this);
case SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE:
SendToGoogleUtils.cancelNotification(this, SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
if (resultCode == Activity.RESULT_OK) {
driveCallback.onSuccess();
} else {
driveCallback.onFailure();
}
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:
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_NO_ACCOUNT_ID:
return new AlertDialog.Builder(this)
.setCancelable(true)
return new AlertDialog.Builder(this).setCancelable(true)
.setMessage(R.string.send_google_no_account_message)
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
})
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setTitle(R.string.send_google_no_account_title)
.create();
}).setTitle(R.string.send_google_no_account_title).create();
case DIALOG_CHOOSER_ID:
return createChooserDialog();
default:
@@ -143,103 +145,115 @@ public class AccountChooserActivity extends Activity {
for (int i = 0; i < accounts.length; i++) {
choices[i] = accounts[i].name;
}
return new AlertDialog.Builder(this)
.setCancelable(true)
return new AlertDialog.Builder(this).setCancelable(true)
.setNegativeButton(R.string.generic_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
})
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
}).setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
Account account = accounts[position];
PreferencesUtils.setString(
AccountChooserActivity.this, R.string.google_account_key, account.name);
sendRequest.setAccount(account);
checkDrivePermission(account.name);
checkDrivePermission();
}
})
.setSingleChoiceItems(choices, 0, null)
.setTitle(R.string.send_google_choose_account_title)
.create();
}).setSingleChoiceItems(choices, 0, null)
.setTitle(R.string.send_google_choose_account_title).create();
}
/**
* Checks the Drive permission.
*
* @param accountName the account name
*/
private void checkDrivePermission(String accountName) {
private void checkDrivePermission() {
if (sendRequest.isSendDrive()) {
SyncUtils.checkPermissionByActivity(this, accountName, driveCallback);
SendToGoogleUtils.checkPermissionByActivity(this, sendRequest.getAccount().name,
SendToGoogleUtils.DRIVE_SCOPE, SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE,
driveCallback);
} else {
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() {
@Override
@Override
public void onSuccess() {
startNextActivity();
}
@Override
}
@Override
public void onFailure() {
handleNoAccountPermission();
}
};
private PermissionCallback docsCallback = new PermissionCallback() {
@Override
@Override
public void onSuccess() {
getPermission(SpreadsheetsClient.SERVICE, sendRequest.isSendDocs(), spreadsheetsCallback);
}
@Override
}
@Override
public void onFailure() {
handleNoAccountPermission();
}
};
private PermissionCallback fusionTablesCallback = new PermissionCallback() {
@Override
@Override
public void onSuccess() {
getPermission(DocumentsClient.SERVICE, sendRequest.isSendDocs(), docsCallback);
}
@Override
}
@Override
public void onFailure() {
handleNoAccountPermission();
}
};
private PermissionCallback mapsCallback = new PermissionCallback() {
@Override
@Override
public void onSuccess() {
getPermission(
SendFusionTablesUtils.SERVICE, sendRequest.isSendFusionTables(), fusionTablesCallback);
checkFusionTablesPermission();
}
@Override
@Override
public void onFailure() {
handleNoAccountPermission();
}
};
private PermissionCallback driveCallback = new PermissionCallback() {
@Override
@Override
public void onSuccess() {
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
}
@Override
@Override
public void onFailure() {
handleNoAccountPermission();
}
};
/**
* Gets the user permission to access a service.
*
@@ -252,7 +266,7 @@ public class AccountChooserActivity extends Activity {
if (needPermission) {
AccountManager.get(this).getAuthToken(sendRequest.getAccount(), authTokenType, null, this,
new AccountManagerCallback<Bundle>() {
@Override
@Override
public void run(AccountManagerFuture<Bundle> future) {
try {
if (future.getResult().getString(AccountManager.KEY_AUTHTOKEN) != null) {
@@ -290,7 +304,6 @@ public class AccountChooserActivity extends Activity {
* !sendMaps && !sendFusionTables && sendDocs -> {@link SendDocsActivity}
* <p>
* !sendMaps && !sendFusionTables && !sendDocs -> {@link UploadResultActivity}
*
*/
private void startNextActivity() {
Class<?> next;
@@ -310,7 +323,7 @@ public class AccountChooserActivity extends Activity {
startActivity(intent);
finish();
}
/**
* Handles when not able to get account permission.
*/
@@ -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.stats.TripStatistics;
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 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.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -36,6 +50,16 @@ public class SendToGoogleUtils {
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() {}
/**
@@ -115,4 +139,105 @@ public class SendToGoogleUtils {
splitTracks.add(segment);
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.Track;
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.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.UserRecoverableAuthException;
@@ -101,8 +102,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
}
try {
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
context, account.name);
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
context, account.name, SendToGoogleUtils.DRIVE_SCOPE);
if (credential == null) {
return;
}
@@ -125,11 +126,13 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
}
insertNewTracks(folderId);
} catch (UserRecoverableAuthException e) {
SyncUtils.sendNotification(context, account.name, e.getIntent());
SendToGoogleUtils.sendNotification(
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
} catch (GoogleAuthException e) {
Log.e(TAG, "GoogleAuthException", 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) {
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.io.file.TrackFileFormat;
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.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.api.client.extensions.android.http.AndroidHttp;
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.services.drive.Drive;
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.FileList;
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.AccountManager;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.FileInputStream;
@@ -70,9 +61,6 @@ import java.util.Locale;
*/
public class SyncUtils {
// Request code to obtain Drive permission
public static final int DRIVE_PERMISSION_REQUEST_CODE = 1;
// Get tracks with drive id
public static final String DRIVE_ID_TRACKS_QUERY = TracksColumns.DRIVEID + " IS NOT NULL AND "
+ TracksColumns.DRIVEID + "!=''";
@@ -103,106 +91,9 @@ public class SyncUtils {
private static final String TAG = SyncUtils.class.getSimpleName();
private static final String SYNC_AUTHORITY = "com.google.android.maps.mytracks";
private static final int NOTIFICATION_ID = 0;
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.
*
@@ -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.Track;
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.util.DialogUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
@@ -143,8 +144,8 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SyncUtils.DRIVE_PERMISSION_REQUEST_CODE:
SyncUtils.cancelNotification(this);
case SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE:
SendToGoogleUtils.cancelNotification(this, SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
if (resultCode == Activity.RESULT_OK) {
permissionCallback.onSuccess();
} else {
@@ -173,8 +174,9 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity {
String googleAccount = PreferencesUtils.getString(
GoogleSettingsActivity.this, R.string.google_account_key,
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
SyncUtils.checkPermissionByActivity(
GoogleSettingsActivity.this, googleAccount, permissionCallback);
SendToGoogleUtils.checkPermissionByActivity(GoogleSettingsActivity.this,
googleAccount, SendToGoogleUtils.DRIVE_SCOPE,
SendToGoogleUtils.DRIVE_PERMISSION_REQUEST_CODE, permissionCallback);
}
});
break;
@@ -20,8 +20,6 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import junit.framework.TestCase;
@@ -225,62 +223,4 @@ public class SendFusionTablesUtilsTest extends TestCase {
SendFusionTablesUtils.appendLocation(location, builder);
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));
}
}
@@ -17,7 +17,6 @@ package com.google.android.apps.mytracks.endtoendtest;
import com.google.android.apps.mytracks.Constants;
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.gdata.GDataClientFactory;
import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
@@ -63,11 +62,17 @@ import java.util.Locale;
* @author Youtao Liu
*/
public class GoogleUtils {
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_2 = "mytrackstest2@gmail.com";
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.
*
@@ -408,7 +413,7 @@ public class GoogleUtils {
String fusionTableAuthToken = AccountManager.get(context).blockingGetAuthToken(getAccount(context),
SendFusionTablesUtils.SERVICE, false);
GenericUrl url = new GenericUrl(SendFusionTablesAsyncTask.FUSION_TABLES_BASE_URL);
GenericUrl url = new GenericUrl(FUSION_TABLES_BASE_URL);
String sql = "sql=" + query;
ByteArrayInputStream inputStream = new ByteArrayInputStream(sql.getBytes());
InputStreamContent inputStreamContent = new InputStreamContent(null, inputStream);
@@ -418,11 +423,11 @@ public class GoogleUtils {
.createRequestFactory(new MethodOverride())).buildPostRequest(url, inputStreamContent);
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName(SendFusionTablesAsyncTask.APP_NAME_PREFIX
headers.setApplicationName(APP_NAME_PREFIX
+ SystemUtils.getMyTracksVersion(context));
headers.setGDataVersion(SendFusionTablesAsyncTask.GDATA_VERSION);
headers.setGDataVersion(GDATA_VERSION);
headers.setGoogleLogin(fusionTableAuthToken);
headers.setContentType(SendFusionTablesAsyncTask.CONTENT_TYPE);
headers.setContentType(CONTENT_TYPE);
request.setHeaders(headers);
HttpResponse response;
@@ -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.endtoendtest.EndToEndTestUtils;
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.util.PreferencesUtils;
import com.google.android.gms.auth.GoogleAuthException;
@@ -119,8 +120,8 @@ public class SyncTestUtils {
public static Drive getGoogleDrive(Context context) throws IOException, GoogleAuthException {
String googleAccount = PreferencesUtils.getString(
context, R.string.google_account_key, PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
GoogleAccountCredential credential = SyncUtils.getGoogleAccountCredential(
context, googleAccount);
GoogleAccountCredential credential = SendToGoogleUtils.getGoogleAccountCredential(
context, googleAccount, SendToGoogleUtils.DRIVE_SCOPE);
return SyncUtils.getDriveService(credential);
}