summaryrefslogtreecommitdiffstats
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
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}
-rw-r--r--chrome/android/javatests/AndroidManifest.xml8
-rw-r--r--chrome/android/sync_shell/javatests/AndroidManifest.xml9
-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
-rw-r--r--sync/sync_android.gypi1
-rw-r--r--sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java419
-rw-r--r--sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java48
10 files changed, 112 insertions, 524 deletions
diff --git a/chrome/android/javatests/AndroidManifest.xml b/chrome/android/javatests/AndroidManifest.xml
index 13c98db..f073bef 100644
--- a/chrome/android/javatests/AndroidManifest.xml
+++ b/chrome/android/javatests/AndroidManifest.xml
@@ -30,14 +30,6 @@
android:authorities="org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsDelayedProvider"
android:exported="true" />
- <activity android:name="org.chromium.sync.test.util.MockGrantCredentialsPermissionActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
<activity android:name="org.chromium.chrome.browser.customtabs.CustomTabExternalNavigationTest$DummyActivityForSpecialScheme"
android:exported="true" >
<intent-filter>
diff --git a/chrome/android/sync_shell/javatests/AndroidManifest.xml b/chrome/android/sync_shell/javatests/AndroidManifest.xml
index eb83976..8aff831 100644
--- a/chrome/android/sync_shell/javatests/AndroidManifest.xml
+++ b/chrome/android/sync_shell/javatests/AndroidManifest.xml
@@ -15,16 +15,7 @@
<application
android:label="ChromeSyncShellTest">
-
<uses-library android:name="android.test.runner" />
-
- <activity android:name="org.chromium.sync.test.util.MockGrantCredentialsPermissionActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
</application>
<instrumentation android:name="org.chromium.chrome.test.ChromeInstrumentationTestRunner"
android:targetPackage="{{manifest_package}}"
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
diff --git a/sync/sync_android.gypi b/sync/sync_android.gypi
index c71dfdc..e2600c0 100644
--- a/sync/sync_android.gypi
+++ b/sync/sync_android.gypi
@@ -18,6 +18,7 @@
'sync_jni_headers',
'../base/base.gyp:base_java',
'../net/net.gyp:net_java',
+ '../third_party/android_tools/android_tools.gyp:google_play_services_javalib',
'../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
'../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
],
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
index 8c3efc9..f28f21d 100644
--- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
+++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
@@ -8,23 +8,11 @@ import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.os.AsyncTask;
-import android.os.Bundle;
import android.os.Handler;
-import android.text.TextUtils;
import org.chromium.base.Callback;
import org.chromium.base.Log;
@@ -32,24 +20,13 @@ import org.chromium.base.VisibleForTesting;
import org.chromium.sync.signin.AccountManagerDelegate;
import org.chromium.sync.signin.AccountManagerHelper;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.Nullable;
/**
* The MockAccountManager helps out if you want to mock out all calls to the Android AccountManager.
@@ -84,8 +61,6 @@ public class MockAccountManager implements AccountManagerDelegate {
private final Set<AccountHolder> mAccounts;
- private final List<AccountAuthTokenPreparation> mAccountPermissionPreparations;
-
private final Handler mMainHandler;
private final SingleThreadedExecutor mExecutor;
@@ -104,7 +79,6 @@ public class MockAccountManager implements AccountManagerDelegate {
mExecutor = new SingleThreadedExecutor();
mGetAccountsTaskCounter = new ZeroCounter();
mAccounts = new HashSet<AccountHolder>();
- mAccountPermissionPreparations = new LinkedList<AccountAuthTokenPreparation>();
if (accounts != null) {
for (Account account : accounts) {
mAccounts.add(AccountHolder.create().account(account).alwaysAccept(true).build());
@@ -119,7 +93,7 @@ public class MockAccountManager implements AccountManagerDelegate {
}
@Override
- public Account[] getAccountsByType(@Nullable String type) {
+ public Account[] getAccountsByType(String type) {
if (!AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(type)) {
throw new IllegalArgumentException("Invalid account type: " + type);
}
@@ -128,7 +102,7 @@ public class MockAccountManager implements AccountManagerDelegate {
} else {
ArrayList<Account> validAccounts = new ArrayList<Account>();
for (AccountHolder ah : mAccounts) {
- if (TextUtils.equals(ah.getAccount().type, type)) {
+ if (type.equals(ah.getAccount().type)) {
validAccounts.add(ah.getAccount());
}
}
@@ -208,72 +182,28 @@ public class MockAccountManager implements AccountManagerDelegate {
}
@Override
- public AccountManagerFuture<Bundle> getAuthToken(Account account, String authTokenType,
- boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler) {
- return getAuthTokenFuture(account, authTokenType, null, callback, handler);
- }
-
- private AccountManagerFuture<Bundle> getAuthTokenFuture(Account account, String authTokenType,
- Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
- final AccountHolder ah = getAccountHolder(account);
- if (ah.hasBeenAccepted(authTokenType)) {
- final String authToken = internalGenerateAndStoreAuthToken(ah, authTokenType);
- return runTask(mExecutor,
- new AccountManagerAuthTokenTask(activity, handler, callback,
- account, authTokenType,
- new Callable<Bundle>() {
- @Override
- public Bundle call() throws Exception {
- return getAuthTokenBundle(ah.getAccount(), authToken);
- }
- }));
- } else {
- Log.d(TAG, "getAuthTokenFuture: Account " + ah.getAccount()
- + " is asking for permission for " + authTokenType);
- final Intent intent = newGrantCredentialsPermissionIntent(
- activity != null, account, authTokenType);
- return runTask(mExecutor,
- new AccountManagerAuthTokenTask(activity, handler, callback,
- account, authTokenType,
- new Callable<Bundle>() {
- @Override
- public Bundle call() throws Exception {
- Bundle result = new Bundle();
- result.putParcelable(AccountManager.KEY_INTENT, intent);
- return result;
- }
- }));
- }
- }
-
- private static Bundle getAuthTokenBundle(Account account, String authToken) {
- Bundle result = new Bundle();
- result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
- result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
- return result;
- }
-
- private String internalGenerateAndStoreAuthToken(AccountHolder ah, String authTokenType) {
+ public String getAuthToken(Account account, String authTokenScope) {
+ AccountHolder ah = getAccountHolder(account);
+ assert ah.hasBeenAccepted(authTokenScope);
synchronized (mAccounts) {
// Some tests register auth tokens with value null, and those should be preserved.
- if (!ah.hasAuthTokenRegistered(authTokenType)
- && ah.getAuthToken(authTokenType) == null) {
+ if (!ah.hasAuthTokenRegistered(authTokenScope)
+ && ah.getAuthToken(authTokenScope) == null) {
// No authtoken registered. Need to create one.
String authToken = UUID.randomUUID().toString();
- Log.d(TAG, "Created new auth token for " + ah.getAccount()
- + ": autTokenType = " + authTokenType + ", authToken = " + authToken);
- ah = ah.withAuthToken(authTokenType, authToken);
+ Log.d(TAG, "Created new auth token for " + ah.getAccount() + ": authTokenScope = "
+ + authTokenScope + ", authToken = " + authToken);
+ ah = ah.withAuthToken(authTokenScope, authToken);
mAccounts.add(ah);
}
}
- return ah.getAuthToken(authTokenType);
+ return ah.getAuthToken(authTokenScope);
}
@Override
- public void invalidateAuthToken(String accountType, String authToken) {
- if (!AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(accountType)) {
- throw new IllegalArgumentException("Invalid account type: " + accountType);
+ public void invalidateAuthToken(String accountScope, String authToken) {
+ if (!AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(accountScope)) {
+ throw new IllegalArgumentException("Invalid account type: " + accountScope);
}
if (authToken == null) {
throw new IllegalArgumentException("AuthToken can not be null");
@@ -313,74 +243,6 @@ public class MockAccountManager implements AccountManagerDelegate {
});
}
- public void notifyFeaturesFetched(Account account, Set<String> features) {
- getAccountHolder(account).didFetchFeatures(features);
- }
-
- public void prepareAllowAppPermission(Account account, String authTokenType) {
- addPreparedAppPermission(new AccountAuthTokenPreparation(account, authTokenType, true));
- }
-
- public void prepareDenyAppPermission(Account account, String authTokenType) {
- addPreparedAppPermission(new AccountAuthTokenPreparation(account, authTokenType, false));
- }
-
- private void addPreparedAppPermission(AccountAuthTokenPreparation accountAuthTokenPreparation) {
- Log.d(TAG, "Adding " + accountAuthTokenPreparation);
- mAccountPermissionPreparations.add(accountAuthTokenPreparation);
- }
-
- private AccountAuthTokenPreparation getPreparedPermission(Account account,
- String authTokenType) {
- for (AccountAuthTokenPreparation accountPrep : mAccountPermissionPreparations) {
- if (accountPrep.getAccount().equals(account)
- && accountPrep.getAuthTokenType().equals(authTokenType)) {
- return accountPrep;
- }
- }
- return null;
- }
-
- private void applyPreparedPermission(AccountAuthTokenPreparation prep) {
- if (prep != null) {
- Log.d(TAG, "Applying " + prep);
- mAccountPermissionPreparations.remove(prep);
- mAccounts.add(getAccountHolder(prep.getAccount()).withHasBeenAccepted(
- prep.getAuthTokenType(), prep.isAllowed()));
- }
- }
-
- private Intent newGrantCredentialsPermissionIntent(boolean hasActivity, Account account,
- String authTokenType) {
- ComponentName component = new ComponentName(mTestContext,
- MockGrantCredentialsPermissionActivity.class.getCanonicalName());
-
- // Make sure we can start the activity.
- ActivityInfo ai = null;
- try {
- ai = mContext.getPackageManager().getActivityInfo(component, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalStateException(
- "Unable to find " + component.getClassName());
- }
- if (ai.applicationInfo != mContext.getApplicationInfo() && !ai.exported) {
- throw new IllegalStateException(
- "Unable to start " + ai.name + ". "
- + "The accounts you added to MockAccountManager may not be "
- + "configured correctly.");
- }
-
- Intent intent = new Intent();
- intent.setComponent(component);
- intent.putExtra(MockGrantCredentialsPermissionActivity.ACCOUNT, account);
- intent.putExtra(MockGrantCredentialsPermissionActivity.AUTH_TOKEN_TYPE, authTokenType);
- if (!hasActivity) {
- // No activity provided, so we help the caller by adding the new task flag
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
- return intent;
- }
-
private AccountHolder getAccountHolder(Account account) {
if (account == null) {
throw new IllegalArgumentException("Account can not be null");
@@ -393,216 +255,6 @@ public class MockAccountManager implements AccountManagerDelegate {
throw new IllegalArgumentException("Can not find AccountHolder for account " + account);
}
- private static <T> AccountManagerFuture<T> runTask(Executor executorService,
- AccountManagerTask<T> accountManagerBundleTask) {
- executorService.execute(accountManagerBundleTask);
- return accountManagerBundleTask;
- }
-
- private class AccountManagerTask<T> extends FutureTask<T> implements AccountManagerFuture<T> {
-
- protected final Handler mHandler;
-
- protected final AccountManagerCallback<T> mCallback;
-
- protected final Callable<T> mCallable;
-
- public AccountManagerTask(Handler handler,
- AccountManagerCallback<T> callback, Callable<T> callable) {
- super(new Callable<T>() {
- @Override
- public T call() throws Exception {
- throw new IllegalStateException("this should never be called, "
- + "but call must be overridden.");
- }
- });
- mHandler = handler;
- mCallback = callback;
- mCallable = callable;
- }
-
- private T internalGetResult(long timeout, TimeUnit unit)
- throws OperationCanceledException, IOException, AuthenticatorException {
- try {
- if (timeout == -1) {
- return get();
- } else {
- return get(timeout, unit);
- }
- } catch (CancellationException e) {
- throw new OperationCanceledException();
- } catch (TimeoutException e) {
- // Fall through and cancel.
- } catch (InterruptedException e) {
- // Fall through and cancel.
- } catch (ExecutionException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof IOException) {
- throw (IOException) cause;
- } else if (cause instanceof UnsupportedOperationException) {
- throw new AuthenticatorException(cause);
- } else if (cause instanceof AuthenticatorException) {
- throw (AuthenticatorException) cause;
- } else if (cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- } else if (cause instanceof Error) {
- throw (Error) cause;
- } else {
- throw new IllegalStateException(cause);
- }
- } finally {
- cancel(true /* Interrupt if running. */);
- }
- throw new OperationCanceledException();
- }
-
- @Override
- public T getResult()
- throws OperationCanceledException, IOException, AuthenticatorException {
- return internalGetResult(-1, null);
- }
-
- @Override
- public T getResult(long timeout, TimeUnit unit)
- throws OperationCanceledException, IOException, AuthenticatorException {
- return internalGetResult(timeout, unit);
- }
-
- @Override
- public void run() {
- try {
- set(mCallable.call());
- } catch (Exception e) {
- setException(e);
- }
- }
-
- @Override
- protected void done() {
- if (mCallback != null) {
- postToHandler(getHandler(), mCallback, this);
- }
- }
-
- private Handler getHandler() {
- return mHandler == null ? mMainHandler : mHandler;
- }
-
- }
-
- private static <T> void postToHandler(Handler handler, final AccountManagerCallback<T> callback,
- final AccountManagerFuture<T> future) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.run(future);
- }
- });
- }
-
- private class AccountManagerAuthTokenTask extends AccountManagerTask<Bundle> {
-
- private final Activity mActivity;
-
- private final AccountAuthTokenPreparation mAccountAuthTokenPreparation;
-
- private final Account mAccount;
-
- private final String mAuthTokenType;
-
- public AccountManagerAuthTokenTask(Activity activity, Handler handler,
- AccountManagerCallback<Bundle> callback,
- Account account, String authTokenType,
- Callable<Bundle> callable) {
- super(handler, callback, callable);
- mActivity = activity;
- mAccountAuthTokenPreparation = getPreparedPermission(account, authTokenType);
- mAccount = account;
- mAuthTokenType = authTokenType;
- }
-
- @Override
- public void run() {
- try {
- Bundle bundle = mCallable.call();
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
- if (intent != null) {
- // Start the intent activity and wait for it to finish.
- if (mActivity != null) {
- waitForActivity(mActivity, intent);
- } else {
- waitForActivity(mContext, intent);
- }
- if (mAccountAuthTokenPreparation == null) {
- throw new IllegalStateException("No account preparation ready for "
- + mAccount + ", authTokenType = " + mAuthTokenType
- + ". Add a call to either prepareGrantAppPermission(...) or "
- + "prepareRevokeAppPermission(...) in your test before asking for "
- + "an auth token");
- } else {
- // We have shown the Allow/Deny activity, and it has gone away. We can now
- // apply the pre-stored permission.
- applyPreparedPermission(mAccountAuthTokenPreparation);
- generateResult(getAccountHolder(mAccount), mAuthTokenType);
- }
- } else {
- set(bundle);
- }
- } catch (Exception e) {
- setException(e);
- }
- }
-
- private void generateResult(AccountHolder accountHolder, String authTokenType)
- throws OperationCanceledException {
- if (accountHolder.hasBeenAccepted(authTokenType)) {
- String authToken = internalGenerateAndStoreAuthToken(accountHolder, authTokenType);
- // Return a valid auth token.
- set(getAuthTokenBundle(accountHolder.getAccount(), authToken));
- } else {
- // Throw same exception as when user clicks "Deny".
- throw new OperationCanceledException("User denied request");
- }
- }
- }
-
- /**
- * This method starts {@link MockGrantCredentialsPermissionActivity} and waits for it
- * to be started before it returns.
- *
- * @param context the context to start the intent in
- * @param intent the intent to use to start MockGrantCredentialsPermissionActivity
- */
- @SuppressWarnings("WaitNotInLoop")
- private void waitForActivity(Context context, Intent intent) {
- final Object mutex = new Object();
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mutex) {
- mutex.notifyAll();
- }
- }
- };
- if (!MockGrantCredentialsPermissionActivity.class.getCanonicalName()
- .equals(intent.getComponent().getClassName())) {
- throw new IllegalArgumentException("Can only wait for "
- + "MockGrantCredentialsPermissionActivity");
- }
- mContext.registerReceiver(receiver, new IntentFilter(MUTEX_WAIT_ACTION));
- context.startActivity(intent);
- try {
- Log.d(TAG, "Waiting for broadcast of " + MUTEX_WAIT_ACTION);
- synchronized (mutex) {
- mutex.wait(WAIT_TIME_FOR_GRANT_BROADCAST_MS);
- }
- } catch (InterruptedException e) {
- throw new IllegalStateException("Got unexpected InterruptedException");
- }
- Log.d(TAG, "Got broadcast of " + MUTEX_WAIT_ACTION);
- mContext.unregisterReceiver(receiver);
- }
-
private void postAsyncAccountChangedEvent() {
// Mimic that this does not happen on the main thread.
new AsyncTask<Void, Void, Void>() {
@@ -615,49 +267,6 @@ public class MockAccountManager implements AccountManagerDelegate {
}
/**
- * Internal class for storage of prepared account auth token permissions.
- *
- * This is used internally by {@link MockAccountManager} to mock the same behavior as clicking
- * Allow/Deny in the Android {@link GrantCredentialsPermissionActivity}.
- */
- private static class AccountAuthTokenPreparation {
-
- private final Account mAccount;
-
- private final String mAuthTokenType;
-
- private final boolean mAllowed;
-
- private AccountAuthTokenPreparation(Account account, String authTokenType,
- boolean allowed) {
- mAccount = account;
- mAuthTokenType = authTokenType;
- mAllowed = allowed;
- }
-
- public Account getAccount() {
- return mAccount;
- }
-
- public String getAuthTokenType() {
- return mAuthTokenType;
- }
-
- public boolean isAllowed() {
- return mAllowed;
- }
-
- @Override
- public String toString() {
- return "AccountAuthTokenPreparation{"
- + "mAccount=" + mAccount
- + ", mAuthTokenType='" + mAuthTokenType + '\''
- + ", mAllowed=" + mAllowed
- + '}';
- }
- }
-
- /**
* Simple concurrency helper class for waiting until a resource count becomes zero.
*/
private static class ZeroCounter {
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java
index 79a2914..bbc4385 100644
--- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java
+++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java
@@ -4,56 +4,10 @@
package org.chromium.sync.test.util;
-import android.accounts.Account;
import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.widget.TextView;
/**
- * A dummy implementation of the Android {@link GrantCredentialsPermissionActivity} that is used
- * when displaying the Allow/Deny dialog when an application asks for an auth token
- * for a given auth token type and that app has never gotten the permission.
- *
- * Currently this activity just starts up, broadcasts an intent, and finishes.
- *
- * This class is used by {@link MockAccountManager}.
+ * TODO(knn): Remove this after downstream references have been removed.
*/
public class MockGrantCredentialsPermissionActivity extends Activity {
-
- private static final String TAG = "MockGrantCredentialsPermissionActivity";
-
- static final String ACCOUNT = "account";
-
- static final String AUTH_TOKEN_TYPE = "authTokenType";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- TextView textView = new TextView(this);
- Account account = (Account) getIntent().getParcelableExtra(ACCOUNT);
- String authTokenType = getIntent().getStringExtra(AUTH_TOKEN_TYPE);
- String accountName = account == null ? null : account.name;
- String message = "account = " + accountName + ", authTokenType = " + authTokenType;
- textView.setText(message);
- setContentView(textView);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- // Send out the broadcast after the Activity has completely started up.
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, "Broadcasting " + MockAccountManager.MUTEX_WAIT_ACTION);
- sendBroadcast(new Intent(MockAccountManager.MUTEX_WAIT_ACTION));
- finish();
- }
- });
- }
}