android_profile_oauth2_token_service.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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#include "net/url_request/url_request_context_getter.h"
17
18using base::android::AttachCurrentThread;
19using base::android::CheckException;
20using base::android::ConvertJavaStringToUTF8;
21using base::android::ConvertUTF8ToJavaString;
22using base::android::ScopedJavaLocalRef;
23using content::BrowserThread;
24
25namespace {
26
27std::string CombineScopes(const OAuth2TokenService::ScopeSet& scopes) {
28  // The Android AccountManager supports multiple scopes separated by a space:
29  // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
30  std::string scope;
31  for (OAuth2TokenService::ScopeSet::const_iterator it = scopes.begin();
32       it != scopes.end(); ++it) {
33    if (!scope.empty())
34      scope += " ";
35    scope += *it;
36  }
37  return scope;
38}
39
40}  // namespace
41
42AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService(
43    net::URLRequestContextGetter* getter)
44    : ProfileOAuth2TokenService(getter) {
45}
46
47AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {
48}
49
50scoped_ptr<OAuth2TokenService::Request>
51    AndroidProfileOAuth2TokenService::StartRequest(
52        const OAuth2TokenService::ScopeSet& scopes,
53        OAuth2TokenService::Consumer* consumer) {
54  const std::string& sync_username =
55      SigninManagerFactory::GetForProfile(profile())->
56          GetAuthenticatedUsername();
57  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
58  DCHECK(!sync_username.empty());
59  return StartRequestForUsername(sync_username, scopes, consumer);
60}
61
62scoped_ptr<OAuth2TokenService::Request>
63    AndroidProfileOAuth2TokenService::StartRequestForUsername(
64        const std::string& username,
65        const OAuth2TokenService::ScopeSet& scopes,
66        OAuth2TokenService::Consumer* consumer) {
67  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
68
69  scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
70  FetchOAuth2Token(
71      username,
72      CombineScopes(scopes),
73      base::Bind(&RequestImpl::InformConsumer, request->AsWeakPtr()));
74  return request.PassAs<Request>();
75}
76
77bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable() {
78  SigninManagerBase* signin_manager =
79      SigninManagerFactory::GetForProfile(profile());
80  return !signin_manager->GetAuthenticatedUsername().empty();
81}
82
83void AndroidProfileOAuth2TokenService::InvalidateToken(
84    const ScopeSet& scopes,
85    const std::string& invalid_token) {
86  OAuth2TokenService::InvalidateToken(scopes, invalid_token);
87
88  JNIEnv* env = AttachCurrentThread();
89  ScopedJavaLocalRef<jstring> j_invalid_token =
90      ConvertUTF8ToJavaString(env, invalid_token);
91  Java_AndroidProfileOAuth2TokenServiceHelper_invalidateOAuth2AuthToken(
92      env, base::android::GetApplicationContext(),
93      j_invalid_token.obj());
94}
95
96void AndroidProfileOAuth2TokenService::FetchOAuth2Token(
97    const std::string& username,
98    const std::string& scope,
99    const FetchOAuth2TokenCallback& callback) {
100  JNIEnv* env = AttachCurrentThread();
101  ScopedJavaLocalRef<jstring> j_username =
102      ConvertUTF8ToJavaString(env, username);
103  ScopedJavaLocalRef<jstring> j_scope =
104      ConvertUTF8ToJavaString(env, scope);
105
106  // Allocate a copy of the callback on the heap, because the callback
107  // needs to be passed through JNI as an int.
108  // It will be passed back to OAuth2TokenFetched(), where it will be freed.
109  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
110      new FetchOAuth2TokenCallback(callback));
111
112  // Call into Java to get a new token.
113  Java_AndroidProfileOAuth2TokenServiceHelper_getOAuth2AuthToken(
114      env, base::android::GetApplicationContext(),
115      j_username.obj(),
116      j_scope.obj(),
117      reinterpret_cast<int>(heap_callback.release()));
118}
119
120// Called from Java when fetching of an OAuth2 token is finished. The
121// |authToken| param is only valid when |result| is true.
122void OAuth2TokenFetched(JNIEnv* env, jclass clazz,
123    jstring authToken,
124    jboolean result,
125    jint nativeCallback) {
126  std::string token = ConvertJavaStringToUTF8(env, authToken);
127  scoped_ptr<AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback>
128      heap_callback(
129          reinterpret_cast<
130              AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback*>(
131                  nativeCallback));
132  GoogleServiceAuthError err(result ?
133                             GoogleServiceAuthError::NONE :
134                             GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
135  heap_callback->Run(err, token, base::Time());
136}
137
138// static
139bool AndroidProfileOAuth2TokenService::Register(JNIEnv* env) {
140  return RegisterNativesImpl(env);
141}
142