diff --git a/astrid/.classpath b/astrid/.classpath
index 9cf65cc65..e0db125e4 100644
--- a/astrid/.classpath
+++ b/astrid/.classpath
@@ -15,5 +15,6 @@
+
diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml
index 01ff5b68c..b6727a190 100644
--- a/astrid/AndroidManifest.xml
+++ b/astrid/AndroidManifest.xml
@@ -22,6 +22,13 @@
+
+
+
+
+
+
+
diff --git a/astrid/libs/googleloginclient-helper.jar b/astrid/libs/googleloginclient-helper.jar
new file mode 100644
index 000000000..6e610e991
Binary files /dev/null and b/astrid/libs/googleloginclient-helper.jar differ
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AccountChooser.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AccountChooser.java
new file mode 100644
index 000000000..aaa86d3b1
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AccountChooser.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010 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.todoroo.astrid.gtasks.auth;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+
+import com.timsu.astrid.R;
+
+/**
+ * Choose which account to upload track information to.
+ * @author Sandor Dornbush
+ */
+public class AccountChooser {
+
+ /**
+ * The last selected account.
+ */
+ private int selectedAccountIndex = -1;
+ private Account selectedAccount = null;
+
+ /**
+ * An interface for receiving updates once the user has selected the account.
+ */
+ public interface AccountHandler {
+ /**
+ * Handle the account being selected.
+ * @param account The selected account or null if none could be found
+ */
+ public void handleAccountSelected(Account account);
+ }
+
+ /**
+ * Chooses the best account to upload to.
+ * If no account is found the user will be alerted.
+ * If only one account is found that will be used.
+ * If multiple accounts are found the user will be allowed to choose.
+ *
+ * @param activity The parent activity
+ * @param handler The handler to be notified when an account has been selected
+ */
+ public void chooseAccount(final Activity activity,
+ final AccountHandler handler) {
+ final Account[] accounts = AccountManager.get(activity)
+ .getAccountsByType("com.google"); //$NON-NLS-1$
+ if (accounts.length < 1) {
+ alertNoAccounts(activity, handler);
+ return;
+ }
+ if (accounts.length == 1) {
+ handler.handleAccountSelected(accounts[0]);
+ return;
+ }
+
+ // TODO This should be read out of a preference.
+ if (selectedAccount != null) {
+ handler.handleAccountSelected(selectedAccount);
+ return;
+ }
+
+ // Let the user choose.
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.choose_account_title);
+ builder.setCancelable(false);
+ builder.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ selectedAccount = accounts[selectedAccountIndex];
+ handler.handleAccountSelected(selectedAccount);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ handler.handleAccountSelected(null);
+ }
+ });
+ 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.show();
+ }
+
+ /**
+ * Puts up a dialog alerting the user that no suitable account was found.
+ */
+ private void alertNoAccounts(final Activity activity,
+ final AccountHandler handler) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.no_account_found_title);
+ builder.setMessage(R.string.no_account_found);
+ builder.setCancelable(true);
+ builder.setNegativeButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ handler.handleAccountSelected(null);
+ }
+ });
+ builder.show();
+ }
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManager.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManager.java
new file mode 100644
index 000000000..f410aca31
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManager.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 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.todoroo.astrid.gtasks.auth;
+
+import android.content.Intent;
+
+/**
+ * This interface describes a class that will fetch and maintain a Google
+ * authentication token.
+ *
+ * @author Sandor Dornbush
+ */
+public interface AuthManager {
+
+ /**
+ * Initializes the login process. The user should be asked to login if they
+ * haven't already. The {@link Runnable} provided will be executed when the
+ * auth token is successfully fetched.
+ *
+ * @param whenFinished A {@link Runnable} to execute when the auth token
+ * has been successfully fetched and is available via
+ * {@link #getAuthToken()}
+ */
+ public abstract void doLogin(Runnable whenFinished, Object o);
+
+ /**
+ * The {@link android.app.Activity} owner of this class should call this
+ * function when it gets {@link android.app.Activity#onActivityResult} with
+ * the request code passed into the constructor. The resultCode and results
+ * should come directly from the {@link android.app.Activity#onActivityResult}
+ * function. This function will return true if an auth token was successfully
+ * fetched or the process is not finished.
+ *
+ * @param resultCode The result code passed in to the
+ * {@link android.app.Activity}'s
+ * {@link android.app.Activity#onActivityResult} function
+ * @param results The data passed in to the {@link android.app.Activity}'s
+ * {@link android.app.Activity#onActivityResult} function
+ * @return True if the auth token was fetched or we aren't done fetching
+ * the auth token, or False if there was an error or the request was
+ * canceled
+ */
+ public abstract boolean authResult(int resultCode, Intent results);
+
+ /**
+ * Returns the current auth token. Response may be null if no valid auth
+ * token has been fetched.
+ *
+ * @return The current auth token or null if no auth token has been
+ * fetched
+ */
+ public abstract String getAuthToken();
+
+ /**
+ * Invalidates the existing auth token and request a new one. The
+ * {@link Runnable} provided will be executed when the new auth token is
+ * successfully fetched.
+ *
+ * @param whenFinished A {@link Runnable} to execute when a new auth token
+ * is successfully fetched
+ */
+ public abstract void invalidateAndRefresh(Runnable whenFinished);
+
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerFactory.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerFactory.java
new file mode 100644
index 000000000..8ffbd0342
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010 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.todoroo.astrid.gtasks.auth;
+
+import android.app.Activity;
+import android.os.Build;
+import android.os.Bundle;
+
+/**
+ * A factory for getting the platform specific AuthManager.
+ *
+ * @author Sandor Dornbush
+ */
+public class AuthManagerFactory {
+
+ private AuthManagerFactory() {
+ // don't construct me
+ }
+
+ /**
+ * Returns whether the modern AuthManager should be used
+ */
+ public static boolean useModernAuthManager() {
+ return Integer.parseInt(Build.VERSION.SDK) >= 7;
+ }
+
+ /**
+ * Get a right {@link AuthManager} for the platform.
+ * @return A new AuthManager
+ */
+ public static AuthManager getAuthManager(Activity activity, int code,
+ Bundle extras, boolean requireGoogle, String service) {
+ if (useModernAuthManager()) {
+ return new ModernAuthManager(activity, code, extras, requireGoogle, service);
+ } else {
+ return new AuthManagerOld(activity, code, extras, requireGoogle, service);
+ }
+ }
+
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerOld.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerOld.java
new file mode 100644
index 000000000..eda7413e2
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/AuthManagerOld.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2009 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.todoroo.astrid.gtasks.auth;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.google.android.googlelogindist.GoogleLoginServiceConstants;
+import com.google.android.googlelogindist.GoogleLoginServiceHelper;
+
+/**
+ * AuthManager keeps track of the current auth token for a user. The advantage
+ * over just passing around a String is that this class can renew the auth
+ * token if necessary, and it will change for all classes using this
+ * AuthManager.
+ */
+public class AuthManagerOld implements AuthManager {
+ /** The activity that will handle auth result callbacks. */
+ private final Activity activity;
+
+ /** The code used to tell the activity that it is an auth result. */
+ private final int code;
+
+ /** Extras to pass into the getCredentials function. */
+ private final Bundle extras;
+
+ /** True if the account must be a Google account (not a domain account). */
+ private final boolean requireGoogle;
+
+ /** The name of the service to authorize for. */
+ private final String service;
+
+ /** A list of handlers to call when a new auth token is fetched. */
+ private final Vector newTokenListeners = new Vector();
+
+ /** The most recently fetched auth token or null if none is available. */
+ private String authToken;
+
+ /**
+ * The number of handlers at the beginning of the above list that shouldn't
+ * be removed after they are called.
+ */
+ private int stickyNewTokenListenerCount;
+
+ /**
+ * AuthManager requires many of the same parameters as
+ * {@link GoogleLoginServiceHelper#getCredentials(Activity, int, Bundle,
+ * boolean, String, boolean)}. The activity must have
+ * a handler in {@link Activity#onActivityResult} that calls
+ * {@link #authResult(int, Intent)} if the request code is the code given
+ * here.
+ *
+ * @param activity An activity with a handler in
+ * {@link Activity#onActivityResult} that calls
+ * {@link #authResult(int, Intent)} when {@literal code} is the request
+ * code
+ * @param code The request code to pass to
+ * {@link Activity#onActivityResult} when
+ * {@link #authResult(int, Intent)} should be called
+ * @param extras A {@link Bundle} of extras for
+ * {@link GoogleLoginServiceHelper}
+ * @param requireGoogle True if the account must be a Google account
+ * @param service The name of the service to authenticate as
+ */
+ public AuthManagerOld(Activity activity, int code, Bundle extras,
+ boolean requireGoogle, String service) {
+ this.activity = activity;
+ this.code = code;
+ this.extras = extras;
+ this.requireGoogle = requireGoogle;
+ this.service = service;
+ }
+
+ /* (non-Javadoc)
+ * @see com.google.android.apps.mytracks.io.AuthManager#doLogin(java.lang.Runnable)
+ */
+ public void doLogin(Runnable whenFinished, Object o) {
+ synchronized (newTokenListeners) {
+ if (whenFinished != null) {
+ newTokenListeners.add(whenFinished);
+ }
+ }
+ activity.runOnUiThread(new LoginRunnable());
+ }
+
+ /**
+ * Runnable which actually gets login credentials.
+ */
+ private class LoginRunnable implements Runnable {
+ @Override
+ public void run() {
+ GoogleLoginServiceHelper.getCredentials(
+ activity, code, extras, requireGoogle, service, true);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.google.android.apps.mytracks.io.AuthManager#authResult(int, android.content.Intent)
+ */
+ public boolean authResult(int resultCode, Intent results) {
+ if (resultCode == Activity.RESULT_OK) {
+ authToken = results.getStringExtra(
+ GoogleLoginServiceConstants.AUTHTOKEN_KEY);
+ if (authToken == null) {
+ GoogleLoginServiceHelper.getCredentials(
+ activity, code, extras, requireGoogle, service, false);
+ return true;
+ } else {
+ // Notify all active listeners that we have a new auth token.
+ synchronized (newTokenListeners) {
+ Iterator iter = newTokenListeners.iterator();
+ while (iter.hasNext()) {
+ iter.next().run();
+ }
+ iter = null;
+ // Remove anything not in the sticky part of the list.
+ newTokenListeners.setSize(stickyNewTokenListenerCount);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see com.google.android.apps.mytracks.io.AuthManager#getAuthToken()
+ */
+ public String getAuthToken() {
+ return authToken;
+ }
+
+ /* (non-Javadoc)
+ * @see com.google.android.apps.mytracks.io.AuthManager#invalidateAndRefresh(java.lang.Runnable)
+ */
+ public void invalidateAndRefresh(Runnable whenFinished) {
+ synchronized (newTokenListeners) {
+ if (whenFinished != null) {
+ newTokenListeners.add(whenFinished);
+ }
+ }
+ activity.runOnUiThread(new Runnable() {
+ public void run() {
+ GoogleLoginServiceHelper.invalidateAuthToken(activity, code, authToken);
+ }
+ });
+ }
+
+ /**
+ * Adds a {@link Runnable} to be executed every time the auth token is
+ * updated. The {@link Runnable} will not be removed until manually removed
+ * with {@link #removeStickyNewTokenListener(Runnable)}.
+ *
+ * @param listener The {@link Runnable} to execute every time a new auth
+ * token is fetched
+ */
+ public void addStickyNewTokenListener(Runnable listener) {
+ synchronized (newTokenListeners) {
+ newTokenListeners.add(0, listener);
+ stickyNewTokenListenerCount++;
+ }
+ }
+
+ /**
+ * Stops executing the given {@link Runnable} every time the auth token is
+ * updated. This {@link Runnable} must have been added with
+ * {@link #addStickyNewTokenListener(Runnable)} above. If the
+ * {@link Runnable} was added more than once, only the first occurrence
+ * will be removed.
+ *
+ * @param listener The {@link Runnable} to stop executing every time a new
+ * auth token is fetched
+ */
+ public void removeStickyNewTokenListener(Runnable listener) {
+ synchronized (newTokenListeners) {
+ if (stickyNewTokenListenerCount > 0
+ && newTokenListeners.remove(listener)) {
+ stickyNewTokenListenerCount--;
+ }
+ }
+ }
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/ModernAuthManager.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/ModernAuthManager.java
new file mode 100644
index 000000000..0df1b4812
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/auth/ModernAuthManager.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2010 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.todoroo.astrid.gtasks.auth;
+
+import java.io.IOException;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * AuthManager keeps track of the current auth token for a user. The advantage
+ * over just passing around a String is that this class can renew the auth
+ * token if necessary, and it will change for all classes using this
+ * AuthManager.
+ */
+public class ModernAuthManager implements AuthManager {
+ protected static final int GET_LOGIN_REQUEST = 1;
+
+/** The activity that will handle auth result callbacks. */
+ private final Activity activity;
+
+ /** The name of the service to authorize for. */
+ private final String service;
+
+ /** The most recently fetched auth token or null if none is available. */
+ private String authToken;
+
+ private final AccountManager accountManager;
+
+ private Runnable whenFinished;
+
+ /**
+ * AuthManager requires many of the same parameters as
+ * {@link com.google.android.googlelogindist.GoogleLoginServiceHelper
+ * #getCredentials(Activity, int, Bundle, boolean, String, boolean)}.
+ * The activity must have a handler in {@link Activity#onActivityResult} that
+ * calls {@link #authResult(int, Intent)} if the request code is the code
+ * given here.
+ *
+ * @param activity An activity with a handler in
+ * {@link Activity#onActivityResult} that calls
+ * {@link #authResult(int, Intent)} when {@literal code} is the request
+ * code
+ * @param code The request code to pass to
+ * {@link Activity#onActivityResult} when
+ * {@link #authResult(int, Intent)} should be called
+ * @param extras A {@link Bundle} of extras for
+ * {@link com.google.android.googlelogindist.GoogleLoginServiceHelper}
+ * @param requireGoogle True if the account must be a Google account
+ * @param service The name of the service to authenticate as
+ */
+ public ModernAuthManager(Activity activity, int code, Bundle extras,
+ boolean requireGoogle, String service) {
+ this.activity = activity;
+ this.service = service;
+ this.accountManager = AccountManager.get(activity);
+ }
+
+ /**
+ * Call this to do the initial login. The user will be asked to login if
+ * they haven't already. The {@link Runnable} provided will be executed
+ * when the auth token is successfully fetched.
+ *
+ * @param runnable A {@link Runnable} to execute when the auth token
+ * has been successfully fetched and is available via
+ * {@link #getAuthToken()}
+ */
+ @SuppressWarnings("nls")
+ public void doLogin(final Runnable runnable, Object o) {
+ this.whenFinished = runnable;
+ if (!(o instanceof Account)) {
+ throw new IllegalArgumentException("FroyoAuthManager requires an account.");
+ }
+ Account account = (Account) o;
+ accountManager.getAuthToken(account, service, true,
+ new AccountManagerCallback() {
+ public void run(AccountManagerFuture future) {
+ try {
+ Bundle result = future.getResult();
+
+ // AccountManager needs user to grant permission
+ if (result.containsKey(AccountManager.KEY_INTENT)) {
+ Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
+ clearNewTaskFlag(intent);
+ activity.startActivityForResult(intent, GET_LOGIN_REQUEST);
+ return;
+ }
+
+ authToken = result.getString(
+ AccountManager.KEY_AUTHTOKEN);
+ Log.e("gtasks-auth", "Got auth token.");
+ runWhenFinished();
+ } catch (OperationCanceledException e) {
+ Log.e("gtasks-auth", "Operation Canceled", e);
+ } catch (IOException e) {
+ Log.e("gtasks-auth", "IOException", e);
+ } catch (AuthenticatorException e) {
+ Log.e("gtasks-auth", "Authentication Failed", e);
+ }
+ }
+ }, null /* handler */);
+ }
+
+ private static void clearNewTaskFlag(Intent intent) {
+ int flags = intent.getFlags();
+ flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
+ intent.setFlags(flags);
+ }
+
+ /**
+ * The {@link Activity} passed into the constructor should call this
+ * function when it gets {@link Activity#onActivityResult} with the request
+ * code passed into the constructor. The resultCode and results should
+ * come directly from the {@link Activity#onActivityResult} function. This
+ * function will return true if an auth token was successfully fetched or
+ * the process is not finished.
+ *
+ * @param resultCode The result code passed in to the {@link Activity}'s
+ * {@link Activity#onActivityResult} function
+ * @param results The data passed in to the {@link Activity}'s
+ * {@link Activity#onActivityResult} function
+ * @return True if the auth token was fetched or we aren't done fetching
+ * the auth token, or False if there was an error or the request was
+ * canceled
+ */
+ @SuppressWarnings("nls")
+ public boolean authResult(int resultCode, Intent results) {
+ if (results != null) {
+ authToken = results.getStringExtra(
+ AccountManager.KEY_AUTHTOKEN);
+ Log.w("google-auth", "authResult: " + authToken);
+ } else {
+ Log.e("google-auth", "No auth result results!!");
+ }
+ runWhenFinished();
+ return authToken != null;
+ }
+
+ /**
+ * Returns the current auth token. Response may be null if no valid auth
+ * token has been fetched.
+ *
+ * @return The current auth token or null if no auth token has been
+ * fetched
+ */
+ public String getAuthToken() {
+ return authToken;
+ }
+
+ /**
+ * Invalidates the existing auth token and request a new one. The
+ * {@link Runnable} provided will be executed when the new auth token is
+ * successfully fetched.
+ *
+ * @param runnable A {@link Runnable} to execute when a new auth token
+ * is successfully fetched
+ */
+ public void invalidateAndRefresh(final Runnable runnable) {
+ this.whenFinished = runnable;
+
+ activity.runOnUiThread(new Runnable() {
+ public void run() {
+ accountManager.invalidateAuthToken("com.google", authToken); //$NON-NLS-1$
+ new AccountChooser().chooseAccount(activity,
+ new AccountChooser.AccountHandler() {
+ @Override
+ public void handleAccountSelected(Account account) {
+ if (account != null) {
+ doLogin(whenFinished, account);
+ } else {
+ runWhenFinished();
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private void runWhenFinished() {
+ if (whenFinished != null) {
+ (new Thread() {
+ @Override
+ public void run() {
+ whenFinished.run();
+ }
+ }).start();
+ }
+ }
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncProvider.java b/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncProvider.java
index b3da92157..83aa673e7 100644
--- a/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncProvider.java
+++ b/astrid/plugin-src/com/todoroo/astrid/gtasks/sync/GtasksSyncProvider.java
@@ -16,6 +16,8 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
@@ -41,6 +43,8 @@ import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.GtasksPreferences;
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
+import com.todoroo.astrid.gtasks.auth.AuthManager;
+import com.todoroo.astrid.gtasks.auth.AuthManagerFactory;
import com.todoroo.astrid.producteev.api.ApiServiceException;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.sync.SyncBackgroundService;
@@ -48,7 +52,6 @@ import com.todoroo.astrid.sync.SyncContainer;
import com.todoroo.astrid.sync.SyncProvider;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.gtasks.GoogleConnectionManager;
-import com.todoroo.gtasks.GoogleLoginException;
import com.todoroo.gtasks.GoogleTaskService;
import com.todoroo.gtasks.GoogleTaskTask;
import com.todoroo.gtasks.GoogleTaskView;
@@ -83,8 +86,6 @@ public class GtasksSyncProvider extends SyncProvider {
public GtasksSyncProvider() {
super();
DependencyInjectionService.getInstance().inject(this);
- // TODO?
- gtasksPreferenceService.stopOngoing();
}
// ----------------------------------------------------------------------
@@ -152,7 +153,8 @@ public class GtasksSyncProvider extends SyncProvider {
final GoogleConnectionManager connectionManager;
if(authToken == null) {
- connectionManager = logInHelper();
+ Log.e("astrid-sync", "No token, unable to sync");
+ return;
} else {
connectionManager = new GoogleConnectionManager(authToken);
}
@@ -168,36 +170,39 @@ public class GtasksSyncProvider extends SyncProvider {
}
}
- private GoogleConnectionManager logInHelper() throws GoogleLoginException,
- IOException {
- // TODO get email and password or something?
- String email = "tasktest@todoroo.com";
- String password = "tasktest0000";
- GoogleConnectionManager connectionManager = new GoogleConnectionManager(email, password);
- connectionManager.authenticate(true);
- gtasksPreferenceService.setToken(connectionManager.getToken());
- return connectionManager;
- }
-
/**
* If user isn't already signed in, show sign in dialog. Else perform sync.
*/
@Override
- protected void initiateManual(Activity activity) {
+ protected void initiateManual(final Activity activity) {
String authToken = gtasksPreferenceService.getToken();
gtasksPreferenceService.stopOngoing();
// check if we have a token & it works
if(authToken == null) {
try {
- logInHelper();
+ final AuthManager authManager = AuthManagerFactory.getAuthManager(activity, 0, new Bundle(), true, "goanna_mobile");
+ authManager.invalidateAndRefresh(new Runnable() {
+ @Override
+ public void run() {
+ String token = authManager.getAuthToken();
+ if(token != null) {
+ gtasksPreferenceService.setToken(token);
+ //activity.startService(new Intent(SyncBackgroundService.SYNC_ACTION, null,
+ // activity, GtasksBackgroundService.class));
+ System.err.println("yay! " + token);
+ activity.finish();
+ }
+ }
+ });
} catch (Exception e) {
handleException("auth", e, true);
}
- }
-
- activity.startService(new Intent(SyncBackgroundService.SYNC_ACTION, null,
+ } else {
+ activity.startService(new Intent(SyncBackgroundService.SYNC_ACTION, null,
activity, GtasksBackgroundService.class));
+ activity.finish();
+ }
}
diff --git a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java
index 3d51b53ae..d62fa6e86 100644
--- a/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java
+++ b/astrid/plugin-src/com/todoroo/astrid/producteev/ProducteevPreferences.java
@@ -31,6 +31,7 @@ public class ProducteevPreferences extends SyncProviderPreferences {
@Override
public void startSync() {
new ProducteevSyncProvider().synchronize(this);
+ finish();
}
@Override
diff --git a/astrid/res/values/strings-gtasks.xml b/astrid/res/values/strings-gtasks.xml
index febd2d61a..912031eb3 100644
--- a/astrid/res/values/strings-gtasks.xml
+++ b/astrid/res/values/strings-gtasks.xml
@@ -35,5 +35,14 @@
Astrid: Google Tasks
+
+ Choose Account
+
+
+ No Accounts Found
+
+
+ We were unable to find a Google account on this phone. You will not be able to synchronize to Google Tasks without one!
+
diff --git a/astrid/rmilk-src/org/weloveastrid/rmilk/MilkPreferences.java b/astrid/rmilk-src/org/weloveastrid/rmilk/MilkPreferences.java
index 613486a18..89b3ab780 100644
--- a/astrid/rmilk-src/org/weloveastrid/rmilk/MilkPreferences.java
+++ b/astrid/rmilk-src/org/weloveastrid/rmilk/MilkPreferences.java
@@ -23,6 +23,7 @@ public class MilkPreferences extends SyncProviderPreferences {
@Override
public void startSync() {
new MilkSyncProvider().synchronize(this);
+ finish();
}
@Override