summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java6
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java153
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java276
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java275
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java (renamed from chrome/android/javatests/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelperTest.java)42
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java14
-rw-r--r--chrome/android/testshell/java/AndroidManifest.xml7
-rw-r--r--chrome/android/testshell/java/src/org/chromium/chrome/testshell/signin/AccountsChangedReceiver.java59
-rw-r--r--chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java15
-rw-r--r--chrome/browser/profiles/profile_android.cc23
-rw-r--r--chrome/browser/profiles/profile_android.h2
-rw-r--r--chrome/browser/signin/DEPS1
-rw-r--r--chrome/browser/signin/android_profile_oauth2_token_service.cc113
-rw-r--r--chrome/browser/signin/android_profile_oauth2_token_service.h43
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--google_apis/gaia/oauth2_token_service.h6
16 files changed, 873 insertions, 164 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java b/chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
index 4cec13e..138ebbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
@@ -17,6 +17,10 @@ public class Profile {
mNativeProfileAndroid = nativeProfileAndroid;
}
+ public static Profile getLastUsedProfile() {
+ return (Profile) nativeGetLastUsedProfile();
+ }
+
@CalledByNative
private static Profile create(int nativeProfileAndroid) {
return new Profile(nativeProfileAndroid);
@@ -31,4 +35,6 @@ public class Profile {
private int getNativePointer() {
return mNativeProfileAndroid;
}
+
+ private static native Object nativeGetLastUsedProfile();
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java
index 09d73a1..5a47988 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java
@@ -7,163 +7,46 @@ package org.chromium.chrome.browser.signin;
import android.accounts.Account;
import android.app.Activity;
import android.content.Context;
-import android.util.Log;
-import org.chromium.base.CalledByNative;
-import org.chromium.base.ThreadUtils;
import org.chromium.sync.signin.AccountManagerHelper;
-import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
- * Helper class for working with access tokens from native code.
- * <p/>
- * This class forwards calls to request or invalidate access tokens made by native code to
- * AccountManagerHelper and forwards callbacks to native code.
- * <p/>
+ * Temporary wrapper class until all callers have moved to use {@link OAuth2TokenService}.
+ * TODO(nyquist) Remove this class.
*/
public final class AndroidProfileOAuth2TokenServiceHelper {
- private static final String TAG = "AndroidProfileOAuth2TokenServiceHelper";
-
- private static final String OAUTH2_SCOPE_PREFIX = "oauth2:";
-
- private AndroidProfileOAuth2TokenServiceHelper() {
- }
-
- private static Account getAccountOrNullFromUsername(Context context, String username) {
- if (username == null) {
- Log.e(TAG, "Username is null");
- return null;
- }
-
- AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
- Account account = accountManagerHelper.getAccountFromName(username);
- if (account == null) {
- Log.e(TAG, "Account not found for provided username.");
- return null;
- }
- return account;
- }
-
- /**
- * Called by native to list the accounts with OAuth2 refresh tokens.
- */
- @CalledByNative
- public static String[] getAccounts(Context context) {
- AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
- java.util.List<String> accountNames = accountManagerHelper.getGoogleAccountNames();
- return accountNames.toArray(new String[accountNames.size()]);
- }
-
- /**
- * Called by native to retrieve OAuth2 tokens.
- *
- * @param username The native username (full address).
- * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
- * @param nativeCallback The pointer to the native callback that should be run upon completion.
- */
- @CalledByNative
- public static void getOAuth2AuthToken(
- Context context, String username, String scope, final int nativeCallback) {
- Account account = getAccountOrNullFromUsername(context, username);
- if (account == null) {
- nativeOAuth2TokenFetched(null, false, nativeCallback);
- return;
- }
- String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
-
- AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
- accountManagerHelper.getAuthTokenFromForeground(
- null, account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallback() {
- @Override
- public void tokenAvailable(String token) {
- nativeOAuth2TokenFetched(
- token, token != null, nativeCallback);
- }
- });
- }
+ private AndroidProfileOAuth2TokenServiceHelper() {}
/**
- * Call this method to retrieve an OAuth2 access token for the given account and scope.
- *
- * @param activity the current activity. May be null.
- * @param account the account to get the access token for.
- * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
- * @param callback called on successful and unsuccessful fetching of auth token.
+ * Use {@link OAuth2TokenService#getOAuth2AccessToken} instead.
*/
+ @Deprecated
public static void getOAuth2AccessToken(Context context, @Nullable Activity activity,
- Account account, String scope,
- AccountManagerHelper.GetAuthTokenCallback callback) {
- String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
- AccountManagerHelper.get(context).getAuthTokenFromForeground(
- activity, account, oauth2Scope, callback);
+ Account account, String scope, AccountManagerHelper.GetAuthTokenCallback callback) {
+ OAuth2TokenService.getOAuth2AccessToken(context, activity, account, scope, callback);
}
/**
- * Call this method to retrieve an OAuth2 access token for the given account and scope. This
- * method times out after the specified timeout, and will return null if that happens.
- *
- * Given that this is a blocking method call, this should never be called from the UI thread.
- *
- * @param activity the current activity. May be null.
- * @param account the account to get the access token for.
- * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
- * @param timeout the timeout.
- * @param unit the unit for |timeout|.
+ * Use {@link OAuth2TokenService#invalidateOAuth2AuthToken} instead.
*/
- public static String getOAuth2AccessTokenWithTimeout(
- Context context, @Nullable Activity activity, Account account, String scope,
- long timeout, TimeUnit unit) {
- assert !ThreadUtils.runningOnUiThread();
- final AtomicReference<String> result = new AtomicReference<String>();
- final Semaphore semaphore = new Semaphore(0);
- getOAuth2AccessToken(
- context, activity, account, scope,
- new AccountManagerHelper.GetAuthTokenCallback() {
- @Override
- public void tokenAvailable(String token) {
- result.set(token);
- semaphore.release();
- }
- });
- try {
- if (semaphore.tryAcquire(timeout, unit)) {
- return result.get();
- } else {
- Log.d(TAG, "Failed to retrieve auth token within timeout (" +
- timeout + " + " + unit.name() + ")");
- return null;
- }
- } catch (InterruptedException e) {
- Log.w(TAG, "Got interrupted while waiting for auth token");
- return null;
- }
+ @Deprecated
+ public static void invalidateOAuth2AuthToken(Context context, String accessToken) {
+ OAuth2TokenService.invalidateOAuth2AuthToken(context, accessToken);
}
/**
- * Called by native to check wether the account has an OAuth2 refresh token.
+ * Use {@link OAuth2TokenService#getOAuth2AccessTokenWithTimeout} instead.
*/
- @CalledByNative
- public static boolean hasOAuth2RefreshToken(Context context, String accountName) {
- return AccountManagerHelper.get(context).hasAccountForName(accountName);
- }
-
- /**
- * Called by native to invalidate an OAuth2 token.
- */
- @CalledByNative
- public static void invalidateOAuth2AuthToken(Context context, String accessToken) {
- if (accessToken != null) {
- AccountManagerHelper.get(context).invalidateAuthToken(accessToken);
- }
+ @Deprecated
+ public static String getOAuth2AccessTokenWithTimeout(Context context,
+ @Nullable Activity activity, Account account, String scope,
+ long timeout, TimeUnit unit) {
+ return OAuth2TokenService.getOAuth2AccessTokenWithTimeout(
+ context, activity, account, scope, timeout, unit);
}
-
- private static native void nativeOAuth2TokenFetched(
- String authToken, boolean result, int nativeCallback);
-
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java
new file mode 100644
index 0000000..6f50e49
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java
@@ -0,0 +1,276 @@
+// Copyright 2013 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.chrome.browser.signin;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.ObserverList;
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.sync.signin.AccountManagerHelper;
+import org.chromium.sync.signin.ChromeSigninController;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Nullable;
+
+/**
+ * Java instance for the native OAuth2TokenService.
+ * <p/>
+ * This class forwards calls to request or invalidate access tokens made by native code to
+ * AccountManagerHelper and forwards callbacks to native code.
+ * <p/>
+ */
+public final class OAuth2TokenService {
+
+ private static final String TAG = "OAuth2TokenService";
+
+ public interface OAuth2TokenServiceObserver {
+ void onRefreshTokenAvailable(Account account);
+ void onRefreshTokenRevoked(Account account);
+ void onRefreshTokensLoaded();
+ }
+
+ private static final String OAUTH2_SCOPE_PREFIX = "oauth2:";
+
+ private final int mNativeProfileOAuth2TokenService;
+ private final ObserverList<OAuth2TokenServiceObserver> mObservers;
+
+ private OAuth2TokenService(int nativeOAuth2Service) {
+ mNativeProfileOAuth2TokenService = nativeOAuth2Service;
+ mObservers = new ObserverList<OAuth2TokenServiceObserver>();
+ }
+
+ public static OAuth2TokenService getForProfile(Profile profile) {
+ ThreadUtils.assertOnUiThread();
+ return (OAuth2TokenService) nativeGetForProfile(profile);
+ }
+
+ @CalledByNative
+ private static OAuth2TokenService create(int nativeOAuth2Service) {
+ ThreadUtils.assertOnUiThread();
+ return new OAuth2TokenService(nativeOAuth2Service);
+ }
+
+ public void addObserver(OAuth2TokenServiceObserver observer) {
+ ThreadUtils.assertOnUiThread();
+ mObservers.addObserver(observer);
+ }
+
+ public void removeObserver(OAuth2TokenServiceObserver observer) {
+ ThreadUtils.assertOnUiThread();
+ mObservers.removeObserver(observer);
+ }
+
+ private static Account getAccountOrNullFromUsername(Context context, String username) {
+ if (username == null) {
+ Log.e(TAG, "Username is null");
+ return null;
+ }
+
+ AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
+ Account account = accountManagerHelper.getAccountFromName(username);
+ if (account == null) {
+ Log.e(TAG, "Account not found for provided username.");
+ return null;
+ }
+ return account;
+ }
+
+ /**
+ * Called by native to list the accounts with OAuth2 refresh tokens.
+ */
+ @CalledByNative
+ public static String[] getAccounts(Context context) {
+ AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
+ java.util.List<String> accountNames = accountManagerHelper.getGoogleAccountNames();
+ return accountNames.toArray(new String[accountNames.size()]);
+ }
+
+ /**
+ * Called by native to retrieve OAuth2 tokens.
+ *
+ * @param username The native username (full address).
+ * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
+ * @param nativeCallback The pointer to the native callback that should be run upon completion.
+ */
+ @CalledByNative
+ public static void getOAuth2AuthToken(
+ Context context, String username, String scope, final int nativeCallback) {
+ Account account = getAccountOrNullFromUsername(context, username);
+ if (account == null) {
+ nativeOAuth2TokenFetched(null, false, nativeCallback);
+ return;
+ }
+ String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
+
+ AccountManagerHelper accountManagerHelper = AccountManagerHelper.get(context);
+ accountManagerHelper.getAuthTokenFromForeground(
+ null, account, oauth2Scope, new AccountManagerHelper.GetAuthTokenCallback() {
+ @Override
+ public void tokenAvailable(String token) {
+ nativeOAuth2TokenFetched(
+ token, token != null, nativeCallback);
+ }
+ });
+ }
+
+ /**
+ * Call this method to retrieve an OAuth2 access token for the given account and scope.
+ *
+ * @param activity the current activity. May be null.
+ * @param account the account to get the access token for.
+ * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
+ * @param callback called on successful and unsuccessful fetching of auth token.
+ */
+ public static void getOAuth2AccessToken(Context context, @Nullable Activity activity,
+ Account account, String scope,
+ AccountManagerHelper.GetAuthTokenCallback callback) {
+ String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
+ AccountManagerHelper.get(context).getAuthTokenFromForeground(
+ activity, account, oauth2Scope, callback);
+ }
+
+ /**
+ * Call this method to retrieve an OAuth2 access token for the given account and scope. This
+ * method times out after the specified timeout, and will return null if that happens.
+ *
+ * Given that this is a blocking method call, this should never be called from the UI thread.
+ *
+ * @param activity the current activity. May be null.
+ * @param account the account to get the access token for.
+ * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
+ * @param timeout the timeout.
+ * @param unit the unit for |timeout|.
+ */
+ public static String getOAuth2AccessTokenWithTimeout(
+ Context context, @Nullable Activity activity, Account account, String scope,
+ long timeout, TimeUnit unit) {
+ assert !ThreadUtils.runningOnUiThread();
+ final AtomicReference<String> result = new AtomicReference<String>();
+ final Semaphore semaphore = new Semaphore(0);
+ getOAuth2AccessToken(
+ context, activity, account, scope,
+ new AccountManagerHelper.GetAuthTokenCallback() {
+ @Override
+ public void tokenAvailable(String token) {
+ result.set(token);
+ semaphore.release();
+ }
+ });
+ try {
+ if (semaphore.tryAcquire(timeout, unit)) {
+ return result.get();
+ } else {
+ Log.d(TAG, "Failed to retrieve auth token within timeout (" +
+ timeout + " + " + unit.name() + ")");
+ return null;
+ }
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Got interrupted while waiting for auth token");
+ return null;
+ }
+ }
+
+ /**
+ * Called by native to check wether the account has an OAuth2 refresh token.
+ */
+ @CalledByNative
+ public static boolean hasOAuth2RefreshToken(Context context, String accountName) {
+ return AccountManagerHelper.get(context).hasAccountForName(accountName);
+ }
+
+ /**
+ * Called by native to invalidate an OAuth2 token.
+ */
+ @CalledByNative
+ public static void invalidateOAuth2AuthToken(Context context, String accessToken) {
+ if (accessToken != null) {
+ AccountManagerHelper.get(context).invalidateAuthToken(accessToken);
+ }
+ }
+
+ public void validateAccounts(Context context) {
+ ThreadUtils.assertOnUiThread();
+ String currentlySignedInAccount =
+ ChromeSigninController.get(context).getSignedInAccountName();
+ String[] accounts = getAccounts(context);
+ nativeValidateAccounts(
+ mNativeProfileOAuth2TokenService, accounts, currentlySignedInAccount);
+ }
+
+ /**
+ * Triggers a notification to all observers of the native and Java instance of the
+ * OAuth2TokenService that a refresh token is now available. This may cause observers to retry
+ * operations that require authentication.
+ */
+ public void fireRefreshTokenAvailable(Account account) {
+ ThreadUtils.assertOnUiThread();
+ assert account != null;
+ nativeFireRefreshTokenAvailableFromJava(mNativeProfileOAuth2TokenService, account.name);
+ }
+
+ @CalledByNative
+ public void notifyRefreshTokenAvailable(String accountName) {
+ assert accountName != null;
+ Account account = AccountManagerHelper.createAccountFromName(accountName);
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokenAvailable(account);
+ }
+ }
+
+ /**
+ * Triggers a notification to all observers of the native and Java instance of the
+ * OAuth2TokenService that a refresh token is now revoked.
+ */
+ public void fireRefreshTokenRevoked(Account account) {
+ ThreadUtils.assertOnUiThread();
+ assert account != null;
+ nativeFireRefreshTokenRevokedFromJava(mNativeProfileOAuth2TokenService, account.name);
+ }
+
+ @CalledByNative
+ public void notifyRefreshTokenRevoked(String accountName) {
+ assert accountName != null;
+ Account account = AccountManagerHelper.createAccountFromName(accountName);
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokenRevoked(account);
+ }
+ }
+
+ /**
+ * Triggers a notification to all observers of the native and Java instance of the
+ * OAuth2TokenService that all refresh tokens now have been loaded.
+ */
+ public void fireRefreshTokensLoaded() {
+ ThreadUtils.assertOnUiThread();
+ nativeFireRefreshTokensLoadedFromJava(mNativeProfileOAuth2TokenService);
+ }
+
+ @CalledByNative
+ public void notifyRefreshTokensLoaded() {
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokensLoaded();
+ }
+ }
+
+ private static native Object nativeGetForProfile(Profile profile);
+ private static native void nativeOAuth2TokenFetched(
+ String authToken, boolean result, int nativeCallback);
+ private native void nativeValidateAccounts(int nativeAndroidProfileOAuth2TokenService,
+ String[] accounts, String currentlySignedInAccount);
+ private native void nativeFireRefreshTokenAvailableFromJava(
+ int nativeAndroidProfileOAuth2TokenService, String accountName);
+ private native void nativeFireRefreshTokenRevokedFromJava(
+ int nativeAndroidProfileOAuth2TokenService, String accountName);
+ private native void nativeFireRefreshTokensLoadedFromJava(
+ int nativeAndroidProfileOAuth2TokenService);
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
new file mode 100644
index 0000000..c2d2334
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
@@ -0,0 +1,275 @@
+// Copyright 2013 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.chrome.browser.signin;
+
+import android.accounts.Account;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
+import org.chromium.sync.signin.AccountManagerHelper;
+import org.chromium.sync.signin.ChromeSigninController;
+import org.chromium.sync.test.util.AccountHolder;
+import org.chromium.sync.test.util.MockAccountManager;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Integration test for the OAuth2TokenService.
+ *
+ * These tests initialize the native part of the service.
+ */
+public class OAuth2TokenServiceIntegrationTest extends ChromiumTestShellTestBase {
+
+ private static final Account TEST_ACCOUNT1 =
+ AccountManagerHelper.createAccountFromName("foo@gmail.com");
+ private static final Account TEST_ACCOUNT2 =
+ AccountManagerHelper.createAccountFromName("bar@gmail.com");
+ private static final AccountHolder TEST_ACCOUNT_HOLDER_1 =
+ AccountHolder.create().account(TEST_ACCOUNT1).build();
+ private static final AccountHolder TEST_ACCOUNT_HOLDER_2 =
+ AccountHolder.create().account(TEST_ACCOUNT2).build();
+
+ private AdvancedMockContext mContext;
+ private OAuth2TokenService mOAuth2TokenService;
+ private MockAccountManager mAccountManager;
+ private TestObserver mObserver;
+ private ChromeSigninController mChromeSigninController;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearAppData();
+ startChromeBrowserProcessSync(getInstrumentation().getTargetContext());
+
+ // Set up AccountManager.
+ mContext = new AdvancedMockContext(getInstrumentation().getTargetContext());
+ mAccountManager = new MockAccountManager(mContext, getInstrumentation().getContext());
+ AccountManagerHelper.overrideAccountManagerHelperForTests(mContext, mAccountManager);
+ mChromeSigninController = ChromeSigninController.get(mContext);
+
+ // Get a reference to the service.
+ mOAuth2TokenService = getOAuth2TokenServiceOnUiThread();
+
+ // Set up observer.
+ mObserver = new TestObserver();
+ addObserver(mObserver);
+ }
+
+ /**
+ * The {@link OAuth2TokenService} and the {@link Profile} can only be accessed from the UI
+ * thread, so this helper method is a convenience method to retrieve it.
+ *
+ * @return the OAuth2TokenService.
+ */
+ private static OAuth2TokenService getOAuth2TokenServiceOnUiThread() {
+ final AtomicReference<OAuth2TokenService> service =
+ new AtomicReference<OAuth2TokenService>();
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+ @Override
+ public void run() {
+ service.set(OAuth2TokenService.getForProfile(Profile.getLastUsedProfile()));
+ }
+ });
+ return service.get();
+ }
+
+ private void addObserver(final TestObserver observer) {
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+ @Override
+ public void run() {
+ mOAuth2TokenService.addObserver(observer);
+ }
+ });
+ }
+
+ @MediumTest
+ @UiThreadTest
+ @Feature({"Sync"})
+ public void testFireRefreshTokenAvailableNotifiesJavaObservers() {
+ // Adding an observer should not lead to a callback.
+ assertEquals(0, mObserver.getAvailableCallCount());
+
+ // An observer should be called with the correct account.
+ mOAuth2TokenService.fireRefreshTokenAvailable(TEST_ACCOUNT1);
+ assertEquals(1, mObserver.getAvailableCallCount());
+ assertEquals(TEST_ACCOUNT1, mObserver.getLastAccount());
+
+ // When mOAuth2TokenService, an observer should not be called.
+ mOAuth2TokenService.removeObserver(mObserver);
+ mOAuth2TokenService.fireRefreshTokenAvailable(TEST_ACCOUNT1);
+ assertEquals(1, mObserver.getAvailableCallCount());
+
+ // No other observer interface method should ever have been called.
+ assertEquals(0, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ @Feature({"Sync"})
+ public void testFireRefreshTokenRevokedNotifiesJavaObservers() {
+ // Adding an observer should not lead to a callback.
+ assertEquals(0, mObserver.getRevokedCallCount());
+
+ // An observer should be called with the correct account.
+ mOAuth2TokenService.fireRefreshTokenRevoked(TEST_ACCOUNT1);
+ assertEquals(1, mObserver.getRevokedCallCount());
+ assertEquals(TEST_ACCOUNT1, mObserver.getLastAccount());
+
+ // When removed, an observer should not be called.
+ mOAuth2TokenService.removeObserver(mObserver);
+ mOAuth2TokenService.fireRefreshTokenRevoked(TEST_ACCOUNT1);
+ assertEquals(1, mObserver.getRevokedCallCount());
+
+ // No other observer interface method should ever have been called.
+ assertEquals(0, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ @Feature({"Sync"})
+ public void testFireRefreshTokensLoadedNotifiesJavaObservers() {
+ // Adding an observer should not lead to a callback.
+ assertEquals(0, mObserver.getLoadedCallCount());
+
+ // An observer should be called with the correct account.
+ mOAuth2TokenService.fireRefreshTokensLoaded();
+ assertEquals(1, mObserver.getLoadedCallCount());
+
+ // When removed, an observer should not be called.
+ mOAuth2TokenService.removeObserver(mObserver);
+ mOAuth2TokenService.fireRefreshTokensLoaded();
+ assertEquals(1, mObserver.getLoadedCallCount());
+
+ // No other observer interface method should ever have been called.
+ assertEquals(0, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getRevokedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ public void testValidateAccountsNoAccountsRegisteredAndNoSignedInUser() {
+ // Run test.
+ mOAuth2TokenService.validateAccounts(mContext);
+
+ // Ensure no calls have been made to the observer.
+ assertEquals(0, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ public void testValidateAccountsOneAccountsRegisteredAndNoSignedInUser() {
+ // Add account.
+ mAccountManager.addAccountHolderExplicitly(TEST_ACCOUNT_HOLDER_1);
+
+ // Run test.
+ mOAuth2TokenService.validateAccounts(mContext);
+
+ // Ensure no calls have been made to the observer.
+ assertEquals(0, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ public void testValidateAccountsOneAccountsRegisteredSignedIn() {
+ // Add account.
+ mAccountManager.addAccountHolderExplicitly(TEST_ACCOUNT_HOLDER_1);
+
+ // Mark user as signed in.
+ mChromeSigninController.setSignedInAccountName(TEST_ACCOUNT1.name);
+
+ // Run test.
+ mOAuth2TokenService.validateAccounts(mContext);
+
+ // Ensure no calls have been made to the observer.
+ assertEquals(1, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ public void testValidateAccountsTwoAccountsRegisteredAndOneSignedIn() {
+ // Add accounts.
+ mAccountManager.addAccountHolderExplicitly(TEST_ACCOUNT_HOLDER_1);
+ mAccountManager.addAccountHolderExplicitly(TEST_ACCOUNT_HOLDER_2);
+
+ // Mark user as signed in.
+ mChromeSigninController.setSignedInAccountName(TEST_ACCOUNT1.name);
+
+ // Run test.
+ mOAuth2TokenService.validateAccounts(mContext);
+
+ // Ensure no calls have been made to the observer.
+ assertEquals(1, mObserver.getAvailableCallCount());
+ assertEquals(0, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ @MediumTest
+ @UiThreadTest
+ public void testValidateAccountsNoAccountsRegisteredButSignedIn() {
+ // Mark user as signed in without setting up the account.
+ mChromeSigninController.setSignedInAccountName(TEST_ACCOUNT1.name);
+
+ // Run test.
+ mOAuth2TokenService.validateAccounts(mContext);
+
+ // Ensure no calls have been made to the observer.
+ assertEquals(0, mObserver.getAvailableCallCount());
+ assertEquals(1, mObserver.getRevokedCallCount());
+ assertEquals(0, mObserver.getLoadedCallCount());
+ }
+
+ private static class TestObserver implements OAuth2TokenService.OAuth2TokenServiceObserver {
+ private int mAvailableCallCount;
+ private int mRevokedCallCount;
+ private int mLoadedCallCount;
+ private Account mLastAccount;
+
+ @Override
+ public void onRefreshTokenAvailable(Account account) {
+ mAvailableCallCount++;
+ mLastAccount = account;
+ }
+
+ @Override
+ public void onRefreshTokenRevoked(Account account) {
+ mRevokedCallCount++;
+ mLastAccount = account;
+ }
+
+ @Override
+ public void onRefreshTokensLoaded() {
+ mLoadedCallCount++;
+ }
+
+ public int getAvailableCallCount() {
+ return mAvailableCallCount;
+ }
+
+ public int getRevokedCallCount() {
+ return mRevokedCallCount;
+ }
+
+ public int getLoadedCallCount() {
+ return mLoadedCallCount;
+ }
+
+ public Account getLastAccount() {
+ return mLastAccount;
+ }
+ }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
index ef9c5c9..78baa84 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
@@ -14,9 +14,10 @@ import org.chromium.sync.signin.AccountManagerHelper;
import org.chromium.sync.test.util.AccountHolder;
import org.chromium.sync.test.util.MockAccountManager;
+import java.util.Arrays;
import java.util.concurrent.TimeUnit;
-public class AndroidProfileOAuth2TokenServiceHelperTest extends InstrumentationTestCase {
+public class OAuth2TokenServiceTest extends InstrumentationTestCase {
private AdvancedMockContext mContext;
private MockAccountManager mAccountManager;
@@ -33,6 +34,43 @@ public class AndroidProfileOAuth2TokenServiceHelperTest extends InstrumentationT
@SmallTest
@Feature({"Sync"})
+ public void testGetAccountsNoAccountsRegistered() {
+ String[] accounts = OAuth2TokenService.getAccounts(mContext);
+ assertEquals("There should be no accounts registered", 0, accounts.length);
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testGetAccountsOneAccountRegistered() {
+ Account account1 = AccountManagerHelper.createAccountFromName("foo@gmail.com");
+ AccountHolder accountHolder1 = AccountHolder.create().account(account1).build();
+ mAccountManager.addAccountHolderExplicitly(accountHolder1);
+
+ String[] accounts = OAuth2TokenService.getAccounts(mContext);
+ assertEquals("There should be one registered account", 1, accounts.length);
+ assertEquals("The account should be " + account1, account1.name, accounts[0]);
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
+ public void testGetAccountsTwoAccountsRegistered() {
+ Account account1 = AccountManagerHelper.createAccountFromName("foo@gmail.com");
+ AccountHolder accountHolder1 = AccountHolder.create().account(account1).build();
+ mAccountManager.addAccountHolderExplicitly(accountHolder1);
+ Account account2 = AccountManagerHelper.createAccountFromName("bar@gmail.com");
+ AccountHolder accountHolder2 = AccountHolder.create().account(account2).build();
+ mAccountManager.addAccountHolderExplicitly(accountHolder2);
+
+ String[] accounts = OAuth2TokenService.getAccounts(mContext);
+ assertEquals("There should be one registered account", 2, accounts.length);
+ assertTrue("The list should contain " + account1,
+ Arrays.asList(accounts).contains(account1.name));
+ assertTrue("The list should contain " + account2,
+ Arrays.asList(accounts).contains(account2.name));
+ }
+
+ @SmallTest
+ @Feature({"Sync"})
public void testGetOAuth2AccessTokenWithTimeoutOnSuccess() {
String authToken = "someToken";
// Auth token should be successfully received.
@@ -61,7 +99,7 @@ public class AndroidProfileOAuth2TokenServiceHelperTest extends InstrumentationT
mAccountManager.addAccountHolderExplicitly(accountHolder);
String accessToken =
- AndroidProfileOAuth2TokenServiceHelper.getOAuth2AccessTokenWithTimeout(
+ OAuth2TokenService.getOAuth2AccessTokenWithTimeout(
mContext, null, account, scope, 5, TimeUnit.SECONDS);
assertEquals(expectedToken, accessToken);
}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index f5fa2fa..b8ccc47 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -6,7 +6,6 @@ package org.chromium.chrome.browser.sync;
import android.accounts.Account;
import android.app.Activity;
-import android.content.Context;
import android.util.Log;
import org.chromium.base.ThreadUtils;
@@ -18,14 +17,12 @@ import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
import org.chromium.chrome.testshell.ChromiumTestShellActivity;
import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
import org.chromium.chrome.testshell.sync.SyncController;
-import org.chromium.content.browser.BrowserStartupController;
import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.JavaScriptUtils;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
-import org.chromium.content.common.CommandLine;
import org.chromium.sync.notifier.SyncStatusHelper;
import org.chromium.sync.signin.AccountManagerHelper;
import org.chromium.sync.signin.ChromeSigninController;
@@ -75,17 +72,6 @@ public class SyncTest extends ChromiumTestShellTestBase {
SyncTestUtil.verifySyncServerIsRunning();
}
- private static void startChromeBrowserProcessSync(final Context targetContext) {
- ThreadUtils.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- CommandLine.initFromFile("/data/local/tmp/chromium-testshell-command-line");
- BrowserStartupController.get(targetContext).startBrowserProcessesSync(
- BrowserStartupController.MAX_RENDERERS_LIMIT);
- }
- });
- }
-
@HostDrivenTest
public void testGetAboutSyncInfoYieldsValidData() throws Throwable {
setupTestAccountAndSignInToSync(FOREIGN_SESSION_TEST_MACHINE_ID);
diff --git a/chrome/android/testshell/java/AndroidManifest.xml b/chrome/android/testshell/java/AndroidManifest.xml
index 71f6b00..1628bc3 100644
--- a/chrome/android/testshell/java/AndroidManifest.xml
+++ b/chrome/android/testshell/java/AndroidManifest.xml
@@ -180,5 +180,12 @@
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
+
+ <!-- Broadcast receiver that will be notified of account changes. -->
+ <receiver android:name="org.chromium.chrome.testshell.signin.AccountsChangedReceiver">
+ <intent-filter>
+ <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/signin/AccountsChangedReceiver.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/signin/AccountsChangedReceiver.java
new file mode 100644
index 0000000..dc97f30
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/signin/AccountsChangedReceiver.java
@@ -0,0 +1,59 @@
+// Copyright 2013 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.chrome.testshell.signin;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.OAuth2TokenService;
+import org.chromium.content.browser.BrowserStartupController;
+import org.chromium.sync.signin.ChromeSigninController;
+
+/**
+ * A BroadcastReceiver for acting on changes to Android accounts.
+ */
+public class AccountsChangedReceiver extends BroadcastReceiver {
+ private static final String TAG = "AccountsChangedReceiver";
+
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(intent.getAction())) {
+ final Account signedInUser =
+ ChromeSigninController.get(context).getSignedInUser();
+ if (signedInUser != null) {
+ BrowserStartupController.StartupCallback callback =
+ new BrowserStartupController.StartupCallback() {
+ @Override
+ public void onSuccess(boolean alreadyStarted) {
+ OAuth2TokenService.getForProfile(Profile.getLastUsedProfile())
+ .validateAccounts(context);
+ }
+
+ @Override
+ public void onFailure() {
+ Log.w(TAG, "Failed to start browser process.");
+ }
+ };
+ startBrowserProcessOnUiThread(context, callback);
+ }
+ }
+ }
+
+ private static void startBrowserProcessOnUiThread(final Context context,
+ final BrowserStartupController.StartupCallback callback) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ BrowserStartupController.get(context).startBrowserProcessesAsync(callback);
+ }
+ });
+ }
+}
diff --git a/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java b/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java
index c982a72..4ad0645 100644
--- a/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java
+++ b/chrome/android/testshell/javatests/src/org/chromium/chrome/testshell/ChromiumTestShellTestBase.java
@@ -5,14 +5,18 @@
package org.chromium.chrome.testshell;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2;
import android.text.TextUtils;
+import org.chromium.base.ThreadUtils;
import org.chromium.chrome.test.util.ApplicationData;
+import org.chromium.content.browser.BrowserStartupController;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.common.CommandLine;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -28,6 +32,17 @@ public class ChromiumTestShellTestBase extends
super(ChromiumTestShellActivity.class);
}
+ protected static void startChromeBrowserProcessSync(final Context targetContext) {
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+ @Override
+ public void run() {
+ CommandLine.initFromFile("/data/local/tmp/chromium-testshell-command-line");
+ BrowserStartupController.get(targetContext).startBrowserProcessesSync(
+ BrowserStartupController.MAX_RENDERERS_LIMIT);
+ }
+ });
+ }
+
/**
* Starts the ChromiumTestShell activity and loads the given URL.
*/
diff --git a/chrome/browser/profiles/profile_android.cc b/chrome/browser/profiles/profile_android.cc
index 71df381..5f0eda1 100644
--- a/chrome/browser/profiles/profile_android.cc
+++ b/chrome/browser/profiles/profile_android.cc
@@ -6,6 +6,7 @@
#include "base/android/jni_android.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "jni/Profile_jni.h"
using base::android::AttachCurrentThread;
@@ -45,6 +46,28 @@ bool ProfileAndroid::RegisterProfileAndroid(JNIEnv* env) {
return RegisterNativesImpl(env);
}
+// static
+jobject ProfileAndroid::GetLastUsedProfile(JNIEnv* env, jclass clazz) {
+ Profile* profile = ProfileManager::GetLastUsedProfile();
+ if (profile == NULL) {
+ NOTREACHED() << "Profile not found.";
+ return NULL;
+ }
+
+ ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile);
+ if (profile_android == NULL) {
+ NOTREACHED() << "ProfileAndroid not found.";
+ return NULL;
+ }
+
+ return profile_android->obj_.obj();
+}
+
+// static
+jobject GetLastUsedProfile(JNIEnv* env, jclass clazz) {
+ return ProfileAndroid::GetLastUsedProfile(env, clazz);
+}
+
ProfileAndroid::ProfileAndroid(Profile* profile)
: profile_(profile) {
JNIEnv* env = AttachCurrentThread();
diff --git a/chrome/browser/profiles/profile_android.h b/chrome/browser/profiles/profile_android.h
index 780dde0..0017b5b 100644
--- a/chrome/browser/profiles/profile_android.h
+++ b/chrome/browser/profiles/profile_android.h
@@ -21,6 +21,8 @@ class ProfileAndroid : public base::SupportsUserData::Data {
static Profile* FromProfileAndroid(jobject obj);
static bool RegisterProfileAndroid(JNIEnv* env);
+ static jobject GetLastUsedProfile(JNIEnv* env, jclass clazz);
+
explicit ProfileAndroid(Profile* profile);
virtual ~ProfileAndroid();
diff --git a/chrome/browser/signin/DEPS b/chrome/browser/signin/DEPS
index 2b4bc3803..9ada978 100644
--- a/chrome/browser/signin/DEPS
+++ b/chrome/browser/signin/DEPS
@@ -12,6 +12,7 @@ include_rules = [
"!chrome/browser/policy/cloud/user_policy_signin_service.h",
"!chrome/browser/policy/cloud/user_policy_signin_service_factory.h",
"!chrome/browser/profiles/profile.h",
+ "!chrome/browser/profiles/profile_android.h",
"!chrome/browser/profiles/profile_info_cache.h",
"!chrome/browser/profiles/profile_io_data.h",
"!chrome/browser/profiles/profile_manager.h",
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.cc b/chrome/browser/signin/android_profile_oauth2_token_service.cc
index 6883533..60d378d 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.cc
@@ -9,11 +9,13 @@
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/logging.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service_android.h"
#include "content/public/browser/browser_thread.h"
-#include "jni/AndroidProfileOAuth2TokenServiceHelper_jni.h"
+#include "jni/OAuth2TokenService_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
@@ -49,9 +51,28 @@ typedef base::Callback<void(
} // namespace
AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
+ JNIEnv* env = AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> local_java_ref =
+ Java_OAuth2TokenService_create(env, reinterpret_cast<int>(this));
+ java_ref_.Reset(env, local_java_ref.obj());
}
-AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {
+AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {}
+
+// static
+jobject AndroidProfileOAuth2TokenService::GetForProfile(
+ JNIEnv* env, jclass clazz, jobject j_profile_android) {
+ Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android);
+ AndroidProfileOAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+ return service->java_ref_.obj();
+}
+
+static jobject GetForProfile(JNIEnv* env,
+ jclass clazz,
+ jobject j_profile_android) {
+ return AndroidProfileOAuth2TokenService::GetForProfile(
+ env, clazz, j_profile_android);
}
bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable(
@@ -60,7 +81,7 @@ bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable(
ScopedJavaLocalRef<jstring> j_account_id =
ConvertUTF8ToJavaString(env, account_id);
jboolean refresh_token_is_available =
- Java_AndroidProfileOAuth2TokenServiceHelper_hasOAuth2RefreshToken(
+ Java_OAuth2TokenService_hasOAuth2RefreshToken(
env, base::android::GetApplicationContext(),
j_account_id.obj());
return refresh_token_is_available != JNI_FALSE;
@@ -70,7 +91,7 @@ std::vector<std::string> AndroidProfileOAuth2TokenService::GetAccounts() {
std::vector<std::string> accounts;
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_accounts =
- Java_AndroidProfileOAuth2TokenServiceHelper_getAccounts(
+ Java_OAuth2TokenService_getAccounts(
env, base::android::GetApplicationContext());
// TODO(fgorski): We may decide to filter out some of the accounts.
base::android::AppendJavaStringArrayToStringVector(env,
@@ -104,7 +125,7 @@ void AndroidProfileOAuth2TokenService::FetchOAuth2Token(
request->AsWeakPtr())));
// Call into Java to get a new token.
- Java_AndroidProfileOAuth2TokenServiceHelper_getOAuth2AuthToken(
+ Java_OAuth2TokenService_getOAuth2AuthToken(
env, base::android::GetApplicationContext(),
j_username.obj(),
j_scope.obj(),
@@ -124,11 +145,91 @@ void AndroidProfileOAuth2TokenService::InvalidateOAuth2Token(
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> j_access_token =
ConvertUTF8ToJavaString(env, access_token);
- Java_AndroidProfileOAuth2TokenServiceHelper_invalidateOAuth2AuthToken(
+ Java_OAuth2TokenService_invalidateOAuth2AuthToken(
env, base::android::GetApplicationContext(),
j_access_token.obj());
}
+void AndroidProfileOAuth2TokenService::ValidateAccounts(JNIEnv* env,
+ jobject obj,
+ jobjectArray accounts,
+ jstring j_current_acc) {
+ std::vector<std::string> account_ids;
+ base::android::AppendJavaStringArrayToStringVector(env,
+ accounts,
+ &account_ids);
+ std::string signed_in_account = ConvertJavaStringToUTF8(env, j_current_acc);
+
+ if (signed_in_account.empty())
+ return;
+
+ if (std::find(account_ids.begin(),
+ account_ids.end(),
+ signed_in_account) != account_ids.end()) {
+ // Currently signed in account still exists among accounts on system.
+ FireRefreshTokenAvailable(signed_in_account);
+ } else {
+ // Currently signed in account does not any longer exist among accounts on
+ // system.
+ FireRefreshTokenRevoked(signed_in_account);
+ }
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailableFromJava(
+ JNIEnv* env,
+ jobject obj,
+ const jstring account_name) {
+ std::string account_id = ConvertJavaStringToUTF8(env, account_name);
+ AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(account_id);
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(
+ const std::string& account_id) {
+ // Notify native observers.
+ OAuth2TokenService::FireRefreshTokenAvailable(account_id);
+ // Notify Java observers.
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> account_name =
+ ConvertUTF8ToJavaString(env, account_id);
+ Java_OAuth2TokenService_notifyRefreshTokenAvailable(
+ env, java_ref_.obj(), account_name.obj());
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokenRevokedFromJava(
+ JNIEnv* env,
+ jobject obj,
+ const jstring account_name) {
+ std::string account_id = ConvertJavaStringToUTF8(env, account_name);
+ AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(account_id);
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(
+ const std::string& account_id) {
+ // Notify native observers.
+ OAuth2TokenService::FireRefreshTokenRevoked(account_id);
+ // Notify Java observers.
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> account_name =
+ ConvertUTF8ToJavaString(env, account_id);
+ Java_OAuth2TokenService_notifyRefreshTokenRevoked(
+ env, java_ref_.obj(), account_name.obj());
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokensLoadedFromJava(
+ JNIEnv* env,
+ jobject obj) {
+ AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded();
+}
+
+void AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded() {
+ // Notify native observers.
+ OAuth2TokenService::FireRefreshTokensLoaded();
+ // Notify Java observers.
+ JNIEnv* env = AttachCurrentThread();
+ Java_OAuth2TokenService_notifyRefreshTokensLoaded(
+ env, java_ref_.obj());
+}
+
// Called from Java when fetching of an OAuth2 token is finished. The
// |authToken| param is only valid when |result| is true.
void OAuth2TokenFetched(JNIEnv* env, jclass clazz,
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.h b/chrome/browser/signin/android_profile_oauth2_token_service.h
index 6c44377..1d6c054 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.h
@@ -28,16 +28,43 @@ class TokenService;
// request from other thread, please use ProfileOAuth2TokenServiceRequest.
class AndroidProfileOAuth2TokenService : public ProfileOAuth2TokenService {
public:
- virtual bool RefreshTokenIsAvailable(
- const std::string& account_id) OVERRIDE;
-
// Registers the AndroidProfileOAuth2TokenService's native methods through
// JNI.
static bool Register(JNIEnv* env);
+ // Creates a new instance of the AndroidProfileOAuth2TokenService.
+ static AndroidProfileOAuth2TokenService* Create();
+
+ // Returns a reference to the Java instance of this service.
+ static jobject GetForProfile(
+ JNIEnv* env, jclass clazz, jobject j_profile_android);
+
+ virtual bool RefreshTokenIsAvailable(
+ const std::string& account_id) OVERRIDE;
+
// Lists account IDs of all accounts with a refresh token.
virtual std::vector<std::string> GetAccounts() OVERRIDE;
+ void ValidateAccounts(JNIEnv* env,
+ jobject obj,
+ jobjectArray accounts,
+ jstring current_account);
+
+ // Triggers a notification to all observers of the OAuth2TokenService that a
+ // refresh token is now available. This may cause observers to retry
+ // operations that require authentication.
+ virtual void FireRefreshTokenAvailableFromJava(JNIEnv* env,
+ jobject obj,
+ const jstring account_name);
+ // Triggers a notification to all observers of the OAuth2TokenService that a
+ // refresh token is now available.
+ virtual void FireRefreshTokenRevokedFromJava(JNIEnv* env,
+ jobject obj,
+ const jstring account_name);
+ // Triggers a notification to all observers of the OAuth2TokenService that all
+ // refresh tokens have now been loaded.
+ virtual void FireRefreshTokensLoadedFromJava(JNIEnv* env, jobject obj);
+
protected:
friend class ProfileOAuth2TokenServiceFactory;
AndroidProfileOAuth2TokenService();
@@ -59,7 +86,17 @@ class AndroidProfileOAuth2TokenService : public ProfileOAuth2TokenService {
const ScopeSet& scopes,
const std::string& access_token) OVERRIDE;
+ // Called to notify observers when a refresh token is available.
+ virtual void FireRefreshTokenAvailable(
+ const std::string& account_id) OVERRIDE;
+ // Called to notify observers when a refresh token has been revoked.
+ virtual void FireRefreshTokenRevoked(const std::string& account_id) OVERRIDE;
+ // Called to notify observers when refresh tokans have been loaded.
+ virtual void FireRefreshTokensLoaded() OVERRIDE;
+
private:
+ base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+
DISALLOW_COPY_AND_ASSIGN(AndroidProfileOAuth2TokenService);
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 21caa33..0ad6c8d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3637,7 +3637,7 @@
'android/java/src/org/chromium/chrome/browser/ShortcutHelper.java',
'android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java',
'android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java',
- 'android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java',
+ 'android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java',
'android/java/src/org/chromium/chrome/browser/signin/SigninManager.java',
'android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java',
'android/java/src/org/chromium/chrome/browser/TabBase.java',
diff --git a/google_apis/gaia/oauth2_token_service.h b/google_apis/gaia/oauth2_token_service.h
index b8faecd..52ea3ad 100644
--- a/google_apis/gaia/oauth2_token_service.h
+++ b/google_apis/gaia/oauth2_token_service.h
@@ -223,9 +223,9 @@ class OAuth2TokenService : public base::NonThreadSafe {
void CancelRequestsForAccount(const std::string& account_id);
// Called by subclasses to notify observers.
- void FireRefreshTokenAvailable(const std::string& account_id);
- void FireRefreshTokenRevoked(const std::string& account_id);
- void FireRefreshTokensLoaded();
+ virtual void FireRefreshTokenAvailable(const std::string& account_id);
+ virtual void FireRefreshTokenRevoked(const std::string& account_id);
+ virtual void FireRefreshTokensLoaded();
// Creates a request implementation. Can be overriden by derived classes to
// provide additional control of token consumption. |consumer| will outlive