merge heads

This commit is contained in:
Jimmy Shih
2012-02-01 13:44:50 -08:00
19 changed files with 403 additions and 578 deletions
@@ -22,7 +22,7 @@ import android.app.Application;
/** /**
* MyTracksApplication for keeping global state. * MyTracksApplication for keeping global state.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class MyTracksApplication extends Application { public class MyTracksApplication extends Application {
@@ -15,107 +15,33 @@
*/ */
package com.google.android.apps.mytracks.io.docs; package com.google.android.apps.mytracks.io.docs;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity; import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle;
/** /**
* An activity to send a track to Google Docs. * An activity to send a track to Google Docs.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendDocsActivity extends Activity { public class SendDocsActivity extends AbstractSendActivity {
private static final int PROGRESS_DIALOG = 1;
private SendRequest sendRequest;
private SendDocsAsyncTask asyncTask;
private ProgressDialog progressDialog;
@Override @Override
public void onCreate(Bundle savedInstanceState) { protected AbstractSendAsyncTask createAsyncTask() {
super.onCreate(savedInstanceState); return new SendDocsAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof SendDocsAsyncTask) {
asyncTask = (SendDocsAsyncTask) retained;
asyncTask.setActivity(this);
} else {
asyncTask = new SendDocsAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
asyncTask.execute();
}
} }
@Override @Override
public Object onRetainNonConfigurationInstance() { protected String getServiceName() {
asyncTask.setActivity(null); return getString(R.string.send_google_docs);
return asyncTask;
} }
@Override @Override
protected Dialog onCreateDialog(int id) { protected void startNextActivity(boolean success, boolean isCancel) {
switch (id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(getString(
R.string.send_google_progress_title, getString(R.string.send_google_docs)));
progressDialog.setMax(100);
progressDialog.setProgress(0);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
asyncTask.cancel(true);
startNextActivity(false);
}
});
return progressDialog;
default:
return null;
}
}
/**
* Invokes when the associated AsyncTask completes.
*
* @param success true if success
*/
public void onAsyncTaskCompleted(boolean success) {
startNextActivity(success);
}
/**
* Shows the progress dialog.
*/
public void showProgressDialog() {
showDialog(PROGRESS_DIALOG);
}
/**
* Sets the progress dialog value.
*/
public void setProgressDialogValue(int value) {
if (progressDialog != null) {
progressDialog.setProgress(value);
}
}
/**
* Starts the next activity.
*
* @param success true if sendDocs is success
*/
private void startNextActivity(boolean success) {
sendRequest.setDocsSuccess(success); sendRequest.setDocsSuccess(success);
Intent intent = new Intent(this, UploadResultActivity.class) Intent intent = new Intent(this, UploadResultActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest); .putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
@@ -21,6 +21,7 @@ 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;
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.docs.XmlDocsGDataParserFactory; import com.google.android.apps.mytracks.io.gdata.docs.XmlDocsGDataParserFactory;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.common.gdata.AndroidXmlParserFactory; import com.google.android.common.gdata.AndroidXmlParserFactory;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import com.google.wireless.gdata.client.GDataClient; import com.google.wireless.gdata.client.GDataClient;
@@ -33,7 +34,6 @@ import android.accounts.AccountManager;
import android.accounts.AuthenticatorException; import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException; import android.accounts.OperationCanceledException;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
@@ -41,9 +41,9 @@ import java.io.IOException;
/** /**
* AsyncTask to send a track to Google Docs. * AsyncTask to send a track to Google Docs.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> { public class SendDocsAsyncTask extends AbstractSendAsyncTask {
private static final int PROGRESS_GET_SPREADSHEET_ID = 0; private static final int PROGRESS_GET_SPREADSHEET_ID = 0;
private static final int PROGRESS_CREATE_SPREADSHEET = 25; private static final int PROGRESS_CREATE_SPREADSHEET = 25;
private static final int PROGRESS_GET_WORKSHEET_ID = 50; private static final int PROGRESS_GET_WORKSHEET_ID = 50;
@@ -52,7 +52,6 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = SendDocsAsyncTask.class.getSimpleName(); private static final String TAG = SendDocsAsyncTask.class.getSimpleName();
private SendDocsActivity activity;
private final long trackId; private final long trackId;
private final Account account; private final Account account;
private final Context context; private final Context context;
@@ -61,21 +60,6 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private final DocumentsClient documentsClient; private final DocumentsClient documentsClient;
private final SpreadsheetsClient spreadsheetsClient; private final SpreadsheetsClient spreadsheetsClient;
/**
* True if can retry sending to Google Docs.
*/
private boolean canRetry;
/**
* True if the AsyncTask has completed.
*/
private boolean completed;
/**
* True if the result is success.
*/
private boolean success;
// The following variables are for per upload states // The following variables are for per upload states
private String documentsAuthToken; private String documentsAuthToken;
private String spreadsheetsAuthToken; private String spreadsheetsAuthToken;
@@ -83,7 +67,7 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private String worksheetId; private String worksheetId;
public SendDocsAsyncTask(SendDocsActivity activity, long trackId, Account account) { public SendDocsAsyncTask(SendDocsActivity activity, long trackId, Account account) {
this.activity = activity; super(activity);
this.trackId = trackId; this.trackId = trackId;
this.account = account; this.account = account;
@@ -94,68 +78,22 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory())); gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
spreadsheetsClient = new SpreadsheetsClient( spreadsheetsClient = new SpreadsheetsClient(
gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory())); gDataClient, new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
canRetry = true;
completed = false;
success = false;
}
/**
* Sets the activity associated with this AyncTask.
*
* @param activity the activity.
*/
public void setActivity(SendDocsActivity activity) {
this.activity = activity;
if (completed && activity != null) {
activity.onAsyncTaskCompleted(success);
}
} }
@Override @Override
protected void onPreExecute() { protected void closeConnection() {
activity.showProgressDialog();
}
@Override
protected Boolean doInBackground(Void... params) {
return doUpload();
}
@Override
protected void onProgressUpdate(Integer... values) {
if (activity != null) {
activity.setProgressDialogValue(values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
closeClient();
success = result;
completed = true;
if (activity != null) {
activity.onAsyncTaskCompleted(success);
}
}
@Override
protected void onCancelled() {
closeClient();
}
private void closeClient() {
if (gDataClient != null) { if (gDataClient != null) {
gDataClient.close(); gDataClient.close();
} }
} }
/** @Override
* Uploads a track to Google Docs. protected void saveResult() {
* // No action for Google Docs
* @return true if success. }
*/
private boolean doUpload() { @Override
protected boolean performTask() {
// Reset the per upload states // Reset the per upload states
documentsAuthToken = null; documentsAuthToken = null;
spreadsheetsAuthToken = null; spreadsheetsAuthToken = null;
@@ -169,13 +107,13 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
account, spreadsheetsClient.getServiceName(), false); account, spreadsheetsClient.getServiceName(), false);
} catch (OperationCanceledException e) { } catch (OperationCanceledException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (AuthenticatorException e) { } catch (AuthenticatorException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (IOException e) { } catch (IOException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} }
Track track = myTracksProviderUtils.getTrack(trackId); Track track = myTracksProviderUtils.getTrack(trackId);
@@ -192,7 +130,7 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
// Get the spreadsheet ID // Get the spreadsheet ID
publishProgress(PROGRESS_GET_SPREADSHEET_ID); publishProgress(PROGRESS_GET_SPREADSHEET_ID);
if (!fetchSpreadSheetId(title, false)) { if (!fetchSpreadSheetId(title, false)) {
return retryUpload(); return retryTask();
} }
// Create a new spreadsheet if necessary // Create a new spreadsheet if necessary
@@ -223,7 +161,7 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
// Get the worksheet ID // Get the worksheet ID
publishProgress(PROGRESS_GET_WORKSHEET_ID); publishProgress(PROGRESS_GET_WORKSHEET_ID);
if (!fetchWorksheetId()) { if (!fetchWorksheetId()) {
return retryUpload(); return retryTask();
} }
if (worksheetId == null) { if (worksheetId == null) {
Log.d(TAG, "Unable to get a worksheet ID"); Log.d(TAG, "Unable to get a worksheet ID");
@@ -241,6 +179,14 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return true; return true;
} }
@Override
protected void invalidateToken() {
AccountManager.get(context).invalidateAuthToken(
documentsClient.getServiceName(), documentsAuthToken);
AccountManager.get(context).invalidateAuthToken(
spreadsheetsClient.getServiceName(), spreadsheetsAuthToken);
}
/** /**
* Fetches the spreadsheet id. Sets the instance variable * Fetches the spreadsheet id. Sets the instance variable
* {@link SendDocsAsyncTask#spreadsheetId}. * {@link SendDocsAsyncTask#spreadsheetId}.
@@ -366,24 +312,4 @@ public class SendDocsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
} }
return true; return true;
} }
/**
* Retries upload. Invalidates the authToken. If can retry, invokes
* {@link SendDocsAsyncTask#doUpload()}. Returns false if cannot retry.
*/
private boolean retryUpload() {
if (isCancelled()) {
return false;
}
AccountManager.get(context).invalidateAuthToken(
documentsClient.getServiceName(), documentsAuthToken);
AccountManager.get(context).invalidateAuthToken(
spreadsheetsClient.getServiceName(), spreadsheetsAuthToken);
if (canRetry) {
canRetry = false;
return doUpload();
}
return false;
}
} }
@@ -16,121 +16,35 @@
package com.google.android.apps.mytracks.io.fusiontables; package com.google.android.apps.mytracks.io.fusiontables;
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.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity; import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle;
/** /**
* An activity to send a track to Google Fusion Tables. * An activity to send a track to Google Fusion Tables.
* <p>
* The activity gets recreated when the screen rotates. To support the activity
* displaying a progress dialog, we do the following:
* <ul>
* <li>use one instance of an AyncTask to send the track</li>
* <li>save that instance as the last non configuration instance of the activity
* </li>
* <li>when a new activity is created, pass the activity to the AsyncTask so
* that the AsyncTask can update the progress dialog of the activity</li>
* </ul>
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendFusionTablesActivity extends Activity { public class SendFusionTablesActivity extends AbstractSendActivity {
private static final int PROGRESS_DIALOG = 1;
private SendRequest sendRequest;
private SendFusionTablesAsyncTask asyncTask;
private ProgressDialog progressDialog;
@Override @Override
public void onCreate(Bundle savedInstanceState) { protected AbstractSendAsyncTask createAsyncTask() {
super.onCreate(savedInstanceState); return new SendFusionTablesAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof SendFusionTablesAsyncTask) {
asyncTask = (SendFusionTablesAsyncTask) retained;
asyncTask.setActivity(this);
} else {
asyncTask = new SendFusionTablesAsyncTask(
this, sendRequest.getTrackId(), sendRequest.getAccount());
asyncTask.execute();
}
} }
@Override @Override
public Object onRetainNonConfigurationInstance() { protected String getServiceName() {
asyncTask.setActivity(null); return getString(R.string.send_google_fusion_tables);
return asyncTask;
} }
@Override @Override
protected Dialog onCreateDialog(int id) { protected void startNextActivity(boolean success, boolean isCancel) {
switch (id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(getString(
R.string.send_google_progress_title, getString(R.string.send_google_fusion_tables)));
progressDialog.setMax(100);
progressDialog.setProgress(0);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
asyncTask.cancel(true);
startNextActivity(false, true);
}
});
return progressDialog;
default:
return null;
}
}
/**
* Invokes when the associated AsyncTask completes.
*
* @param success true if success
*/
public void onAsyncTaskCompleted(boolean success) {
startNextActivity(success, false);
}
/**
* Shows the progress dialog.
*/
public void showProgressDialog() {
showDialog(PROGRESS_DIALOG);
}
/**
* Sets the progress dialog value.
*/
public void setProgressDialogValue(int value) {
if (progressDialog != null) {
progressDialog.setProgress(value);
}
}
/**
* Starts the next activity.
*
* @param success true if sendFusionTables is success
* @param isCancel true if it is a cancel request
*/
private void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setFusionTablesSuccess(success); sendRequest.setFusionTablesSuccess(success);
Class<?> next; Class<?> next;
if (isCancel) { if (isCancel) {
next = UploadResultActivity.class; next = UploadResultActivity.class;
@@ -141,8 +55,7 @@ public class SendFusionTablesActivity extends Activity {
next = UploadResultActivity.class; next = UploadResultActivity.class;
} }
} }
Intent intent = new Intent(this, next) Intent intent = new Intent(this, next).putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
@@ -6,6 +6,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.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
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.DoubleBuffer; import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
@@ -32,7 +33,6 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.location.Location; import android.location.Location;
import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -46,9 +46,9 @@ import java.util.Vector;
/** /**
* AsyncTask to send a track to Google Fusion Tables. * AsyncTask to send a track to Google Fusion Tables.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean> { public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
private static final String APP_NAME_PREFIX = "Google-MyTracks-"; private static final String APP_NAME_PREFIX = "Google-MyTracks-";
private static final String SQL_KEY = "sql="; private static final String SQL_KEY = "sql=";
@@ -73,29 +73,12 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName(); private static final String TAG = SendFusionTablesAsyncTask.class.getSimpleName();
private SendFusionTablesActivity activity;
private final Context context; private final Context context;
private final long trackId; private final long trackId;
private final Account account; private final Account account;
private final MyTracksProviderUtils myTracksProviderUtils; private final MyTracksProviderUtils myTracksProviderUtils;
private final HttpRequestFactory httpRequestFactory; private final HttpRequestFactory httpRequestFactory;
/**
* True if can retry sending to Google Fusion Tables.
*/
private boolean canRetry;
/**
* True if the AsyncTask has completed.
*/
private boolean completed;
/**
* True if the result is success.
*/
private boolean success;
// The following variables are for per upload states // The following variables are for per upload states
private String authToken; private String authToken;
private String tableId; private String tableId;
@@ -103,7 +86,7 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
public SendFusionTablesAsyncTask( public SendFusionTablesAsyncTask(
SendFusionTablesActivity activity, long trackId, Account account) { SendFusionTablesActivity activity, long trackId, Account account) {
this.activity = activity; super(activity);
this.trackId = trackId; this.trackId = trackId;
this.account = account; this.account = account;
@@ -111,65 +94,26 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context); myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
HttpTransport transport = ApiAdapterFactory.getApiAdapter().getHttpTransport(); HttpTransport transport = ApiAdapterFactory.getApiAdapter().getHttpTransport();
httpRequestFactory = transport.createRequestFactory(new MethodOverride()); httpRequestFactory = transport.createRequestFactory(new MethodOverride());
canRetry = true;
completed = false;
success = false;
} }
/** @Override
* Sets the activity associated with this AyncTask. protected void closeConnection() {
* // No action needed for Google Fusion Tables
* @param activity the activity. }
*/
public void setActivity(SendFusionTablesActivity activity) { @Override
this.activity = activity; protected void saveResult() {
if (completed && activity != null) { Track track = myTracksProviderUtils.getTrack(trackId);
activity.onAsyncTaskCompleted(success); if (track != null) {
track.setTableId(tableId);
myTracksProviderUtils.updateTrack(track);
} else {
Log.d(TAG, "No track");
} }
} }
@Override @Override
protected void onPreExecute() { protected boolean performTask() {
activity.showProgressDialog();
}
@Override
protected Boolean doInBackground(Void... params) {
return doUpload();
}
@Override
protected void onProgressUpdate(Integer... values) {
if (activity != null) {
activity.setProgressDialogValue(values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
success = result;
completed = true;
if (success) {
Track track = myTracksProviderUtils.getTrack(trackId);
if (track != null) {
track.setTableId(tableId);
myTracksProviderUtils.updateTrack(track);
} else {
Log.d(TAG, "No track");
}
}
if (activity != null) {
activity.onAsyncTaskCompleted(success);
}
}
/**
* Uploads a track to Google Fusion Tables.
*
* @return true if success.
*/
private boolean doUpload() {
// Reset the per upload states // Reset the per upload states
authToken = null; authToken = null;
tableId = null; tableId = null;
@@ -179,13 +123,13 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
authToken = AccountManager.get(context).blockingGetAuthToken(account, SERVICE_ID, false); authToken = AccountManager.get(context).blockingGetAuthToken(account, SERVICE_ID, false);
} catch (OperationCanceledException e) { } catch (OperationCanceledException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (AuthenticatorException e) { } catch (AuthenticatorException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (IOException e) { } catch (IOException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} }
Track track = myTracksProviderUtils.getTrack(trackId); Track track = myTracksProviderUtils.getTrack(trackId);
@@ -198,7 +142,7 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
publishProgress(PROGRESS_CREATE_TABLE); publishProgress(PROGRESS_CREATE_TABLE);
if (!createNewTable(track)) { if (!createNewTable(track)) {
// Retry upload in case the auth token is invalid // Retry upload in case the auth token is invalid
return retryUpload(); return retryTask();
} }
// Unlist table // Unlist table
@@ -223,22 +167,9 @@ public class SendFusionTablesAsyncTask extends AsyncTask<Void, Integer, Boolean>
return true; return true;
} }
/** @Override
* Retries upload. Invalidates the authToken. If can retry, invokes protected void invalidateToken() {
* {@link SendFusionTablesAsyncTask#doUpload()}. Returns false if cannot
* retry.
*/
private boolean retryUpload() {
if (isCancelled()) {
return false;
}
AccountManager.get(context).invalidateAuthToken(SERVICE_ID, authToken); AccountManager.get(context).invalidateAuthToken(SERVICE_ID, authToken);
if (canRetry) {
canRetry = false;
return doUpload();
}
return false;
} }
/** /**
@@ -32,7 +32,7 @@ import java.util.Locale;
/** /**
* Utilities for sending a track to Google Fusion Tables. * Utilities for sending a track to Google Fusion Tables.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendFusionTablesUtils { public class SendFusionTablesUtils {
@@ -41,7 +41,7 @@ import java.util.ArrayList;
/** /**
* An activity to choose a Google Map. * An activity to choose a Google Map.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class ChooseMapActivity extends Activity { public class ChooseMapActivity extends Activity {
@@ -208,7 +208,7 @@ public class ChooseMapActivity extends Activity {
/** /**
* A class containing {@link ChooseMapActivity} list item. * A class containing {@link ChooseMapActivity} list item.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
private class ListItem { private class ListItem {
private String mapId; private String mapId;
@@ -42,7 +42,7 @@ import java.util.ArrayList;
/** /**
* AsyncTask for {@link ChooseMapActivity} to get all the maps from Google Maps. * AsyncTask for {@link ChooseMapActivity} to get all the maps from Google Maps.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class ChooseMapAsyncTask extends AsyncTask<Void, Integer, Boolean> { public class ChooseMapAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = ChooseMapAsyncTask.class.getSimpleName(); private static final String TAG = ChooseMapAsyncTask.class.getSimpleName();
@@ -17,111 +17,36 @@ package com.google.android.apps.mytracks.io.maps;
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.fusiontables.SendFusionTablesActivity; import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity; import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle;
/** /**
* An activity to send a track to Google Maps. * An activity to send a track to Google Maps.
* *
* @author Jimmy Shih * @author Jimmy Shih
*/ */
public class SendMapsActivity extends Activity { public class SendMapsActivity extends AbstractSendActivity {
private static final int PROGRESS_DIALOG = 1;
private SendRequest sendRequest;
private SendMapsAsyncTask asyncTask;
private ProgressDialog progressDialog;
@Override @Override
public void onCreate(Bundle savedInstanceState) { protected AbstractSendAsyncTask createAsyncTask() {
super.onCreate(savedInstanceState); return new SendMapsAsyncTask(
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY); this, sendRequest.getTrackId(), sendRequest.getAccount(), sendRequest.getMapId());
Object retained = getLastNonConfigurationInstance();
if (retained instanceof SendMapsAsyncTask) {
asyncTask = (SendMapsAsyncTask) retained;
asyncTask.setActivity(this);
} else {
asyncTask = new SendMapsAsyncTask(
this, sendRequest.getTrackId(), sendRequest.getAccount(), sendRequest.getMapId());
asyncTask.execute();
}
} }
@Override @Override
public Object onRetainNonConfigurationInstance() { protected String getServiceName() {
asyncTask.setActivity(null); return getString(R.string.send_google_maps);
return asyncTask;
} }
@Override @Override
protected Dialog onCreateDialog(int id) { protected void startNextActivity(boolean success, boolean isCancel) {
switch (id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(
getString(R.string.send_google_progress_title, getString(R.string.send_google_maps)));
progressDialog.setMax(100);
progressDialog.setProgress(0);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
asyncTask.cancel(true);
startNextActivity(false, true);
}
});
return progressDialog;
default:
return null;
}
}
/**
* Invokes when the associated AsyncTask completes.
*
* @param success true if success
*/
public void onAsyncTaskCompleted(boolean success) {
startNextActivity(success, false);
}
/**
* Shows the progress dialog.
*/
public void showProgressDialog() {
showDialog(PROGRESS_DIALOG);
}
/**
* Sets the progress dialog value.
*/
public void setProgressDialogValue(int value) {
if (progressDialog != null) {
progressDialog.setProgress(value);
}
}
/**
* Starts the next activity.
*
* @param success true if sendMaps is success
* @param isCancel true if it is a cancel request
*/
private void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setMapsSuccess(success); sendRequest.setMapsSuccess(success);
Class<?> next; Class<?> next;
if (isCancel) { if (isCancel) {
next = UploadResultActivity.class; next = UploadResultActivity.class;
@@ -134,8 +59,7 @@ public class SendMapsActivity extends Activity {
next = UploadResultActivity.class; next = UploadResultActivity.class;
} }
} }
Intent intent = new Intent(this, next) Intent intent = new Intent(this, next).putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.io.gdata.maps.MapsClient;
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.gdata.maps.MapsGDataConverter; import com.google.android.apps.mytracks.io.gdata.maps.MapsGDataConverter;
import com.google.android.apps.mytracks.io.gdata.maps.XmlMapsGDataParserFactory; import com.google.android.apps.mytracks.io.gdata.maps.XmlMapsGDataParserFactory;
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.DoubleBuffer; import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.LocationUtils;
@@ -43,7 +44,6 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.location.Location; import android.location.Location;
import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
@@ -63,7 +63,7 @@ import org.xmlpull.v1.XmlPullParserException;
* *
* @author Jimmy Shih * @author Jimmy Shih
*/ */
public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> { public class SendMapsAsyncTask extends AbstractSendAsyncTask {
private static final String START_ICON_URL = private static final String START_ICON_URL =
"http://maps.google.com/mapfiles/ms/micons/green-dot.png"; "http://maps.google.com/mapfiles/ms/micons/green-dot.png";
private static final String END_ICON_URL = private static final String END_ICON_URL =
@@ -78,7 +78,6 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = SendMapsAsyncTask.class.getSimpleName(); private static final String TAG = SendMapsAsyncTask.class.getSimpleName();
private SendMapsActivity activity;
private final long trackId; private final long trackId;
private final Account account; private final Account account;
private final String chooseMapId; private final String chooseMapId;
@@ -87,30 +86,15 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private final GDataClient gDataClient; private final GDataClient gDataClient;
private final MapsClient mapsClient; private final MapsClient mapsClient;
/**
* True if can retry sending to Google Maps.
*/
private boolean canRetry;
/**
* True if the AsyncTask has completed.
*/
private boolean completed;
/**
* True if the result is success.
*/
private boolean success;
// The following variables are for per upload states // The following variables are for per upload states
private MapsGDataConverter mapsGDataConverter; private MapsGDataConverter mapsGDataConverter;
private String authToken; private String authToken;
private String mapId; private String mapId;
int currentSegment; int currentSegment;
public SendMapsAsyncTask( public SendMapsAsyncTask (
SendMapsActivity activity, long trackId, Account account, String chooseMapId) { SendMapsActivity activity, long trackId, Account account, String chooseMapId) {
this.activity = activity; super(activity);
this.trackId = trackId; this.trackId = trackId;
this.account = account; this.account = account;
this.chooseMapId = chooseMapId; this.chooseMapId = chooseMapId;
@@ -120,80 +104,28 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
gDataClient = GDataClientFactory.getGDataClient(context); gDataClient = GDataClientFactory.getGDataClient(context);
mapsClient = new MapsClient( mapsClient = new MapsClient(
gDataClient, new XmlMapsGDataParserFactory(new AndroidXmlParserFactory())); gDataClient, new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
canRetry = true;
completed = false;
success = false;
}
/**
* Sets the activity associated with this AyncTask.
*
* @param activity the activity.
*/
public void setActivity(SendMapsActivity activity) {
this.activity = activity;
if (completed && activity != null) {
activity.onAsyncTaskCompleted(success);
}
} }
@Override @Override
protected void onPreExecute() { protected void closeConnection() {
activity.showProgressDialog();
}
@Override
protected Boolean doInBackground(Void... params) {
return doUpload();
}
@Override
protected void onProgressUpdate(Integer... values) {
if (activity != null) {
activity.setProgressDialogValue(values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
closeClient();
success = result;
completed = true;
if (success) {
Track track = myTracksProviderUtils.getTrack(trackId);
if (track != null) {
track.setMapId(mapId);
myTracksProviderUtils.updateTrack(track);
} else {
Log.d(TAG, "No track");
}
}
if (activity != null) {
activity.onAsyncTaskCompleted(success);
}
}
@Override
protected void onCancelled() {
closeClient();
}
/**
* Closes the gdata client.
*/
private void closeClient() {
if (gDataClient != null) { if (gDataClient != null) {
gDataClient.close(); gDataClient.close();
} }
} }
/** @Override
* Uploads a track to Google Maps. protected void saveResult() {
* Track track = myTracksProviderUtils.getTrack(trackId);
* @return true if success. if (track != null) {
*/ track.setMapId(mapId);
private boolean doUpload() { myTracksProviderUtils.updateTrack(track);
} else {
Log.d(TAG, "No track");
}
}
@Override
protected boolean performTask() {
// Reset the per upload states // Reset the per upload states
mapsGDataConverter = null; mapsGDataConverter = null;
authToken = null; authToken = null;
@@ -214,13 +146,13 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
account, MapsConstants.SERVICE_NAME, false); account, MapsConstants.SERVICE_NAME, false);
} catch (OperationCanceledException e) { } catch (OperationCanceledException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (AuthenticatorException e) { } catch (AuthenticatorException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} catch (IOException e) { } catch (IOException e) {
Log.d(TAG, "Unable to get auth token", e); Log.d(TAG, "Unable to get auth token", e);
return retryUpload(); return retryTask();
} }
// Get the track // Get the track
@@ -234,14 +166,14 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
publishProgress(PROGRESS_FETCH_MAP_ID); publishProgress(PROGRESS_FETCH_MAP_ID);
if (!fetchSendMapId(track)) { if (!fetchSendMapId(track)) {
Log.d("TAG", "Unable to upload all track points"); Log.d("TAG", "Unable to upload all track points");
return retryUpload(); return retryTask();
} }
// Upload all the track points plus the start and end markers // Upload all the track points plus the start and end markers
publishProgress(PROGRESS_UPLOAD_DATA_MIN); publishProgress(PROGRESS_UPLOAD_DATA_MIN);
if (!uploadAllTrackPoints(track)) { if (!uploadAllTrackPoints(track)) {
Log.d("TAG", "Unable to upload all track points"); Log.d("TAG", "Unable to upload all track points");
return retryUpload(); return retryTask();
} }
// Upload all the waypoints // Upload all the waypoints
@@ -255,21 +187,9 @@ public class SendMapsAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return true; return true;
} }
/** @Override
* Retries upload. Invalidates the authToken. If can retry, invokes protected void invalidateToken() {
* {@link SendMapsAsyncTask#doUpload()}. Returns false if cannot retry.
*/
private boolean retryUpload() {
if (isCancelled()) {
return false;
}
AccountManager.get(context).invalidateAuthToken(MapsConstants.SERVICE_NAME, authToken); AccountManager.get(context).invalidateAuthToken(MapsConstants.SERVICE_NAME, authToken);
if (canRetry) {
canRetry = false;
return doUpload();
}
return false;
} }
/** /**
@@ -37,7 +37,7 @@ import java.util.ArrayList;
/** /**
* Utilities for sending a track to Google Maps. * Utilities for sending a track to Google Maps.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendMapsUtils { public class SendMapsUtils {
@@ -0,0 +1,139 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
/**
* The abstract class for activities sending a track to Google.
* <p>
* The activity gets recreated when the screen rotates. To support the activity
* displaying a progress dialog, we do the following:
* <ul>
* <li>use one instance of an AyncTask to send the track</li>
* <li>save that instance as the last non configuration instance of the activity
* </li>
* <li>when a new activity is created, pass the activity to the AsyncTask so
* that the AsyncTask can update the progress dialog of the activity</li>
* </ul>
*
* @author Jimmy Shih
*/
public abstract class AbstractSendActivity extends Activity {
private static final int PROGRESS_DIALOG = 1;
protected SendRequest sendRequest;
private AbstractSendAsyncTask asyncTask;
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof AbstractSendAsyncTask) {
asyncTask = (AbstractSendAsyncTask) retained;
asyncTask.setActivity(this);
} else {
asyncTask = createAsyncTask();
asyncTask.execute();
}
}
@Override
public Object onRetainNonConfigurationInstance() {
asyncTask.setActivity(null);
return asyncTask;
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
progressDialog.setTitle(getString(R.string.send_google_progress_title, getServiceName()));
progressDialog.setMax(100);
progressDialog.setProgress(0);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
asyncTask.cancel(true);
startNextActivity(false, true);
}
});
return progressDialog;
default:
return null;
}
}
/**
* Invokes when the associated AsyncTask completes.
*
* @param success true if the AsyncTask is successful
*/
public void onAsyncTaskCompleted(boolean success) {
startNextActivity(success, false);
}
/**
* Shows the progress dialog.
*/
public void showProgressDialog() {
showDialog(PROGRESS_DIALOG);
}
/**
* Sets the progress dialog value.
*
* @param value the dialog value
*/
public void setProgressDialogValue(int value) {
if (progressDialog != null) {
progressDialog.setProgress(value);
}
}
/**
* Creates the AsyncTask.
*/
protected abstract AbstractSendAsyncTask createAsyncTask();
/**
* Gets the service name.
*/
protected abstract String getServiceName();
/**
* Starts the next activity.
*
* @param success true if this activity is successful
* @param isCancel true if it is a cancel request
*/
protected abstract void startNextActivity(boolean success, boolean isCancel);
}
@@ -0,0 +1,147 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import android.os.AsyncTask;
/**
* The abstract class for AsyncTasks sending a track to Google.
*
* @author Jimmy Shih
*/
public abstract class AbstractSendAsyncTask extends AsyncTask<Void, Integer, Boolean> {
/**
* The activity associated with this AsyncTask.
*/
private AbstractSendActivity activity;
/**
* True if the AsyncTask result is success.
*/
private boolean success;
/**
* True if the AsyncTask has completed.
*/
private boolean completed;
/**
* True if can retry the AsyncTask.
*/
private boolean canRetry;
/**
* Creates an AsyncTask.
*
* @param activity the activity currently associated with this AsyncTask
*/
public AbstractSendAsyncTask(AbstractSendActivity activity) {
this.activity = activity;
success = false;
completed = false;
canRetry = true;
}
/**
* Sets the current activity associated with this AyncTask.
*
* @param activity the current activity, can be null
*/
public void setActivity(AbstractSendActivity activity) {
this.activity = activity;
if (completed && activity != null) {
activity.onAsyncTaskCompleted(success);
}
}
@Override
protected void onPreExecute() {
activity.showProgressDialog();
}
@Override
protected Boolean doInBackground(Void... params) {
return performTask();
}
@Override
protected void onProgressUpdate(Integer... values) {
if (activity != null) {
activity.setProgressDialogValue(values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
success = result;
if (success) {
saveResult();
}
completed = true;
closeConnection();
if (activity != null) {
activity.onAsyncTaskCompleted(success);
}
}
@Override
protected void onCancelled() {
closeConnection();
}
/**
* Retries the task. First, invalidates the auth token. If can retry, invokes
* {@link #performTask()}. Returns false if cannot retry.
*
* @return the result of the retry.
*/
protected boolean retryTask() {
if (isCancelled()) {
return false;
}
invalidateToken();
if (canRetry) {
canRetry = false;
return performTask();
}
return false;
}
/**
* Closes any AsyncTask connection.
*/
protected abstract void closeConnection();
/**
* Saves any AsyncTask result.
*/
protected abstract void saveResult();
/**
* Performs the AsyncTask.
*
* @return true if success
*/
protected abstract boolean performTask();
/**
* Invalidates the auth token.
*/
protected abstract void invalidateToken();
}
@@ -38,7 +38,7 @@ import android.os.Bundle;
/** /**
* A chooser to select an account. * A chooser to select an account.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class AccountChooserActivity extends Activity { public class AccountChooserActivity extends Activity {
@@ -38,7 +38,7 @@ import android.widget.TextView;
/** /**
* A dialog to show the result of uploading to Google services. * A dialog to show the result of uploading to Google services.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class UploadResultActivity extends Activity { public class UploadResultActivity extends Activity {
@@ -41,7 +41,7 @@ import android.widget.TableRow;
/** /**
* A chooser to select the Google services to upload a track to. * A chooser to select the Google services to upload a track to.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class UploadServiceChooserActivity extends Activity { public class UploadServiceChooserActivity extends Activity {
@@ -37,7 +37,7 @@ import android.util.Log;
* application delegates starting and stopping a recording to * application delegates starting and stopping a recording to
* {@link TrackRecordingService} using RPC calls. * {@link TrackRecordingService} using RPC calls.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class ControlRecordingService extends IntentService implements ServiceConnection { public class ControlRecordingService extends IntentService implements ServiceConnection {
@@ -26,7 +26,7 @@ import android.test.AndroidTestCase;
/** /**
* Tests {@link SendDocsUtils}. * Tests {@link SendDocsUtils}.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendDocsUtilsTest extends AndroidTestCase { public class SendDocsUtilsTest extends AndroidTestCase {
@@ -16,7 +16,6 @@
package com.google.android.apps.mytracks.io.fusiontables; package com.google.android.apps.mytracks.io.fusiontables;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location; import android.location.Location;
@@ -30,7 +29,7 @@ import junit.framework.TestCase;
/** /**
* Tests {@link SendFusionTablesUtils}. * Tests {@link SendFusionTablesUtils}.
* *
* @author jshih@google.com (Jimmy Shih) * @author Jimmy Shih
*/ */
public class SendFusionTablesUtilsTest extends TestCase { public class SendFusionTablesUtilsTest extends TestCase {