summaryrefslogtreecommitdiffstats
path: root/sync/android
diff options
context:
space:
mode:
authorknn <knn@chromium.org>2015-12-02 02:18:47 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-02 10:19:52 +0000
commit4a3edbe6c7515cfdb2d001ddc8fb4e830425a5a5 (patch)
treeabbf9c0e6a319be9d816782ad5378df0c776c72d /sync/android
parentc6397e4d6049de859b8aedc6299600ab55ba4944 (diff)
downloadchromium_src-4a3edbe6c7515cfdb2d001ddc8fb4e830425a5a5.zip
chromium_src-4a3edbe6c7515cfdb2d001ddc8fb4e830425a5a5.tar.gz
chromium_src-4a3edbe6c7515cfdb2d001ddc8fb4e830425a5a5.tar.bz2
Use GoogleAuthUtil's getToken instead of AccountManager.
GoogleAuthUtil gives us better error handling capability and gets rid of the AccountManagerFuture interface that is difficult to Mock in tests. We can do this since we are only handling Google accounts anyway. BUG=555495, 547048 Review URL: https://codereview.chromium.org/1440363002 Cr-Commit-Position: refs/heads/master@{#362676}
Diffstat (limited to 'sync/android')
-rw-r--r--sync/android/BUILD.gn1
-rw-r--r--sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java28
-rw-r--r--sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java52
-rw-r--r--sync/android/java/src/org/chromium/sync/signin/AuthException.java46
-rw-r--r--sync/android/java/src/org/chromium/sync/signin/SystemAccountManagerDelegate.java24
5 files changed, 96 insertions, 55 deletions
diff --git a/sync/android/BUILD.gn b/sync/android/BUILD.gn
index e7bd9e9..564a388 100644
--- a/sync/android/BUILD.gn
+++ b/sync/android/BUILD.gn
@@ -13,6 +13,7 @@ android_library("sync_java") {
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
"//third_party/jsr-305:jsr_305_javalib",
+ google_play_services_library,
]
srcjar_deps = [ ":java_enums" ]
DEPRECATED_java_in_dir = "java/src"
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
index cef541e..eafc4ae 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
@@ -5,11 +5,7 @@
package org.chromium.sync.signin;
import android.accounts.Account;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
-import android.os.Bundle;
-import android.os.Handler;
import org.chromium.base.Callback;
@@ -24,14 +20,34 @@ public interface AccountManagerDelegate {
*/
Account[] getAccountsByType(String type);
+ /**
+ * Get all the accounts for a given {@code type}.
+ */
void getAccountsByType(String type, Callback<Account[]> callback);
- AccountManagerFuture<Bundle> getAuthToken(Account account, String authTokenType,
- boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler);
+ /**
+ * @param account The {@link Account} for which the auth token is requested.
+ * @param authTokenScope The scope of the authToken being requested.
+ * @return The auth token fetched from the authenticator.
+ * The authenticator can throw an {@link AuthException} to indicate a failure in fetching the
+ * auth token perhaps due to a transient error or when user intervention is required (like
+ * confirming the credentials) which is expressed as an {@link Intent} to the handler.
+ * This should only be called on a background thread.
+ */
+ String getAuthToken(Account account, String authTokenScope) throws AuthException;
+ /**
+ * Invalidate the {@code authToken} associated with account type {@code accountType}.
+ */
void invalidateAuthToken(String accountType, String authToken);
+ /**
+ * Get all the available authenticator types.
+ */
AuthenticatorDescription[] getAuthenticatorTypes();
+ /**
+ * Check whether the {@code account} has all the features listed in {@code features}.
+ */
void hasFeatures(Account account, String[] features, Callback<Boolean> callback);
}
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
index fa72690..71be732 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -7,25 +7,18 @@ package org.chromium.sync.signin;
import android.Manifest;
import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Build;
-import android.os.Bundle;
import android.os.Process;
-import android.util.Log;
import org.chromium.base.Callback;
-import org.chromium.base.ThreadUtils;
+import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting;
import org.chromium.net.NetworkChangeNotifier;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -357,48 +350,21 @@ public class AccountManagerHelper {
Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED;
}
- // Gets the auth token synchronously
- private String getAuthTokenInner(AccountManagerFuture<Bundle> future,
- AtomicBoolean isTransientError) {
- try {
- Bundle result = future.getResult();
- if (result != null) {
- return result.getString(AccountManager.KEY_AUTHTOKEN);
- } else {
- Log.w(TAG, "Auth token - getAuthToken returned null");
- }
- } catch (OperationCanceledException e) {
- Log.w(TAG, "Auth token - operation cancelled", e);
- } catch (AuthenticatorException e) {
- Log.w(TAG, "Auth token - authenticator exception", e);
- } catch (IOException e) {
- Log.w(TAG, "Auth token - IO exception", e);
- isTransientError.set(true);
- }
- return null;
- }
-
private void getAuthTokenAsynchronously(final Account account, final String authTokenType,
final GetAuthTokenCallback callback, final AtomicInteger numTries,
final AtomicBoolean isTransientError, final ConnectionRetry retry) {
- // Return null token for no USE_CREDENTIALS permission.
- if (!hasUseCredentialsPermission()) {
- ThreadUtils.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- callback.tokenUnavailable(false);
- }
- });
- return;
- }
- final AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(
- account, authTokenType, true, null, null);
isTransientError.set(false);
-
new AsyncTask<Void, Void, String>() {
@Override
public String doInBackground(Void... params) {
- return getAuthTokenInner(future, isTransientError);
+ try {
+ return mAccountManager.getAuthToken(account, authTokenType);
+ } catch (AuthException ex) {
+ // TODO(547048): Handle the recovery intent if it is present.
+ isTransientError.set(ex.isTransientError());
+ Log.e(TAG, "Failed to getAuthToken", ex);
+ }
+ return null;
}
@Override
public void onPostExecute(String authToken) {
diff --git a/sync/android/java/src/org/chromium/sync/signin/AuthException.java b/sync/android/java/src/org/chromium/sync/signin/AuthException.java
new file mode 100644
index 0000000..56e2ed1
--- /dev/null
+++ b/sync/android/java/src/org/chromium/sync/signin/AuthException.java
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.sync.signin;
+
+import android.content.Intent;
+
+/*
+ * AuthException abstracts away authenticator specific exceptions behind a single interface.
+ * It is used for passing information that is useful for better handling of errors.
+ */
+public class AuthException extends Exception {
+ private final boolean mIsTransientError;
+ private final Intent mRecoveryIntent;
+
+ /*
+ * A simple constructor that stores all the error handling information and makes it available to
+ * the handler.
+ * @param isTransientError Whether the error is transient and we can retry.
+ * @param recoveryIntent An intent that can be used to recover from this error.
+ * Thus, a user recoverable error is not transient, since it requires explicit user handling
+ * before retry.
+ */
+ public AuthException(boolean isTransientError, Intent recoveryIntent, Exception exception) {
+ super(exception);
+ assert !isTransientError || recoveryIntent == null;
+ mIsTransientError = isTransientError;
+ mRecoveryIntent = recoveryIntent;
+ }
+
+ /*
+ * @return Whether the error is transient and we can retry.
+ */
+ public boolean isTransientError() {
+ return mIsTransientError;
+ }
+
+ /*
+ * @return An intent that can be used to recover from this error if it is recoverabale by user
+ * intervention, else {@code null}.
+ */
+ public Intent getRecoveryIntent() {
+ return mRecoveryIntent;
+ }
+}
diff --git a/sync/android/java/src/org/chromium/sync/signin/SystemAccountManagerDelegate.java b/sync/android/java/src/org/chromium/sync/signin/SystemAccountManagerDelegate.java
index 75777dd..d90280a 100644
--- a/sync/android/java/src/org/chromium/sync/signin/SystemAccountManagerDelegate.java
+++ b/sync/android/java/src/org/chromium/sync/signin/SystemAccountManagerDelegate.java
@@ -13,14 +13,17 @@ import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
import android.os.StrictMode;
import android.os.SystemClock;
+import com.google.android.gms.auth.GoogleAuthException;
+import com.google.android.gms.auth.GoogleAuthUtil;
+import com.google.android.gms.auth.UserRecoverableAuthException;
+
import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.MainDex;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.metrics.RecordHistogram;
@@ -31,6 +34,7 @@ import java.util.concurrent.TimeUnit;
* Default implementation of {@link AccountManagerDelegate} which delegates all calls to the
* Android account manager.
*/
+@MainDex
public class SystemAccountManagerDelegate implements AccountManagerDelegate {
private final AccountManager mAccountManager;
@@ -70,10 +74,18 @@ public class SystemAccountManagerDelegate implements AccountManagerDelegate {
}
@Override
- public AccountManagerFuture<Bundle> getAuthToken(Account account, String authTokenType,
- boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler) {
- return mAccountManager.getAuthToken(account, authTokenType, null, notifyAuthFailure,
- callback, handler);
+ public String getAuthToken(Account account, String authTokenScope) throws AuthException {
+ assert !ThreadUtils.runningOnUiThread();
+ assert AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(account.type);
+ try {
+ return GoogleAuthUtil.getToken(mApplicationContext, account, authTokenScope);
+ } catch (UserRecoverableAuthException ex) {
+ throw new AuthException(false /* isTransientError */, ex.getIntent(), ex);
+ } catch (GoogleAuthException ex) {
+ throw new AuthException(false /* isTransientError */, null, ex);
+ } catch (IOException ex) {
+ throw new AuthException(true /* isTransientError */, null, ex);
+ }
}
@Override