diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index bac3f32dd..0f6250419 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -95,7 +95,7 @@ limitations under the License.
-
+
-
+
+
minRecordingInterval
minRequiredAccuracy
pickExistingMap
+ preferredAccount
reportSpeed
sendToDocs
sendToFusionTables
diff --git a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
index bc8dc5707..f7e886106 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
@@ -26,7 +26,10 @@ import android.util.Log;
/**
* Choose which account to upload track information to.
+ *
* @author Sandor Dornbush
+ *
+ * @deprecated To be removed.
*/
public class AccountChooser {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/Constants.java b/MyTracks/src/com/google/android/apps/mytracks/Constants.java
index 5081622f8..a6d2a3df8 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/Constants.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/Constants.java
@@ -35,8 +35,11 @@ public abstract class Constants {
/*
* onActivityResult request codes:
+ *
+ * TODO: These should be moved to the
+ * activities that call startActivityForResult. Thus do not need to keep a
+ * global order across all activities.
*/
-
public static final int GET_LOGIN = 0;
public static final int GET_MAP = 1;
public static final int SHOW_TRACK = 2;
@@ -54,6 +57,7 @@ public abstract class Constants {
public static final int SAVE_TCX_FILE = 14;
public static final int SHOW_WAYPOINT = 15;
public static final int WELCOME = 16;
+ public static final int CHOOSE_ACCOUNT = 17;
/*
* Menu ids:
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AccountChooserActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AccountChooserActivity.java
new file mode 100644
index 000000000..89c09243d
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AccountChooserActivity.java
@@ -0,0 +1,168 @@
+/*
+ * 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.apps.mytracks.Constants;
+import com.google.android.apps.mytracks.util.ApiFeatures;
+import com.google.android.maps.mytracks.R;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+
+/**
+ * A chooser to select an account. To be called with
+ * {@link Activity#startActivityForResult(Intent, int)}. Returns
+ * {@link Activity#RESULT_CANCELED} if the user cancels the activity. Otherwise,
+ * returns {@link Activity#RESULT_OK} with an intent containing the selected
+ * account. The selected account is stored as an {@link Account} in the
+ * {@link AccountChooserActivity#ACCOUNT} item of the intent. The selected
+ * account can be null.
+ *
+ * @author jshih@google.com (Jimmy Shih)
+ */
+public class AccountChooserActivity extends Activity {
+
+ /**
+ * Key for storing an {@link Account} in an {@link Intent}.
+ */
+ public static final String ACCOUNT = "account";
+
+ private static final int NO_ACCOUNT_DIALOG = 1;
+ private static final int CHOOSE_ACCOUNT_DIALOG = 2;
+
+ private Account[] accounts;
+ private int selectedAccountIndex;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ accounts = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE);
+
+ if (accounts.length == 1) {
+ Intent intent = new Intent();
+ intent.putExtra(ACCOUNT, accounts[0]);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ String preferredAccount = prefs.getString(getString(R.string.preferred_account_key), "");
+
+ selectedAccountIndex = -1;
+ for (int i = 0; i < accounts.length; i++) {
+ if (accounts[i].name.equals(preferredAccount)) {
+ selectedAccountIndex = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (accounts.length == 0) {
+ showDialog(NO_ACCOUNT_DIALOG);
+ } else {
+ showDialog(CHOOSE_ACCOUNT_DIALOG);
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ AlertDialog.Builder builder;
+ switch (id) {
+ case NO_ACCOUNT_DIALOG:
+ builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.send_google_no_account_title);
+ builder.setMessage(R.string.send_google_no_account_message);
+ builder.setCancelable(true);
+ builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent();
+ intent.putExtra(ACCOUNT, (Account) null);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+ });
+ return builder.create();
+ case CHOOSE_ACCOUNT_DIALOG:
+ builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.send_google_choose_account_title);
+
+ String[] choices = new String[accounts.length];
+ for (int i = 0; i < accounts.length; i++) {
+ choices[i] = accounts[i].name;
+ }
+ builder.setSingleChoiceItems(choices, selectedAccountIndex, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ selectedAccountIndex = which;
+ }
+ });
+
+ builder.setCancelable(true);
+ builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ builder.setNegativeButton(R.string.generic_cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Account account = null;
+ if (selectedAccountIndex != -1) {
+ account = accounts[selectedAccountIndex];
+ SharedPreferences prefs = getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ Editor editor = prefs.edit();
+ editor.putString(getString(R.string.preferred_account_key), account.name);
+ ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
+ }
+ Intent intent = new Intent();
+ intent.putExtra(ACCOUNT, account);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+ });
+ return builder.create();
+ default:
+ return null;
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java
index 404ff0d05..dad6abe82 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java
@@ -18,7 +18,6 @@ package com.google.android.apps.mytracks.io.sendtogoogle;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.analytics.GoogleAnalyticsTracker;
-import com.google.android.apps.mytracks.AccountChooser;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MapsList;
import com.google.android.apps.mytracks.ProgressIndicator;
@@ -60,6 +59,7 @@ import java.util.List;
*/
public class SendActivity extends Activity implements ProgressIndicator {
+ // Items in the intent that starts the activity.
public static final String TRACK_ID = "trackId";
public static final String SHARE_URL = "shareUrl";
public static final String SEND_MAPS = "sendMaps";
@@ -68,20 +68,17 @@ public class SendActivity extends Activity implements ProgressIndicator {
public static final String CREATE_MAP = "createMap";
// Keys for saved state variables.
- private static final String STATE_SEND_TO_MAPS = "mapsSend";
- private static final String STATE_SEND_TO_FUSION_TABLES = "fusionSend";
- private static final String STATE_SEND_TO_DOCS = "docsSend";
+ private static final String STATE_ACCOUNT = "account";
+ private static final String STATE_STATE = "state";
private static final String STATE_DOCS_SUCCESS = "docsSuccess";
private static final String STATE_FUSION_SUCCESS = "fusionSuccess";
private static final String STATE_MAPS_SUCCESS = "mapsSuccess";
- private static final String STATE_STATE = "state";
- private static final String STATE_ACCOUNT_TYPE = "accountType";
- private static final String STATE_ACCOUNT_NAME = "accountName";
private static final String STATE_TABLE_ID = "tableId";
private static final String STATE_MAP_ID = "mapId";
/** States for the state machine that defines the upload process. */
private enum SendState {
+ CHOOSE_ACCOUNT,
START,
AUTHENTICATE_MAPS,
PICK_MAP,
@@ -108,37 +105,32 @@ public class SendActivity extends Activity implements ProgressIndicator {
// UI
private ProgressDialog progressDialog;
- // Services
+ // Set in Activity.onCreate
private MyTracksProviderUtils providerUtils;
private SharedPreferences sharedPreferences;
private GoogleAnalyticsTracker tracker;
- // Authentication
- private AuthManager lastAuth;
- private final HashMap authMap = new HashMap();
- private AccountChooser accountChooser;
- private String lastAccountName;
- private String lastAccountType;
-
- // Send request information.
+ // Send request information. Set by the intent that starts the activity.
private long sendTrackId;
private boolean shareRequest;
private boolean sendToMaps;
private boolean sendToMapsNewMap;
private boolean sendToFusionTables;
private boolean sendToDocs;
-
- // Send result information, used by results dialog.
- private boolean sendToMapsSuccess = false;
- private boolean sendToFusionTablesSuccess = false;
- private boolean sendToDocsSuccess = false;
-
- // Send result information, used to share a link.
- private String sendToMapsMapId;
- private String sendToFusionTablesTableId;
-
+
+ // Authentication information.
+ private Account account;
+ private HashMap authMap = new HashMap();
+
// Current sending state.
private SendState currentState;
+
+ // Send result information. Used by the results dialog.
+ private boolean sendToMapsSuccess;
+ private boolean sendToFusionTablesSuccess;
+ private boolean sendToDocsSuccess;
+ private String sendToMapsMapId;
+ private String sendToFusionTablesTableId;
private final OnCancelListener finishOnCancelListener = new OnCancelListener() {
@Override
@@ -174,7 +166,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
// Only consider the intent if we're not restoring from a previous state.
- if (currentState == SendState.START) {
+ if (currentState == SendState.CHOOSE_ACCOUNT) {
if (!handleIntent()) {
finish();
return;
@@ -215,41 +207,29 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
private void restoreInstanceState(Bundle savedInstanceState) {
+ account = savedInstanceState.getParcelable(STATE_ACCOUNT);
+
currentState = SendState.values()[savedInstanceState.getInt(STATE_STATE)];
- sendToMaps = savedInstanceState.getBoolean(STATE_SEND_TO_MAPS);
- sendToFusionTables = savedInstanceState.getBoolean(STATE_SEND_TO_FUSION_TABLES);
- sendToDocs = savedInstanceState.getBoolean(STATE_SEND_TO_DOCS);
-
sendToMapsSuccess = savedInstanceState.getBoolean(STATE_MAPS_SUCCESS);
sendToFusionTablesSuccess = savedInstanceState.getBoolean(STATE_FUSION_SUCCESS);
sendToDocsSuccess = savedInstanceState.getBoolean(STATE_DOCS_SUCCESS);
-
sendToMapsMapId = savedInstanceState.getString(STATE_MAP_ID);
sendToFusionTablesTableId = savedInstanceState.getString(STATE_TABLE_ID);
-
- lastAccountName = savedInstanceState.getString(STATE_ACCOUNT_NAME);
- lastAccountType = savedInstanceState.getString(STATE_ACCOUNT_TYPE);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
-
+ outState.putParcelable(STATE_ACCOUNT, account);
+
outState.putInt(STATE_STATE, currentState.ordinal());
outState.putBoolean(STATE_MAPS_SUCCESS, sendToMapsSuccess);
outState.putBoolean(STATE_FUSION_SUCCESS, sendToFusionTablesSuccess);
outState.putBoolean(STATE_DOCS_SUCCESS, sendToDocsSuccess);
-
outState.putString(STATE_MAP_ID, sendToMapsMapId);
outState.putString(STATE_TABLE_ID, sendToFusionTablesTableId);
-
- outState.putString(STATE_ACCOUNT_NAME, lastAccountName);
- outState.putString(STATE_ACCOUNT_TYPE, lastAccountType);
-
- // TODO: Ideally we should serialize/restore the authenticator map and lastAuth somehow,
- // but it's highly unlikely we'll get killed while an auth dialog is displayed.
}
@Override
@@ -282,6 +262,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
private SendState executeState(SendState state) {
switch (state) {
+ case CHOOSE_ACCOUNT:
+ return chooseAccount();
case START:
return startSend();
case AUTHENTICATE_MAPS:
@@ -318,6 +300,12 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
}
+ private SendState chooseAccount() {
+ Intent intent = new Intent(this, AccountChooserActivity.class);
+ startActivityForResult(intent, Constants.CHOOSE_ACCOUNT);
+ return SendState.NOT_READY;
+ }
+
/**
* Initiates the process to send tracks to google.
* This is called once the user has selected sending options via the
@@ -363,8 +351,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
if (!sendToMapsNewMap) {
// Ask the user to choose a map to upload into
Intent listIntent = new Intent(this, MapsList.class);
- listIntent.putExtra(MapsList.EXTRA_ACCOUNT_NAME, lastAccountName);
- listIntent.putExtra(MapsList.EXTRA_ACCOUNT_TYPE, lastAccountType);
+ listIntent.putExtra(MapsList.EXTRA_ACCOUNT_NAME, account.name);
+ listIntent.putExtra(MapsList.EXTRA_ACCOUNT_TYPE, account.type);
startActivityForResult(listIntent, Constants.GET_MAP);
// The callback for GET_MAP calls authenticateToGoogleMaps
return SendState.NOT_READY;
@@ -406,8 +394,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
sendToMapsMapId = SendToMaps.NEW_MAP_ID;
}
- final SendToMaps sender = new SendToMaps(this, sendToMapsMapId, lastAuth,
- sendTrackId, this /*progressIndicator*/, onCompletion);
+ final SendToMaps sender = new SendToMaps(this, sendToMapsMapId,
+ getAuthManager(MapsConstants.SERVICE_NAME), sendTrackId, this /*progressIndicator*/,
+ onCompletion);
new Thread(sender, "SendToMaps").start();
@@ -461,8 +450,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
};
- final SendToFusionTables sender = new SendToFusionTables(this, lastAuth,
- sendTrackId, this /*progressIndicator*/, onCompletion);
+ final SendToFusionTables sender = new SendToFusionTables(
+ this, getAuthManager(SendToFusionTables.SERVICE_ID), sendTrackId,
+ this /* progressIndicator */, onCompletion);
new Thread(sender, "SendToFusionTables").start();
@@ -502,8 +492,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
String serviceName = getString(SendType.DOCS.getServiceName());
setProgressMessage(String.format(format, serviceName));
final SendToDocs sender = new SendToDocs(this,
- authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
- authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST),
+ getAuthManager(SendToDocs.GDATA_SERVICE_NAME_TRIX),
+ getAuthManager(SendToDocs.GDATA_SERVICE_NAME_DOCLIST),
this);
Runnable onCompletion = new Runnable() {
public void run() {
@@ -671,59 +661,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
* token, prompting the user for a login and password if needed.
*/
private void authenticate(final int requestCode, final String service) {
- lastAuth = authMap.get(service);
- if (lastAuth == null) {
- Log.i(TAG, "Creating a new authentication for service: " + service);
- lastAuth = AuthManagerFactory.getAuthManager(this,
- Constants.GET_LOGIN,
- null,
- true,
- service);
- authMap.put(service, lastAuth);
- }
-
- Log.d(TAG, "Logging in to " + service + "...");
- if (AuthManagerFactory.useModernAuthManager()) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- chooseAccount(requestCode, service);
- }
- });
- } else {
- doLogin(requestCode, service, null);
- }
- }
-
- private void chooseAccount(final int requestCode, final String service) {
- if (accountChooser == null) {
- accountChooser = new AccountChooser();
-
- // Restore state if necessary.
- if (lastAccountName != null && lastAccountType != null) {
- accountChooser.setChosenAccount(lastAccountName, lastAccountType);
- }
- }
-
- accountChooser.chooseAccount(SendActivity.this,
- new AccountChooser.AccountHandler() {
- @Override
- public void onAccountSelected(Account account) {
- if (account == null) {
- dismissDialog(PROGRESS_DIALOG);
- finish();
- return;
- }
-
- lastAccountName = account.name;
- lastAccountType = account.type;
- doLogin(requestCode, service, account);
- }
- });
- }
-
- private void doLogin(final int requestCode, final String service, final Object account) {
- lastAuth.doLogin(new AuthCallback() {
+ AuthManager authManager = getAuthManager(service);
+ authManager.doLogin(new AuthCallback() {
@Override
public void onAuthResult(boolean success) {
Log.i(TAG, "Login success for " + service + ": " + success);
@@ -742,16 +681,6 @@ public class SendActivity extends Activity implements ProgressIndicator {
final Intent results) {
SendState nextState = null;
switch (requestCode) {
- case Constants.GET_LOGIN: {
- if (resultCode == RESULT_CANCELED || lastAuth == null) {
- nextState = SendState.FINISH;
- break;
- }
-
- // This will invoke onAuthResult appropriately.
- lastAuth.authResult(resultCode, results);
- break;
- }
case Constants.GET_MAP: {
// User picked a map to upload to
Log.d(TAG, "Get map result: " + resultCode);
@@ -765,6 +694,19 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
break;
}
+ case Constants.CHOOSE_ACCOUNT: {
+ if (resultCode == RESULT_CANCELED) {
+ nextState = SendState.FINISH;
+ break;
+ }
+ account = results.getParcelableExtra(AccountChooserActivity.ACCOUNT);
+ if (account == null) {
+ nextState = SendState.FINISH;
+ break;
+ }
+ nextState = SendState.START;
+ break;
+ }
default: {
Log.e(TAG, "Unrequested result: " + requestCode);
return;
@@ -805,15 +747,29 @@ public class SendActivity extends Activity implements ProgressIndicator {
executeStateMachine(nextState);
}
+ private AuthManager getAuthManager(String service) {
+ AuthManager authManager = authMap.get(service);
+ if (authManager == null) {
+ authManager = AuthManagerFactory.getAuthManager(this,
+ Constants.GET_LOGIN,
+ null,
+ true,
+ service);
+ authMap.put(service, authManager);
+ }
+ return authManager;
+ }
/**
* Resets status information for sending to Maps/Fusion Tables/Docs.
*/
private void resetState() {
- currentState = SendState.START;
+ account = null;
+ authMap.clear();
+ currentState = SendState.CHOOSE_ACCOUNT;
+ sendToMapsSuccess = false;
+ sendToFusionTablesSuccess = false;
+ sendToDocsSuccess = false;
sendToMapsMapId = null;
- sendToMapsSuccess = true;
- sendToFusionTablesSuccess = true;
- sendToDocsSuccess = true;
sendToFusionTablesTableId = null;
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java
index 01241687d..b6f3fc8d1 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java
@@ -88,12 +88,6 @@ public class UploadServiceChooserActivity extends Activity {
showDialog(SERVICE_PICKER_DIALOG);
}
- @Override
- protected void onPause() {
- super.onPause();
- removeDialog(SERVICE_PICKER_DIALOG);
- }
-
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {