android_profile_oauth2_token_service.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/android_profile_oauth2_token_service.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/android/jni_android.h"
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/android/jni_array.h"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/android/jni_string.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/logging.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile_android.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_android.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "jni/OAuth2TokenService_jni.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing base::android::AttachCurrentThread;
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing base::android::ConvertJavaStringToUTF8;
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing base::android::ConvertUTF8ToJavaString;
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing base::android::ScopedJavaLocalRef;
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing content::BrowserThread;
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstd::string CombineScopes(const OAuth2TokenService::ScopeSet& scopes) {
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The Android AccountManager supports multiple scopes separated by a space:
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string scope;
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (OAuth2TokenService::ScopeSet::const_iterator it = scopes.begin();
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       it != scopes.end(); ++it) {
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!scope.empty())
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      scope += " ";
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    scope += *it;
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return scope;
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Callback from FetchOAuth2TokenWithUsername().
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Arguments:
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// - the error, or NONE if the token fetch was successful.
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// - the OAuth2 access token.
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// - the expiry time of the token (may be null, indicating that the expiry
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//   time is unknown.
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)typedef base::Callback<void(
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const GoogleServiceAuthError&, const std::string&, const base::Time&)>
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        FetchOAuth2TokenCallback;
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochAndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::android::ScopedJavaLocalRef<jobject> local_java_ref =
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      Java_OAuth2TokenService_create(env, reinterpret_cast<intptr_t>(this));
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  java_ref_.Reset(env, local_java_ref.obj());
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {}
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)jobject AndroidProfileOAuth2TokenService::GetForProfile(
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    JNIEnv* env, jclass clazz, jobject j_profile_android) {
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android);
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AndroidProfileOAuth2TokenService* service =
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(profile);
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return service->java_ref_.obj();
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static jobject GetForProfile(JNIEnv* env,
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             jclass clazz,
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             jobject j_profile_android) {
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return AndroidProfileOAuth2TokenService::GetForProfile(
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      env, clazz, j_profile_android);
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable(
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& account_id) const {
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jstring> j_account_id =
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ConvertUTF8ToJavaString(env, account_id);
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  jboolean refresh_token_is_available =
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      Java_OAuth2TokenService_hasOAuth2RefreshToken(
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          env, base::android::GetApplicationContext(),
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          j_account_id.obj());
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return refresh_token_is_available != JNI_FALSE;
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<std::string> AndroidProfileOAuth2TokenService::GetAccounts() {
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<std::string> accounts;
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  JNIEnv* env = AttachCurrentThread();
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jobjectArray> j_accounts =
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      Java_OAuth2TokenService_getAccounts(
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          env, base::android::GetApplicationContext());
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(fgorski): We may decide to filter out some of the accounts.
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::android::AppendJavaStringArrayToStringVector(env,
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     j_accounts.obj(),
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     &accounts);
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return accounts;
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustd::vector<std::string> AndroidProfileOAuth2TokenService::GetSystemAccounts() {
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<std::string> accounts;
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  JNIEnv* env = AttachCurrentThread();
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ScopedJavaLocalRef<jobjectArray> j_accounts =
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      Java_OAuth2TokenService_getSystemAccounts(
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          env, base::android::GetApplicationContext());
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::android::AppendJavaStringArrayToStringVector(env,
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                     j_accounts.obj(),
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                     &accounts);
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return accounts;
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AndroidProfileOAuth2TokenService::FetchOAuth2Token(
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    RequestImpl* request,
11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    net::URLRequestContextGetter* getter,
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& client_id,
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& client_secret,
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes) {
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(!account_id.empty());
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  JNIEnv* env = AttachCurrentThread();
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string scope = CombineScopes(scopes);
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScopedJavaLocalRef<jstring> j_username =
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ConvertUTF8ToJavaString(env, account_id);
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ScopedJavaLocalRef<jstring> j_scope =
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ConvertUTF8ToJavaString(env, scope);
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Allocate a copy of the request WeakPtr on the heap, because the object
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // needs to be passed through JNI as an int.
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // It will be passed back to OAuth2TokenFetched(), where it will be freed.
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      new FetchOAuth2TokenCallback(base::Bind(&RequestImpl::InformConsumer,
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                              request->AsWeakPtr())));
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Call into Java to get a new token.
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Java_OAuth2TokenService_getOAuth2AuthToken(
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      env, base::android::GetApplicationContext(),
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      j_username.obj(),
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      j_scope.obj(),
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      reinterpret_cast<intptr_t>(heap_callback.release()));
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)OAuth2AccessTokenFetcher*
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)AndroidProfileOAuth2TokenService::CreateAccessTokenFetcher(
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& account_id,
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::URLRequestContextGetter* getter,
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OAuth2AccessTokenConsumer* consumer) {
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTREACHED();
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return NULL;
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void AndroidProfileOAuth2TokenService::InvalidateOAuth2Token(
15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& client_id,
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ScopeSet& scopes,
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& access_token) {
15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  OAuth2TokenService::InvalidateOAuth2Token(account_id,
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            client_id,
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            scopes,
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            access_token);
16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedJavaLocalRef<jstring> j_access_token =
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ConvertUTF8ToJavaString(env, access_token);
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Java_OAuth2TokenService_invalidateOAuth2AuthToken(
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      env, base::android::GetApplicationContext(),
16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      j_access_token.obj());
17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
17168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AndroidProfileOAuth2TokenService::ValidateAccounts(
1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    JNIEnv* env,
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    jobject obj,
1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    jstring j_current_acc) {
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string signed_in_account = ConvertJavaStringToUTF8(env, j_current_acc);
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ValidateAccounts(signed_in_account);
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void AndroidProfileOAuth2TokenService::ValidateAccounts(
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& signed_in_account) {
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<std::string> prev_ids = GetAccounts();
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<std::string> curr_ids = GetSystemAccounts();
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<std::string> refreshed_ids;
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<std::string> revoked_ids;
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ValidateAccounts(
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      signed_in_account, prev_ids, curr_ids, refreshed_ids, revoked_ids)) {
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    curr_ids.clear();
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  JNIEnv* env = AttachCurrentThread();
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ScopedJavaLocalRef<jobjectArray> java_accounts(
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::android::ToJavaArrayOfStrings(env, curr_ids));
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  Java_OAuth2TokenService_saveStoredAccounts(
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      env, base::android::GetApplicationContext(), java_accounts.obj());
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (std::vector<std::string>::iterator it = refreshed_ids.begin();
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it != refreshed_ids.end(); it++) {
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    FireRefreshTokenAvailable(*it);
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (std::vector<std::string>::iterator it = revoked_ids.begin();
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it != revoked_ids.end(); it++) {
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    FireRefreshTokenRevoked(*it);
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool AndroidProfileOAuth2TokenService::ValidateAccounts(
2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& signed_in_account,
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::vector<std::string>& prev_account_ids,
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::vector<std::string>& curr_account_ids,
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::vector<std::string>& refreshed_ids,
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::vector<std::string>& revoked_ids) {
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (std::find(curr_account_ids.begin(),
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                curr_account_ids.end(),
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                signed_in_account) != curr_account_ids.end()) {
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Test to see if an account is removed from the Android AccountManager.
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // If so, invoke FireRefreshTokenRevoked to notify the reconcilor.
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         it != prev_account_ids.end(); it++) {
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (*it == signed_in_account)
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        continue;
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (std::find(curr_account_ids.begin(),
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                    curr_account_ids.end(),
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                    *it) == curr_account_ids.end()) {
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        revoked_ids.push_back(*it);
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Always fire the primary signed in account first.
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    refreshed_ids.push_back(signed_in_account);
234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (std::vector<std::string>::const_iterator it = curr_account_ids.begin();
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         it != curr_account_ids.end(); it++) {
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (*it != signed_in_account) {
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        refreshed_ids.push_back(*it);
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return true;
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Currently signed in account does not any longer exist among accounts on
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // system together with all other accounts.
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!signed_in_account.empty()) {
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      revoked_ids.push_back(signed_in_account);
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         it != prev_account_ids.end(); it++) {
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (*it == signed_in_account)
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        continue;
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      revoked_ids.push_back(*it);
2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailableFromJava(
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    JNIEnv* env,
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jobject obj,
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const jstring account_name) {
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string account_id = ConvertJavaStringToUTF8(env, account_name);
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(account_id);
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& account_id) {
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify native observers.
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OAuth2TokenService::FireRefreshTokenAvailable(account_id);
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify Java observers.
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedJavaLocalRef<jstring> account_name =
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ConvertUTF8ToJavaString(env, account_id);
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Java_OAuth2TokenService_notifyRefreshTokenAvailable(
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      env, java_ref_.obj(), account_name.obj());
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokenRevokedFromJava(
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    JNIEnv* env,
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jobject obj,
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const jstring account_name) {
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string account_id = ConvertJavaStringToUTF8(env, account_name);
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(account_id);
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& account_id) {
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify native observers.
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OAuth2TokenService::FireRefreshTokenRevoked(account_id);
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify Java observers.
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ScopedJavaLocalRef<jstring> account_name =
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ConvertUTF8ToJavaString(env, account_id);
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Java_OAuth2TokenService_notifyRefreshTokenRevoked(
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      env, java_ref_.obj(), account_name.obj());
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokensLoadedFromJava(
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    JNIEnv* env,
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jobject obj) {
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded();
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded() {
3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify native observers.
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OAuth2TokenService::FireRefreshTokensLoaded();
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Notify Java observers.
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Java_OAuth2TokenService_notifyRefreshTokensLoaded(
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      env, java_ref_.obj());
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AndroidProfileOAuth2TokenService::RevokeAllCredentials() {
3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<std::string> accounts = GetAccounts();
3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (std::vector<std::string>::iterator it = accounts.begin();
3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       it != accounts.end(); it++) {
3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    FireRefreshTokenRevoked(*it);
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Called from Java when fetching of an OAuth2 token is finished. The
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// |authToken| param is only valid when |result| is true.
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OAuth2TokenFetched(JNIEnv* env, jclass clazz,
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    jstring authToken,
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    jboolean result,
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    jlong nativeCallback) {
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string token = ConvertJavaStringToUTF8(env, authToken);
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Android does not provide enough information to know if the credentials are
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // wrong, so assume any error is transient by using CONNECTION_FAILED.
3327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  GoogleServiceAuthError err(result ?
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                             GoogleServiceAuthError::NONE :
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             GoogleServiceAuthError::CONNECTION_FAILED);
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  heap_callback->Run(err, token, base::Time());
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool AndroidProfileOAuth2TokenService::Register(JNIEnv* env) {
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return RegisterNativesImpl(env);
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
342