android_profile_oauth2_token_service.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/signin/android_profile_oauth2_token_service.h"
6
7#include "base/android/jni_android.h"
8#include "base/android/jni_string.h"
9#include "base/bind.h"
10#include "base/logging.h"
11#include "chrome/browser/signin/signin_manager.h"
12#include "chrome/browser/signin/signin_manager_factory.h"
13#include "chrome/browser/sync/profile_sync_service_android.h"
14#include "content/public/browser/browser_thread.h"
15#include "jni/AndroidProfileOAuth2TokenServiceHelper_jni.h"
16
17using base::android::AttachCurrentThread;
18using base::android::CheckException;
19using base::android::ConvertJavaStringToUTF8;
20using base::android::ConvertUTF8ToJavaString;
21using base::android::ScopedJavaLocalRef;
22using content::BrowserThread;
23
24namespace {
25
26std::string CombineScopes(const OAuth2TokenService::ScopeSet& scopes) {
27  // The Android AccountManager supports multiple scopes separated by a space:
28  // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
29  std::string scope;
30  for (OAuth2TokenService::ScopeSet::const_iterator it = scopes.begin();
31       it != scopes.end(); ++it) {
32    if (!scope.empty())
33      scope += " ";
34    scope += *it;
35  }
36  return scope;
37}
38
39// Callback from FetchOAuth2TokenWithUsername().
40// Arguments:
41// - the error, or NONE if the token fetch was successful.
42// - the OAuth2 access token.
43// - the expiry time of the token (may be null, indicating that the expiry
44//   time is unknown.
45typedef base::Callback<void(
46    const GoogleServiceAuthError&, const std::string&, const base::Time&)>
47        FetchOAuth2TokenCallback;
48
49}  // namespace
50
51AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
52}
53
54AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {
55}
56
57scoped_ptr<OAuth2TokenService::Request>
58    AndroidProfileOAuth2TokenService::StartRequestForUsername(
59        const std::string& username,
60        const OAuth2TokenService::ScopeSet& scopes,
61        OAuth2TokenService::Consumer* consumer) {
62  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
63
64  scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
65  FetchOAuth2TokenWithUsername(request.get(), username, scopes);
66  return request.PassAs<Request>();
67}
68
69bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable() {
70  SigninManagerBase* signin_manager =
71      SigninManagerFactory::GetForProfile(profile());
72  return !signin_manager->GetAuthenticatedUsername().empty();
73}
74
75void AndroidProfileOAuth2TokenService::InvalidateToken(
76    const ScopeSet& scopes,
77    const std::string& invalid_token) {
78  OAuth2TokenService::InvalidateToken(scopes, invalid_token);
79
80  JNIEnv* env = AttachCurrentThread();
81  ScopedJavaLocalRef<jstring> j_invalid_token =
82      ConvertUTF8ToJavaString(env, invalid_token);
83  Java_AndroidProfileOAuth2TokenServiceHelper_invalidateOAuth2AuthToken(
84      env, base::android::GetApplicationContext(),
85      j_invalid_token.obj());
86}
87
88void AndroidProfileOAuth2TokenService::FetchOAuth2Token(
89    RequestImpl* request,
90    net::URLRequestContextGetter* getter,
91    const std::string& client_id,
92    const std::string& client_secret,
93    const OAuth2TokenService::ScopeSet& scopes) {
94  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
95  std::string username = SigninManagerFactory::GetForProfile(profile())->
96      GetAuthenticatedUsername();
97  DCHECK(!username.empty());
98  // Just ignore client_id, getter, etc since we don't use them on Android.
99  FetchOAuth2TokenWithUsername(request, username, scopes);
100}
101
102void AndroidProfileOAuth2TokenService::FetchOAuth2TokenWithUsername(
103    RequestImpl* request,
104    const std::string& username,
105    const OAuth2TokenService::ScopeSet& scopes) {
106  JNIEnv* env = AttachCurrentThread();
107  std::string scope = CombineScopes(scopes);
108  ScopedJavaLocalRef<jstring> j_username =
109      ConvertUTF8ToJavaString(env, username);
110  ScopedJavaLocalRef<jstring> j_scope =
111      ConvertUTF8ToJavaString(env, scope);
112
113  // Allocate a copy of the request WeakPtr on the heap, because the object
114  // needs to be passed through JNI as an int.
115  // It will be passed back to OAuth2TokenFetched(), where it will be freed.
116  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
117      new FetchOAuth2TokenCallback(base::Bind(&RequestImpl::InformConsumer,
118                                              request->AsWeakPtr())));
119
120  // Call into Java to get a new token.
121  Java_AndroidProfileOAuth2TokenServiceHelper_getOAuth2AuthToken(
122      env, base::android::GetApplicationContext(),
123      j_username.obj(),
124      j_scope.obj(),
125      reinterpret_cast<int>(heap_callback.release()));
126}
127
128// Called from Java when fetching of an OAuth2 token is finished. The
129// |authToken| param is only valid when |result| is true.
130void OAuth2TokenFetched(JNIEnv* env, jclass clazz,
131    jstring authToken,
132    jboolean result,
133    jint nativeCallback) {
134  std::string token = ConvertJavaStringToUTF8(env, authToken);
135  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
136      reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
137  GoogleServiceAuthError err(result ?
138                             GoogleServiceAuthError::NONE :
139                             GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
140  heap_callback->Run(err, token, base::Time());
141}
142
143// static
144bool AndroidProfileOAuth2TokenService::Register(JNIEnv* env) {
145  return RegisterNativesImpl(env);
146}
147