1 // Copyright 2020 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/android/signin/web_signin_bridge.h"
6 
7 #include "base/android/jni_android.h"
8 #include "base/android/scoped_java_ref.h"
9 #include "chrome/android/chrome_jni_headers/WebSigninBridge_jni.h"
10 #include "chrome/browser/profiles/profile_android.h"
11 #include "chrome/browser/signin/account_reconcilor_factory.h"
12 #include "chrome/browser/signin/identity_manager_factory.h"
13 #include "components/signin/public/android/jni_headers/GoogleServiceAuthError_jni.h"
14 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
15 
16 using base::android::JavaParamRef;
17 
ForwardOnSigninCompletedToJava(const base::android::ScopedJavaGlobalRef<jobject> & j_listener,const GoogleServiceAuthError & error)18 void ForwardOnSigninCompletedToJava(
19     const base::android::ScopedJavaGlobalRef<jobject>& j_listener,
20     const GoogleServiceAuthError& error) {
21   JNIEnv* env = base::android::AttachCurrentThread();
22   if (error.state() == GoogleServiceAuthError::State::NONE) {
23     Java_WebSigninBridge_onSigninSucceded(env, j_listener);
24   } else {
25     base::android::ScopedJavaLocalRef<jobject> j_error =
26         signin::Java_GoogleServiceAuthError_Constructor(env, error.state());
27     Java_WebSigninBridge_onSigninFailed(env, j_listener, j_error);
28   }
29 }
30 
WebSigninBridge(signin::IdentityManager * identity_manager,AccountReconcilor * account_reconcilor,CoreAccountInfo signin_account,OnSigninCompletedCallback on_signin_completed)31 WebSigninBridge::WebSigninBridge(signin::IdentityManager* identity_manager,
32                                  AccountReconcilor* account_reconcilor,
33                                  CoreAccountInfo signin_account,
34                                  OnSigninCompletedCallback on_signin_completed)
35     : identity_manager_(identity_manager),
36       account_reconcilor_(account_reconcilor),
37       signin_account_(signin_account),
38       on_signin_completed_(std::move(on_signin_completed)) {
39   DCHECK(on_signin_completed_) << "Callback must be non-null!";
40 
41   identity_manager_->AddObserver(this);
42   account_reconcilor_->AddObserver(this);
43 
44   signin::AccountsInCookieJarInfo info =
45       identity_manager_->GetAccountsInCookieJar();
46   if (info.accounts_are_fresh)
47     OnAccountsInCookieUpdated(info, GoogleServiceAuthError::AuthErrorNone());
48 }
49 
~WebSigninBridge()50 WebSigninBridge::~WebSigninBridge() {
51   identity_manager_->RemoveObserver(this);
52   account_reconcilor_->RemoveObserver(this);
53 }
54 
OnAccountsInCookieUpdated(const signin::AccountsInCookieJarInfo & accounts_in_cookie_jar_info,const GoogleServiceAuthError & error)55 void WebSigninBridge::OnAccountsInCookieUpdated(
56     const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
57     const GoogleServiceAuthError& error) {
58   for (const auto& account : accounts_in_cookie_jar_info.signed_in_accounts) {
59     if (account.valid && account.gaia_id == signin_account_.gaia) {
60       OnSigninCompleted(GoogleServiceAuthError());
61       return;
62     }
63   }
64 }
65 
OnStateChanged(signin_metrics::AccountReconcilorState state)66 void WebSigninBridge::OnStateChanged(
67     signin_metrics::AccountReconcilorState state) {
68   if (state !=
69       signin_metrics::AccountReconcilorState::ACCOUNT_RECONCILOR_ERROR) {
70     return;
71   }
72 
73   bool is_auth_error =
74       identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
75           signin_account_.account_id);
76   OnSigninCompleted(GoogleServiceAuthError(
77       is_auth_error ? GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS
78                     : GoogleServiceAuthError::State::CONNECTION_FAILED));
79 }
80 
OnSigninCompleted(const GoogleServiceAuthError & error)81 void WebSigninBridge::OnSigninCompleted(const GoogleServiceAuthError& error) {
82   on_signin_completed_.Run(error);
83 }
84 
JNI_WebSigninBridge_Create(JNIEnv * env,const JavaParamRef<jobject> & j_profile,const JavaParamRef<jobject> & j_account,const JavaParamRef<jobject> & j_listener)85 static jlong JNI_WebSigninBridge_Create(
86     JNIEnv* env,
87     const JavaParamRef<jobject>& j_profile,
88     const JavaParamRef<jobject>& j_account,
89     const JavaParamRef<jobject>& j_listener) {
90   DCHECK(j_listener) << "Listener should be non-null";
91 
92   Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
93   signin::IdentityManager* identity_manager =
94       IdentityManagerFactory::GetForProfile(profile);
95   AccountReconcilor* account_reconcilor =
96       AccountReconcilorFactory::GetForProfile(profile);
97   CoreAccountInfo signin_account =
98       ConvertFromJavaCoreAccountInfo(env, j_account);
99   base::RepeatingCallback<void(const GoogleServiceAuthError&)>
100       on_signin_completed = base::BindRepeating(
101           &ForwardOnSigninCompletedToJava,
102           base::android::ScopedJavaGlobalRef<jobject>(j_listener));
103   return reinterpret_cast<intptr_t>(
104       new WebSigninBridge(identity_manager, account_reconcilor, signin_account,
105                           std::move(on_signin_completed)));
106 }
107 
JNI_WebSigninBridge_Destroy(JNIEnv * env,jlong web_signin_bridge)108 static void JNI_WebSigninBridge_Destroy(JNIEnv* env, jlong web_signin_bridge) {
109   delete reinterpret_cast<WebSigninBridge*>(web_signin_bridge);
110 }
111