blob: 57ecadaa339f7a898a74b1688e509b47e47abe3b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/signin_metrics.h"
SigninErrorController::SigninErrorController(AccountMode mode,
OAuth2TokenService* token_service)
: account_mode_(mode),
token_service_(token_service),
scoped_token_service_observer_(this),
auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
DCHECK(token_service_);
scoped_token_service_observer_.Add(token_service_);
Update();
}
SigninErrorController::~SigninErrorController() = default;
void SigninErrorController::Shutdown() {
scoped_token_service_observer_.RemoveAll();
}
void SigninErrorController::Update() {
GoogleServiceAuthError::State prev_state = auth_error_.state();
std::string prev_account_id = error_account_id_;
bool error_changed = false;
// Find an error among the status providers. If |auth_error_| has an
// actionable error state and some provider exposes a similar error and
// account id, use that error. Otherwise, just take the first actionable
// error we find.
for (const std::string& account_id : token_service_->GetAccounts()) {
// In PRIMARY_ACCOUNT mode, ignore all secondary accounts.
if (account_mode_ == AccountMode::PRIMARY_ACCOUNT &&
(account_id != primary_account_id_)) {
continue;
}
if (!token_service_->RefreshTokenHasError(account_id))
continue;
GoogleServiceAuthError error = token_service_->GetAuthError(account_id);
// TokenService only reports persistent errors.
DCHECK(error.IsPersistentError());
// Prioritize this error if it matches the previous |auth_error_|.
if (error.state() == prev_state && account_id == prev_account_id) {
auth_error_ = error;
error_account_id_ = account_id;
error_changed = true;
break;
}
// Use this error if we haven't found one already, but keep looking for the
// previous |auth_error_| in case there's a match elsewhere in the set.
if (!error_changed) {
auth_error_ = error;
error_account_id_ = account_id;
error_changed = true;
}
}
if (!error_changed && prev_state != GoogleServiceAuthError::NONE) {
// No provider reported an error, so clear the error we have now.
auth_error_ = GoogleServiceAuthError::AuthErrorNone();
error_account_id_.clear();
error_changed = true;
}
if (error_changed) {
signin_metrics::LogAuthError(auth_error_);
for (auto& observer : observer_list_)
observer.OnErrorChanged();
}
}
bool SigninErrorController::HasError() const {
DCHECK(!auth_error_.IsTransientError());
return auth_error_.state() != GoogleServiceAuthError::NONE;
}
void SigninErrorController::SetPrimaryAccountID(const std::string& account_id) {
primary_account_id_ = account_id;
if (account_mode_ == AccountMode::PRIMARY_ACCOUNT)
Update(); // Recompute the error state.
}
void SigninErrorController::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void SigninErrorController::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void SigninErrorController::OnEndBatchChanges() {
Update();
}
void SigninErrorController::OnAuthErrorChanged(
const std::string& account_id,
const GoogleServiceAuthError& auth_error) {
Update();
}