1 // Copyright 2014 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.
5 #include "google_apis/gaia/account_tracker.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "net/url_request/url_request_context_getter.h"
13 AccountTracker::AccountTracker(
14 IdentityProvider
* identity_provider
,
15 net::URLRequestContextGetter
* request_context_getter
)
16 : identity_provider_(identity_provider
),
17 request_context_getter_(request_context_getter
),
18 shutdown_called_(false) {
19 identity_provider_
->AddObserver(this);
20 identity_provider_
->GetTokenService()->AddObserver(this);
23 AccountTracker::~AccountTracker() {
24 DCHECK(shutdown_called_
);
27 void AccountTracker::Shutdown() {
28 shutdown_called_
= true;
29 STLDeleteValues(&user_info_requests_
);
30 identity_provider_
->GetTokenService()->RemoveObserver(this);
31 identity_provider_
->RemoveObserver(this);
34 void AccountTracker::AddObserver(Observer
* observer
) {
35 observer_list_
.AddObserver(observer
);
38 void AccountTracker::RemoveObserver(Observer
* observer
) {
39 observer_list_
.RemoveObserver(observer
);
42 std::vector
<AccountIds
> AccountTracker::GetAccounts() const {
43 const std::string active_account_id
=
44 identity_provider_
->GetActiveAccountId();
45 std::vector
<AccountIds
> accounts
;
47 for (std::map
<std::string
, AccountState
>::const_iterator it
=
49 it
!= accounts_
.end();
51 const AccountState
& state
= it
->second
;
52 bool is_visible
= state
.is_signed_in
&& !state
.ids
.gaia
.empty();
54 if (it
->first
== active_account_id
) {
56 accounts
.insert(accounts
.begin(), state
.ids
);
58 return std::vector
<AccountIds
>();
60 } else if (is_visible
) {
61 accounts
.push_back(state
.ids
);
67 AccountIds
AccountTracker::FindAccountIdsByGaiaId(const std::string
& gaia_id
) {
68 for (std::map
<std::string
, AccountState
>::const_iterator it
=
70 it
!= accounts_
.end();
72 const AccountState
& state
= it
->second
;
73 if (state
.ids
.gaia
== gaia_id
) {
81 void AccountTracker::OnRefreshTokenAvailable(const std::string
& account_id
) {
82 // Ignore refresh tokens if there is no active account ID at all.
83 if (identity_provider_
->GetActiveAccountId().empty())
86 DVLOG(1) << "AVAILABLE " << account_id
;
87 UpdateSignInState(account_id
, true);
90 void AccountTracker::OnRefreshTokenRevoked(const std::string
& account_id
) {
91 DVLOG(1) << "REVOKED " << account_id
;
92 UpdateSignInState(account_id
, false);
95 void AccountTracker::OnActiveAccountLogin() {
96 std::vector
<std::string
> accounts
=
97 identity_provider_
->GetTokenService()->GetAccounts();
99 DVLOG(1) << "LOGIN " << accounts
.size() << " accounts available.";
101 for (std::vector
<std::string
>::const_iterator it
= accounts
.begin();
102 it
!= accounts
.end();
104 OnRefreshTokenAvailable(*it
);
108 void AccountTracker::OnActiveAccountLogout() {
109 DVLOG(1) << "LOGOUT";
110 StopTrackingAllAccounts();
113 void AccountTracker::SetAccountStateForTest(AccountIds ids
, bool is_signed_in
) {
114 accounts_
[ids
.account_key
].ids
= ids
;
115 accounts_
[ids
.account_key
].is_signed_in
= is_signed_in
;
117 DVLOG(1) << "SetAccountStateForTest " << ids
.account_key
<< ":"
121 for (std::map
<std::string
, AccountState
>::const_iterator it
=
123 it
!= accounts_
.end();
125 DVLOG(1) << it
->first
<< ":" << it
->second
.is_signed_in
;
130 void AccountTracker::NotifyAccountAdded(const AccountState
& account
) {
131 DCHECK(!account
.ids
.gaia
.empty());
133 Observer
, observer_list_
, OnAccountAdded(account
.ids
));
136 void AccountTracker::NotifyAccountRemoved(const AccountState
& account
) {
137 DCHECK(!account
.ids
.gaia
.empty());
139 Observer
, observer_list_
, OnAccountRemoved(account
.ids
));
142 void AccountTracker::NotifySignInChanged(const AccountState
& account
) {
143 DCHECK(!account
.ids
.gaia
.empty());
144 FOR_EACH_OBSERVER(Observer
,
146 OnAccountSignInChanged(account
.ids
, account
.is_signed_in
));
149 void AccountTracker::UpdateSignInState(const std::string account_key
,
151 StartTrackingAccount(account_key
);
152 AccountState
& account
= accounts_
[account_key
];
153 bool needs_gaia_id
= account
.ids
.gaia
.empty();
154 bool was_signed_in
= account
.is_signed_in
;
155 account
.is_signed_in
= is_signed_in
;
157 if (needs_gaia_id
&& is_signed_in
)
158 StartFetchingUserInfo(account_key
);
160 if (!needs_gaia_id
&& (was_signed_in
!= is_signed_in
))
161 NotifySignInChanged(account
);
164 void AccountTracker::StartTrackingAccount(const std::string account_key
) {
165 if (!ContainsKey(accounts_
, account_key
)) {
166 DVLOG(1) << "StartTracking " << account_key
;
167 AccountState account_state
;
168 account_state
.ids
.account_key
= account_key
;
169 account_state
.ids
.email
= account_key
;
170 account_state
.is_signed_in
= false;
171 accounts_
.insert(make_pair(account_key
, account_state
));
175 void AccountTracker::StopTrackingAccount(const std::string account_key
) {
176 DVLOG(1) << "StopTracking " << account_key
;
177 if (ContainsKey(accounts_
, account_key
)) {
178 AccountState
& account
= accounts_
[account_key
];
179 if (!account
.ids
.gaia
.empty()) {
180 UpdateSignInState(account_key
, false);
181 NotifyAccountRemoved(account
);
183 accounts_
.erase(account_key
);
186 if (ContainsKey(user_info_requests_
, account_key
))
187 DeleteFetcher(user_info_requests_
[account_key
]);
190 void AccountTracker::StopTrackingAllAccounts() {
191 while (!accounts_
.empty())
192 StopTrackingAccount(accounts_
.begin()->first
);
195 void AccountTracker::StartFetchingUserInfo(const std::string account_key
) {
196 if (ContainsKey(user_info_requests_
, account_key
))
197 DeleteFetcher(user_info_requests_
[account_key
]);
199 DVLOG(1) << "StartFetching " << account_key
;
200 AccountIdFetcher
* fetcher
=
201 new AccountIdFetcher(identity_provider_
->GetTokenService(),
202 request_context_getter_
.get(),
205 user_info_requests_
[account_key
] = fetcher
;
209 void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher
* fetcher
,
210 const std::string
& gaia_id
) {
211 const std::string
& account_key
= fetcher
->account_key();
212 DCHECK(ContainsKey(accounts_
, account_key
));
213 AccountState
& account
= accounts_
[account_key
];
215 account
.ids
.gaia
= gaia_id
;
216 NotifyAccountAdded(account
);
218 if (account
.is_signed_in
)
219 NotifySignInChanged(account
);
221 DeleteFetcher(fetcher
);
224 void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher
* fetcher
) {
225 LOG(WARNING
) << "Failed to get UserInfo for " << fetcher
->account_key();
226 std::string key
= fetcher
->account_key();
227 DeleteFetcher(fetcher
);
228 StopTrackingAccount(key
);
231 void AccountTracker::DeleteFetcher(AccountIdFetcher
* fetcher
) {
232 DVLOG(1) << "DeleteFetcher " << fetcher
->account_key();
233 const std::string
& account_key
= fetcher
->account_key();
234 DCHECK(ContainsKey(user_info_requests_
, account_key
));
235 DCHECK_EQ(fetcher
, user_info_requests_
[account_key
]);
236 user_info_requests_
.erase(account_key
);
240 AccountIdFetcher::AccountIdFetcher(
241 OAuth2TokenService
* token_service
,
242 net::URLRequestContextGetter
* request_context_getter
,
243 AccountTracker
* tracker
,
244 const std::string
& account_key
)
245 : OAuth2TokenService::Consumer("gaia_account_tracker"),
246 token_service_(token_service
),
247 request_context_getter_(request_context_getter
),
249 account_key_(account_key
) {
252 AccountIdFetcher::~AccountIdFetcher() {}
254 void AccountIdFetcher::Start() {
255 login_token_request_
= token_service_
->StartRequest(
256 account_key_
, OAuth2TokenService::ScopeSet(), this);
259 void AccountIdFetcher::OnGetTokenSuccess(
260 const OAuth2TokenService::Request
* request
,
261 const std::string
& access_token
,
262 const base::Time
& expiration_time
) {
263 DCHECK_EQ(request
, login_token_request_
.get());
265 gaia_oauth_client_
.reset(new gaia::GaiaOAuthClient(request_context_getter_
));
267 const int kMaxGetUserIdRetries
= 3;
268 gaia_oauth_client_
->GetUserId(access_token
, kMaxGetUserIdRetries
, this);
271 void AccountIdFetcher::OnGetTokenFailure(
272 const OAuth2TokenService::Request
* request
,
273 const GoogleServiceAuthError
& error
) {
274 LOG(ERROR
) << "OnGetTokenFailure: " << error
.ToString();
275 DCHECK_EQ(request
, login_token_request_
.get());
276 tracker_
->OnUserInfoFetchFailure(this);
279 void AccountIdFetcher::OnGetUserIdResponse(const std::string
& gaia_id
) {
280 tracker_
->OnUserInfoFetchSuccess(this, gaia_id
);
283 void AccountIdFetcher::OnOAuthError() {
284 LOG(ERROR
) << "OnOAuthError";
285 tracker_
->OnUserInfoFetchFailure(this);
288 void AccountIdFetcher::OnNetworkError(int response_code
) {
289 LOG(ERROR
) << "OnNetworkError " << response_code
;
290 tracker_
->OnUserInfoFetchFailure(this);