summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaelpg@chromium.org <michaelpg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-15 05:21:17 +0000
committermichaelpg@chromium.org <michaelpg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-15 05:21:17 +0000
commitd7f63042849a341441b7237fe28385d1dc9523b7 (patch)
treead2394efd5ad89812e397eb54d3adb324ff1455b
parent4436931da94c0f97c6324c4a09cad6d249596e4f (diff)
downloadchromium_src-d7f63042849a341441b7237fe28385d1dc9523b7.zip
chromium_src-d7f63042849a341441b7237fe28385d1dc9523b7.tar.gz
chromium_src-d7f63042849a341441b7237fe28385d1dc9523b7.tar.bz2
Sign-in Error UI refactor and Ash notifications
For a more detailed design doc, see http://goo.gl/pZnbXS. The previous attempt to add notifications (before this refactored design) was issue 27360003. Auth and sync errors currently show up in the wrench menu as GlobalErrors. This CL removes auth errors from the wrench menu in Chrome OS and in Windows when using the Ash shell, showing notifications instead. The behavior when clicking these notifications should be the same: For sign- in errors, we show a sign-in page (on Chrome OS, the user signs out). SigninGlobalError responds to queries about the menu item errors. Its error-checking logic has been refactored into the new SigninErrorController, which now exposes the error status to the UI classes. The UI class, SigninGlobalError and SigninErrorNotifier, are browser context- keyed services instantiated by the UI which use the SigninErrorController for information about errors, observing the OnErrorChanged method. I tried using a lower similarity, please ignore false positives for unrelated files. ======== Update: I've removed sync error UI changes. A follow-up CL will mirror the auth error logic for sync errors. ======== BUG=128948 TEST=unit_tests --gtest_filter=S*n*Error* TBR=courage@chromium.org big changes: atwilson: signin, sync ben: c/b/ui/views derat: c/b/ui/ash rogerta: signin, sync small changes: asvitkine: c/b/ui/cocoa courage: c/b/extensions/api/identity dbeam: c/b/ui/webui stevenjb: ash/system fyi (Feel free to review): bauerb blundell dewittj oshima rsimha Review URL: https://codereview.chromium.org/172853009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257292 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/system/system_notifier.cc2
-rw-r--r--ash/system/system_notifier.h1
-rw-r--r--chrome/app/chromium_strings.grd42
-rw-r--r--chrome/app/generated_resources.grd7
-rw-r--r--chrome/app/google_chrome_strings.grd42
-rw-r--r--chrome/browser/extensions/api/identity/account_tracker.cc19
-rw-r--r--chrome/browser/extensions/api/identity/account_tracker.h4
-rw-r--r--chrome/browser/signin/fake_auth_status_provider.cc10
-rw-r--r--chrome/browser/signin/fake_auth_status_provider.h15
-rw-r--r--chrome/browser/signin/mutable_profile_oauth2_token_service.cc6
-rw-r--r--chrome/browser/signin/mutable_profile_oauth2_token_service.h4
-rw-r--r--chrome/browser/signin/mutable_profile_oauth2_token_service_unittest.cc3
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service.cc14
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service.h18
-rw-r--r--chrome/browser/signin/signin_error_controller.cc106
-rw-r--r--chrome/browser/signin/signin_error_controller.h79
-rw-r--r--chrome/browser/signin/signin_error_controller_unittest.cc255
-rw-r--r--chrome/browser/signin/signin_error_notifier_ash.cc226
-rw-r--r--chrome/browser/signin/signin_error_notifier_ash.h47
-rw-r--r--chrome/browser/signin/signin_error_notifier_ash_unittest.cc222
-rw-r--r--chrome/browser/signin/signin_error_notifier_factory_ash.cc48
-rw-r--r--chrome/browser/signin/signin_error_notifier_factory_ash.h39
-rw-r--r--chrome/browser/signin/signin_global_error.cc116
-rw-r--r--chrome/browser/signin/signin_global_error.h65
-rw-r--r--chrome/browser/signin/signin_global_error_factory.cc55
-rw-r--r--chrome/browser/signin/signin_global_error_factory.h39
-rw-r--r--chrome/browser/signin/signin_global_error_unittest.cc121
-rw-r--r--chrome/browser/signin/signin_manager.cc1
-rw-r--r--chrome/browser/signin/signin_manager.h1
-rw-r--r--chrome/browser/signin/signin_ui_util.cc13
-rw-r--r--chrome/browser/sync/sync_ui_util.cc12
-rw-r--r--chrome/browser/sync/sync_ui_util_unittest.cc15
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc12
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate_views.cc10
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc25
-rw-r--r--chrome/browser/ui/ash/test_views_delegate_with_parent.cc23
-rw-r--r--chrome/browser/ui/ash/test_views_delegate_with_parent.h25
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller_unittest.mm9
-rw-r--r--chrome/browser/ui/sync/one_click_signin_helper.cc10
-rw-r--r--chrome/browser/ui/views/toolbar/toolbar_view.cc25
-rw-r--r--chrome/browser/ui/views/toolbar/wrench_menu.cc3
-rw-r--r--chrome/browser/ui/webui/options/managed_user_import_handler.cc40
-rw-r--r--chrome/browser/ui/webui/options/managed_user_import_handler.h18
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_handler_impl.cc11
-rw-r--r--chrome/browser/ui/webui/sync_setup_handler.cc13
-rw-r--r--chrome/browser/ui/webui/sync_setup_handler_unittest.cc3
-rw-r--r--chrome/chrome_browser.gypi12
-rw-r--r--chrome/chrome_tests_unit.gypi5
48 files changed, 1504 insertions, 387 deletions
diff --git a/ash/system/system_notifier.cc b/ash/system/system_notifier.cc
index dadb12a..8d30484 100644
--- a/ash/system/system_notifier.cc
+++ b/ash/system/system_notifier.cc
@@ -21,6 +21,7 @@ const char* kAlwaysShownNotifierIds[] = {
};
const char* kAshSystemNotifiers[] = {
+ kNotifierAuthError,
kNotifierDisplay,
kNotifierDisplayResolutionChange,
kNotifierDisplayError,
@@ -53,6 +54,7 @@ bool MatchSystemNotifierId(const message_center::NotifierId& notifier_id,
} // namespace
+const char kNotifierAuthError[] = "ash.auth.error";
const char kNotifierBluetooth[] = "ash.bluetooth";
const char kNotifierDisplay[] = "ash.display";
const char kNotifierDisplayResolutionChange[] = "ash.display.resolution-change";
diff --git a/ash/system/system_notifier.h b/ash/system/system_notifier.h
index 0d4b6c7..00ec2df 100644
--- a/ash/system/system_notifier.h
+++ b/ash/system/system_notifier.h
@@ -14,6 +14,7 @@ namespace ash {
namespace system_notifier {
// The list of ash system notifier IDs. Alphabetical order.
+ASH_EXPORT extern const char kNotifierAuthError[];
ASH_EXPORT extern const char kNotifierBluetooth[];
ASH_EXPORT extern const char kNotifierDisplay[];
ASH_EXPORT extern const char kNotifierDisplayResolutionChange[];
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 8577e6a..616b697 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -926,19 +926,35 @@ Signing in anyway will merge Chromium information like bookmarks, history, and o
</message>
</if>
- <!-- Sync sign-in global error message-->
- <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
- Chromium could not sync your data. Please update your Sync passphrase.
- </message>
- <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user's sign-in credentials are out of date.">
- Chromium could not sync your data because your account sign-in details are out of date.
- </message>
- <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when sync is not available for their domain.">
- Chromium could not sync your data because Sync is not available for your domain.
- </message>
- <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when there's an error signing in.">
- Chromium could not sync your data due to an error signing in.
- </message>
+ <!-- Sync/sign-in error messages -->
+ <if expr="not chromeos">
+ <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
+ Chromium could not sync your data. Please update your Sync passphrase.
+ </message>
+ <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error bubble view when the user's sign-in credentials are out of date.">
+ Chromium could not sync your data because your account sign-in details are out of date.
+ </message>
+ <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error bubble view when sync is not available for their domain.">
+ Chromium could not sync your data because Sync is not available for your domain.
+ </message>
+ <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error bubble view when there's an error signing in.">
+ Chromium could not sync your data due to an error signing in.
+ </message>
+ </if>
+ <if expr="chromeos">
+ <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
+ Chromium OS could not sync your data. Please update your Sync passphrase.
+ </message>
+ <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error notification when the user's sign-in credentials are out of date.">
+ Chromium OS could not sync your data because your account sign-in details are out of date.
+ </message>
+ <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error notification when sync is not available for their domain.">
+ Chromium OS could not sync your data because Sync is not available for your domain.
+ </message>
+ <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sign-in error notification when there's an error signing in.">
+ Chromium OS could not sync your data due to an error signing in.
+ </message>
+ </if>
<message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain.">
On Mac, passwords are saved to your Keychain and may be accessed or synced by other Chromium users sharing this OS X account.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 6ac54e4..d72a8f0 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -12230,13 +12230,16 @@ Some features may be unavailable. Please check that the profile exists and you
Just now
</message>
- <!-- Sync sign in global error message-->
- <message name="IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE" desc="Title in the sign-in error bubble view.">
+ <!-- Sync/sign-in error messages -->
+ <message name="IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE" desc="Title in the sign-in error bubble view/notification.">
Sign-in Error
</message>
<message name="IDS_SYNC_ERROR_BUBBLE_VIEW_TITLE" desc="Title in the sync error bubble view.">
Sync Error
</message>
+ <message name="IDS_SIGNIN_ERROR_NOTIFICATION_TITLE_MULTIPROFILE" desc="Title in the sign-in error notification when multiple users are logged in.">
+ Sign-in Error: <ph name="USER_NAME">$1<ex>foo@example.com</ex></ph>
+ </message>
<if expr="not use_titlecase">
<message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT" desc="The accept button in the sync error bubble view when the user needs to update the passphrase.">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index f83fa88..cdedaf4 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -850,19 +850,35 @@ Signing in anyway will merge Chrome information like bookmarks, history, and oth
</message>
</if>
- <!-- Sync sign-in global error message-->
- <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
- Google Chrome could not sync your data. Please update your Sync passphrase.
- </message>
- <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user's sign-in credentials are out of date.">
- Google Chrome could not sync your data because your account sign-in details are out of date.
- </message>
- <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when sync is not available for their domain.">
- Google Chrome could not sync your data because Sync is not available for your domain.
- </message>
- <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when there's an error signing in.">
- Google Chrome could not sync your data due to an error signing in.
- </message>
+ <!-- Sync/sign-in error messages -->
+ <if expr="not chromeos">
+ <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
+ Google Chrome could not sync your data. Please update your Sync passphrase.
+ </message>
+ <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user's sign-in credentials are out of date.">
+ Google Chrome could not sync your data because your account sign-in details are out of date.
+ </message>
+ <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when sync is not available for their domain.">
+ Google Chrome could not sync your data because Sync is not available for your domain.
+ </message>
+ <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when there's an error signing in.">
+ Google Chrome could not sync your data due to an error signing in.
+ </message>
+ </if>
+ <if expr="chromeos">
+ <message name="IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error bubble view when the user needs to update their sync passphrase.">
+ Chrome OS could not sync your data. Please update your Sync passphrase.
+ </message>
+ <message name="IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error notification when the user's sign-in credentials are out of date.">
+ Chrome OS could not sync your data because your account sign-in details are out of date.
+ </message>
+ <message name="IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error notification when sync is not available for their domain.">
+ Chrome OS could not sync your data because Sync is not available for your domain.
+ </message>
+ <message name="IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE" desc="Message in the sync error notification when there's an error signing in.">
+ Chrome OS could not sync your data due to an error signing in.
+ </message>
+ </if>
<message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain.">
On Mac, passwords are saved to your Keychain and may be accessed or synced by other Chrome users sharing this OS X account.
diff --git a/chrome/browser/extensions/api/identity/account_tracker.cc b/chrome/browser/extensions/api/identity/account_tracker.cc
index 123c88e..f238316 100644
--- a/chrome/browser/extensions/api/identity/account_tracker.cc
+++ b/chrome/browser/extensions/api/identity/account_tracker.cc
@@ -19,8 +19,10 @@
namespace extensions {
AccountTracker::AccountTracker(Profile* profile) : profile_(profile) {
- ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->AddObserver(this);
- SigninGlobalError::GetForProfile(profile_)->AddProvider(this);
+ ProfileOAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ service->AddObserver(this);
+ service->signin_error_controller()->AddProvider(this);
SigninManagerFactory::GetForProfile(profile_)->AddObserver(this);
}
@@ -29,16 +31,18 @@ AccountTracker::~AccountTracker() {}
void AccountTracker::ReportAuthError(const std::string& account_id,
const GoogleServiceAuthError& error) {
account_errors_.insert(make_pair(account_id, error));
- SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+ signin_error_controller()->AuthStatusChanged();
UpdateSignInState(account_id, false);
}
void AccountTracker::Shutdown() {
STLDeleteValues(&user_info_requests_);
SigninManagerFactory::GetForProfile(profile_)->RemoveObserver(this);
- SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
- ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
- RemoveObserver(this);
+ ProfileOAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
+ service->signin_error_controller()->RemoveProvider(this);
+ service->RemoveObserver(this);
}
void AccountTracker::AddObserver(Observer* observer) {
@@ -111,7 +115,8 @@ void AccountTracker::NotifySignInChanged(const AccountState& account) {
void AccountTracker::ClearAuthError(const std::string& account_key) {
account_errors_.erase(account_key);
- SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
+ signin_error_controller()->AuthStatusChanged();
}
void AccountTracker::UpdateSignInState(const std::string& account_key,
diff --git a/chrome/browser/extensions/api/identity/account_tracker.h b/chrome/browser/extensions/api/identity/account_tracker.h
index 3ad4f41..16d8b95 100644
--- a/chrome/browser/extensions/api/identity/account_tracker.h
+++ b/chrome/browser/extensions/api/identity/account_tracker.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/observer_list.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager_base.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -37,7 +37,7 @@ class AccountIdFetcher;
// 3. SignIn follows Add, and there will be a SignOut between SignIn & Remove.
// 4. If there is no primary account, there are no other accounts.
class AccountTracker : public OAuth2TokenService::Observer,
- public SigninGlobalError::AuthStatusProvider,
+ public SigninErrorController::AuthStatusProvider,
public SigninManagerBase::Observer {
public:
explicit AccountTracker(Profile* profile);
diff --git a/chrome/browser/signin/fake_auth_status_provider.cc b/chrome/browser/signin/fake_auth_status_provider.cc
index 830a028..aacf600 100644
--- a/chrome/browser/signin/fake_auth_status_provider.cc
+++ b/chrome/browser/signin/fake_auth_status_provider.cc
@@ -4,14 +4,14 @@
#include "chrome/browser/signin/fake_auth_status_provider.h"
-FakeAuthStatusProvider::FakeAuthStatusProvider(SigninGlobalError* error)
- : global_error_(error),
+FakeAuthStatusProvider::FakeAuthStatusProvider(SigninErrorController* error)
+ : error_provider_(error),
auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
- global_error_->AddProvider(this);
+ error_provider_->AddProvider(this);
}
FakeAuthStatusProvider::~FakeAuthStatusProvider() {
- global_error_->RemoveProvider(this);
+ error_provider_->RemoveProvider(this);
}
std::string FakeAuthStatusProvider::GetAccountId() const {
@@ -26,5 +26,5 @@ void FakeAuthStatusProvider::SetAuthError(const std::string& account_id,
const GoogleServiceAuthError& error) {
account_id_ = account_id;
auth_error_ = error;
- global_error_->AuthStatusChanged();
+ error_provider_->AuthStatusChanged();
}
diff --git a/chrome/browser/signin/fake_auth_status_provider.h b/chrome/browser/signin/fake_auth_status_provider.h
index 756922c..e5969f6 100644
--- a/chrome/browser/signin/fake_auth_status_provider.h
+++ b/chrome/browser/signin/fake_auth_status_provider.h
@@ -5,18 +5,19 @@
#ifndef CHROME_BROWSER_SIGNIN_FAKE_AUTH_STATUS_PROVIDER_H_
#define CHROME_BROWSER_SIGNIN_FAKE_AUTH_STATUS_PROVIDER_H_
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_error_controller.h"
-// Helper class that reports auth errors to SigninGlobalError. Automatically
+// Helper class that reports auth errors to SigninErrorController. Automatically
// registers and de-registers itself as an AuthStatusProvider in the
// constructor and destructor.
-class FakeAuthStatusProvider : public SigninGlobalError::AuthStatusProvider {
+class FakeAuthStatusProvider
+ : public SigninErrorController::AuthStatusProvider {
public:
- explicit FakeAuthStatusProvider(SigninGlobalError* error);
+ explicit FakeAuthStatusProvider(SigninErrorController* error);
virtual ~FakeAuthStatusProvider();
- // Sets the auth error that this provider reports to SigninGlobalError. Also
- // notifies SigninGlobalError via AuthStatusChanged().
+ // Sets the auth error that this provider reports to SigninErrorController.
+ // Also notifies SigninErrorController via AuthStatusChanged().
void SetAuthError(const std::string& account_id,
const GoogleServiceAuthError& error);
@@ -29,7 +30,7 @@ class FakeAuthStatusProvider : public SigninGlobalError::AuthStatusProvider {
virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
private:
- SigninGlobalError* global_error_;
+ SigninErrorController* error_provider_;
std::string account_id_;
GoogleServiceAuthError auth_error_;
};
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service.cc
index 7402a6e..035d7ba 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service.cc
@@ -89,18 +89,18 @@ MutableProfileOAuth2TokenService::AccountInfo::AccountInfo(
last_auth_error_(GoogleServiceAuthError::NONE) {
DCHECK(token_service_);
DCHECK(!account_id_.empty());
- token_service_->signin_global_error()->AddProvider(this);
+ token_service_->signin_error_controller()->AddProvider(this);
}
MutableProfileOAuth2TokenService::AccountInfo::~AccountInfo() {
- token_service_->signin_global_error()->RemoveProvider(this);
+ token_service_->signin_error_controller()->RemoveProvider(this);
}
void MutableProfileOAuth2TokenService::AccountInfo::SetLastAuthError(
const GoogleServiceAuthError& error) {
if (error.state() != last_auth_error_.state()) {
last_auth_error_ = error;
- token_service_->signin_global_error()->AuthStatusChanged();
+ token_service_->signin_error_controller()->AuthStatusChanged();
}
}
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service.h b/chrome/browser/signin/mutable_profile_oauth2_token_service.h
index ad7dca9..80bf19e 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service.h
@@ -36,7 +36,7 @@ class MutableProfileOAuth2TokenService : public ProfileOAuth2TokenService,
void RevokeCredentials(const std::string& account_id);
protected:
- class AccountInfo : public SigninGlobalError::AuthStatusProvider {
+ class AccountInfo : public SigninErrorController::AuthStatusProvider {
public:
AccountInfo(ProfileOAuth2TokenService* token_service,
const std::string& account_id,
@@ -50,7 +50,7 @@ class MutableProfileOAuth2TokenService : public ProfileOAuth2TokenService,
void SetLastAuthError(const GoogleServiceAuthError& error);
- // SigninGlobalError::AuthStatusProvider implementation.
+ // SigninErrorController::AuthStatusProvider implementation.
virtual std::string GetAccountId() const OVERRIDE;
virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_unittest.cc
index bc3b71f..c0f72d5 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_unittest.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_unittest.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/signin/mutable_profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/signin/core/webdata/token_web_data.h"
@@ -343,5 +344,5 @@ TEST_F(MutableProfileOAuth2TokenServiceTest, FetchTransientError) {
oauth2_service_->StartRequest(kEmail, scope_list, &consumer_));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
- oauth2_service_->signin_global_error()->GetLastAuthError());
+ oauth2_service_->signin_error_controller()->auth_error());
}
diff --git a/chrome/browser/signin/profile_oauth2_token_service.cc b/chrome/browser/signin/profile_oauth2_token_service.cc
index 28bc3c6..0d9b50d 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service.cc
@@ -9,15 +9,15 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/global_error/global_error_service.h"
-#include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
+#include "chrome/browser/signin/signin_global_error_factory.h"
#include "net/url_request/url_request_context_getter.h"
ProfileOAuth2TokenService::ProfileOAuth2TokenService()
: client_(NULL), profile_(NULL) {}
ProfileOAuth2TokenService::~ProfileOAuth2TokenService() {
- DCHECK(!signin_global_error_.get()) <<
+ DCHECK(!signin_error_controller_.get()) <<
"ProfileOAuth2TokenService::Initialize called but not "
"ProfileOAuth2TokenService::Shutdown";
}
@@ -31,16 +31,12 @@ void ProfileOAuth2TokenService::Initialize(SigninClient* client,
DCHECK(!profile_);
profile_ = profile;
- signin_global_error_.reset(new SigninGlobalError(profile));
- GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(
- signin_global_error_.get());
+ signin_error_controller_.reset(new SigninErrorController());
}
void ProfileOAuth2TokenService::Shutdown() {
DCHECK(profile_) << "Shutdown() called without matching call to Initialize()";
- GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(
- signin_global_error_.get());
- signin_global_error_.reset();
+ signin_error_controller_.reset();
}
net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() {
diff --git a/chrome/browser/signin/profile_oauth2_token_service.h b/chrome/browser/signin/profile_oauth2_token_service.h
index b7d88795..2b67065 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.h
+++ b/chrome/browser/signin/profile_oauth2_token_service.h
@@ -9,7 +9,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -20,7 +20,6 @@ class URLRequestContextGetter;
class GoogleServiceAuthError;
class Profile;
class SigninClient;
-class SigninGlobalError;
// ProfileOAuth2TokenService is a class that retrieves
// OAuth2 access tokens for a given set of scopes using the OAuth2 login
@@ -69,12 +68,12 @@ class ProfileOAuth2TokenService : public OAuth2TokenService {
// Revokes all credentials handled by the object.
virtual void RevokeAllCredentials();
- SigninGlobalError* signin_global_error() {
- return signin_global_error_.get();
+ SigninErrorController* signin_error_controller() {
+ return signin_error_controller_.get();
}
- const SigninGlobalError* signin_global_error() const {
- return signin_global_error_.get();
+ const SigninErrorController* signin_error_controller() const {
+ return signin_error_controller_.get();
}
SigninClient* client() const { return client_; }
@@ -102,11 +101,8 @@ class ProfileOAuth2TokenService : public OAuth2TokenService {
// The profile with which this instance was initialized, or NULL.
Profile* profile_;
- // Used to show auth errors in the wrench menu. The SigninGlobalError is
- // different than most GlobalErrors in that its lifetime is controlled by
- // ProfileOAuth2TokenService (so we can expose a reference for use in the
- // wrench menu).
- scoped_ptr<SigninGlobalError> signin_global_error_;
+ // Used to expose auth errors to the UI.
+ scoped_ptr<SigninErrorController> signin_error_controller_;
DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenService);
};
diff --git a/chrome/browser/signin/signin_error_controller.cc b/chrome/browser/signin/signin_error_controller.cc
new file mode 100644
index 0000000..94fd840
--- /dev/null
+++ b/chrome/browser/signin/signin_error_controller.cc
@@ -0,0 +1,106 @@
+// 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 "chrome/browser/signin/signin_error_controller.h"
+
+namespace {
+
+typedef std::set<const SigninErrorController::AuthStatusProvider*>
+ AuthStatusProviderSet;
+
+} // namespace
+
+SigninErrorController::AuthStatusProvider::AuthStatusProvider() {
+}
+
+SigninErrorController::AuthStatusProvider::~AuthStatusProvider() {
+}
+
+SigninErrorController::SigninErrorController()
+ : auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
+}
+
+SigninErrorController::~SigninErrorController() {
+ DCHECK(provider_set_.empty())
+ << "All AuthStatusProviders should be unregistered before"
+ << " SigninErrorController::Shutdown() is called";
+}
+
+void SigninErrorController::AddProvider(const AuthStatusProvider* provider) {
+ DCHECK(provider_set_.find(provider) == provider_set_.end())
+ << "Adding same AuthStatusProvider multiple times";
+ provider_set_.insert(provider);
+ AuthStatusChanged();
+}
+
+void SigninErrorController::RemoveProvider(const AuthStatusProvider* provider) {
+ AuthStatusProviderSet::iterator iter = provider_set_.find(provider);
+ DCHECK(iter != provider_set_.end())
+ << "Removing provider that was never added";
+ provider_set_.erase(iter);
+ AuthStatusChanged();
+}
+
+void SigninErrorController::AuthStatusChanged() {
+ 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 (AuthStatusProviderSet::const_iterator it = provider_set_.begin();
+ it != provider_set_.end(); ++it) {
+ GoogleServiceAuthError error = (*it)->GetAuthStatus();
+
+ // Ignore the states we don't want to elevate to the user.
+ if (error.state() == GoogleServiceAuthError::NONE ||
+ error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
+ continue;
+ }
+
+ std::string account_id = (*it)->GetAccountId();
+
+ // 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) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnErrorChanged());
+ }
+}
+
+bool SigninErrorController::HasError() const {
+ return auth_error_.state() != GoogleServiceAuthError::NONE &&
+ auth_error_.state() != GoogleServiceAuthError::CONNECTION_FAILED;
+}
+
+void SigninErrorController::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void SigninErrorController::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
diff --git a/chrome/browser/signin/signin_error_controller.h b/chrome/browser/signin/signin_error_controller.h
new file mode 100644
index 0000000..321060c
--- /dev/null
+++ b/chrome/browser/signin/signin_error_controller.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_CONTROLLER_H_
+#define CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_CONTROLLER_H_
+
+#include <set>
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
+// Keep track of auth errors and expose them to observers in the UI. Services
+// that wish to expose auth errors to the user should register an
+// AuthStatusProvider to report their current authentication state, and should
+// invoke AuthStatusChanged() when their authentication state may have changed.
+class SigninErrorController {
+ public:
+ class AuthStatusProvider {
+ public:
+ AuthStatusProvider();
+ virtual ~AuthStatusProvider();
+
+ // Returns the account id with the status specified by GetAuthStatus().
+ virtual std::string GetAccountId() const = 0;
+
+ // API invoked by SigninErrorController to get the current auth status of
+ // the various signed in services.
+ virtual GoogleServiceAuthError GetAuthStatus() const = 0;
+ };
+
+ // The observer class for SigninErrorController lets the controller notify
+ // observers when an error arises or changes.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnErrorChanged() = 0;
+ };
+
+ SigninErrorController();
+ ~SigninErrorController();
+
+ // Adds a provider which the SigninErrorController object will start querying
+ // for auth status.
+ void AddProvider(const AuthStatusProvider* provider);
+
+ // Removes a provider previously added by SigninErrorController (generally
+ // only called in preparation for shutdown).
+ void RemoveProvider(const AuthStatusProvider* provider);
+
+ // Invoked when the auth status of an AuthStatusProvider has changed.
+ void AuthStatusChanged();
+
+ // True if there exists an error worth elevating to the user.
+ bool HasError() const;
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ const std::string& error_account_id() const { return error_account_id_; }
+ const GoogleServiceAuthError& auth_error() const { return auth_error_; }
+
+ private:
+ std::set<const AuthStatusProvider*> provider_set_;
+
+ // The account that generated the last auth error.
+ std::string error_account_id_;
+
+ // The auth error detected the last time AuthStatusChanged() was invoked (or
+ // NONE if AuthStatusChanged() has never been invoked).
+ GoogleServiceAuthError auth_error_;
+
+ ObserverList<Observer, false> observer_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninErrorController);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_CONTROLLER_H_
diff --git a/chrome/browser/signin/signin_error_controller_unittest.cc b/chrome/browser/signin/signin_error_controller_unittest.cc
new file mode 100644
index 0000000..6eb0c1b
--- /dev/null
+++ b/chrome/browser/signin/signin_error_controller_unittest.cc
@@ -0,0 +1,255 @@
+// 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 "chrome/browser/signin/signin_error_controller.h"
+
+#include <functional>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/signin/fake_auth_status_provider.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static const char kTestAccountId[] = "testuser@test.com";
+static const char kOtherTestAccountId[] = "otheruser@test.com";
+
+class SigninErrorControllerTest : public testing::Test {
+ public:
+ virtual void SetUp() OVERRIDE {
+ error_controller_.reset(new SigninErrorController());
+ }
+
+ scoped_ptr<SigninErrorController> error_controller_;
+};
+
+TEST_F(SigninErrorControllerTest, NoErrorAuthStatusProviders) {
+ scoped_ptr<FakeAuthStatusProvider> provider;
+
+ // No providers.
+ ASSERT_FALSE(error_controller_->HasError());
+
+ // Add a provider.
+ provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
+ ASSERT_FALSE(error_controller_->HasError());
+
+ // Remove the provider.
+ provider.reset();
+ ASSERT_FALSE(error_controller_->HasError());
+}
+
+TEST_F(SigninErrorControllerTest, ErrorAuthStatusProvider) {
+ scoped_ptr<FakeAuthStatusProvider> provider;
+ scoped_ptr<FakeAuthStatusProvider> error_provider;
+
+ provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
+ ASSERT_FALSE(error_controller_->HasError());
+
+ error_provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
+ error_provider->SetAuthError(kTestAccountId, GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_TRUE(error_controller_->HasError());
+
+ error_provider.reset();
+ ASSERT_FALSE(error_controller_->HasError());
+
+ provider.reset();
+ // All providers should be removed now.
+ ASSERT_FALSE(error_controller_->HasError());
+}
+
+TEST_F(SigninErrorControllerTest, AuthStatusProviderErrorTransition) {
+ scoped_ptr<FakeAuthStatusProvider> provider0(
+ new FakeAuthStatusProvider(error_controller_.get()));
+ scoped_ptr<FakeAuthStatusProvider> provider1(
+ new FakeAuthStatusProvider(error_controller_.get()));
+
+ ASSERT_FALSE(error_controller_->HasError());
+ provider0->SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_TRUE(error_controller_->HasError());
+ provider1->SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED));
+ ASSERT_TRUE(error_controller_->HasError());
+
+ // Now resolve the auth errors - the menu item should go away.
+ provider0->SetAuthError(kTestAccountId,
+ GoogleServiceAuthError::AuthErrorNone());
+ ASSERT_TRUE(error_controller_->HasError());
+ provider1->SetAuthError(kTestAccountId,
+ GoogleServiceAuthError::AuthErrorNone());
+ ASSERT_FALSE(error_controller_->HasError());
+
+ provider0.reset();
+ provider1.reset();
+ ASSERT_FALSE(error_controller_->HasError());
+}
+
+TEST_F(SigninErrorControllerTest, AuthStatusProviderAccountTransition) {
+ scoped_ptr<FakeAuthStatusProvider> provider0(
+ new FakeAuthStatusProvider(error_controller_.get()));
+ scoped_ptr<FakeAuthStatusProvider> provider1(
+ new FakeAuthStatusProvider(error_controller_.get()));
+
+ ASSERT_FALSE(error_controller_->HasError());
+
+ provider0->SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ provider1->SetAuthError(
+ kOtherTestAccountId,
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+ ASSERT_TRUE(error_controller_->HasError());
+ ASSERT_STREQ(kTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ // Swap providers reporting errors.
+ provider1->set_error_without_status_change(
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ provider0->set_error_without_status_change(
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+ error_controller_->AuthStatusChanged();
+ ASSERT_TRUE(error_controller_->HasError());
+ ASSERT_STREQ(kOtherTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ // Now resolve the auth errors - the menu item should go away.
+ provider0->set_error_without_status_change(
+ GoogleServiceAuthError::AuthErrorNone());
+ provider1->set_error_without_status_change(
+ GoogleServiceAuthError::AuthErrorNone());
+ error_controller_->AuthStatusChanged();
+ ASSERT_FALSE(error_controller_->HasError());
+
+ provider0.reset();
+ provider1.reset();
+ ASSERT_FALSE(error_controller_->HasError());
+}
+
+// Verify that SigninErrorController handles errors properly.
+TEST_F(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
+ typedef struct {
+ GoogleServiceAuthError::State error_state;
+ bool is_error;
+ } ErrorTableEntry;
+
+ ErrorTableEntry table[] = {
+ { GoogleServiceAuthError::NONE, false },
+ { GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true },
+ { GoogleServiceAuthError::USER_NOT_SIGNED_UP, true },
+ { GoogleServiceAuthError::CONNECTION_FAILED, false },
+ { GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
+ { GoogleServiceAuthError::ACCOUNT_DELETED, true },
+ { GoogleServiceAuthError::ACCOUNT_DISABLED, true },
+ { GoogleServiceAuthError::SERVICE_UNAVAILABLE, true },
+ { GoogleServiceAuthError::TWO_FACTOR, true },
+ { GoogleServiceAuthError::REQUEST_CANCELED, true },
+ { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true },
+ { GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
+ { GoogleServiceAuthError::SERVICE_ERROR, true },
+ };
+ COMPILE_ASSERT(ARRAYSIZE_UNSAFE(table) == GoogleServiceAuthError::NUM_STATES,
+ kTable_size_does_not_match_number_of_auth_error_types);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(table); ++i) {
+ FakeAuthStatusProvider provider(error_controller_.get());
+ provider.SetAuthError(kTestAccountId,
+ GoogleServiceAuthError(table[i].error_state));
+
+ EXPECT_EQ(error_controller_->HasError(), table[i].is_error);
+
+ if (table[i].is_error) {
+ EXPECT_EQ(table[i].error_state,
+ error_controller_->auth_error().state());
+ EXPECT_STREQ(kTestAccountId,
+ error_controller_->error_account_id().c_str());
+ } else {
+ EXPECT_EQ(GoogleServiceAuthError::NONE,
+ error_controller_->auth_error().state());
+ EXPECT_STREQ("",
+ error_controller_->error_account_id().c_str());
+ }
+ }
+}
+
+// Verify that existing error is not replaced by new error.
+TEST_F(SigninErrorControllerTest, AuthStatusChange) {
+ scoped_ptr<FakeAuthStatusProvider> fake_provider0(
+ new FakeAuthStatusProvider(error_controller_.get()));
+ scoped_ptr<FakeAuthStatusProvider> fake_provider1(
+ new FakeAuthStatusProvider(error_controller_.get()));
+
+ // If there are multiple providers in the provider set...
+ //
+ // | provider0 | provider1 | ...
+ // | NONE | INVALID_GAIA_CREDENTIALS | ...
+ //
+ // SigninErrorController picks the first error found when iterating through
+ // the set. But if another error crops up...
+ //
+ // | provider0 | provider1 | ...
+ // | SERVICE_UNAVAILABLE | INVALID_GAIA_CREDENTIALS | ...
+ //
+ // we want the controller to still use the original error.
+
+ // The provider pointers are stored in a set, which is sorted by std::less.
+ std::less<SigninErrorController::AuthStatusProvider*> compare;
+ FakeAuthStatusProvider* provider0 =
+ compare(fake_provider0.get(), fake_provider1.get()) ?
+ fake_provider0.get() : fake_provider1.get();
+ FakeAuthStatusProvider* provider1 =
+ provider0 == fake_provider0.get() ?
+ fake_provider1.get() : fake_provider0.get();
+
+ provider0->SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::NONE));
+ provider1->SetAuthError(
+ kOtherTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
+ error_controller_->auth_error().state());
+ ASSERT_STREQ(kOtherTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ // Change the 1st provider's error.
+ provider1->SetAuthError(
+ kOtherTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE));
+ ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ error_controller_->auth_error().state());
+ ASSERT_STREQ(kOtherTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ // Set the 0th provider's error -- nothing should change.
+ provider0->SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
+ ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ error_controller_->auth_error().state());
+ ASSERT_STREQ(kOtherTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ // Clear the 1st provider's error, so the 0th provider's error is used.
+ provider1->SetAuthError(
+ kOtherTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::NONE));
+ ASSERT_EQ(GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE,
+ error_controller_->auth_error().state());
+ ASSERT_STREQ(kTestAccountId,
+ error_controller_->error_account_id().c_str());
+
+ fake_provider0.reset();
+ fake_provider1.reset();
+ ASSERT_FALSE(error_controller_->HasError());
+}
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc
new file mode 100644
index 0000000..d40fd47
--- /dev/null
+++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -0,0 +1,226 @@
+// 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 "chrome/browser/signin/signin_error_notifier_ash.h"
+
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/system/system_notifier.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_delegate.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service.h"
+#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
+#include "chrome/common/url_constants.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "third_party/WebKit/public/web/WebTextDirection.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_delegate.h"
+
+namespace {
+
+const char kProfileSigninNotificationId[] = "chrome://settings/signin/";
+
+// A notification delegate for the sign-out button.
+class SigninNotificationDelegate : public NotificationDelegate {
+ public:
+ SigninNotificationDelegate(const std::string& id,
+ Profile* profile);
+
+ // NotificationDelegate:
+ virtual void Display() OVERRIDE;
+ virtual void Error() OVERRIDE;
+ virtual void Close(bool by_user) OVERRIDE;
+ virtual bool HasClickedListener() OVERRIDE;
+ virtual void Click() OVERRIDE;
+ virtual void ButtonClick(int button_index) OVERRIDE;
+ virtual std::string id() const OVERRIDE;
+ virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE;
+
+ protected:
+ virtual ~SigninNotificationDelegate();
+
+ private:
+ // Unique id of the notification.
+ const std::string id_;
+
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninNotificationDelegate);
+};
+
+SigninNotificationDelegate::SigninNotificationDelegate(
+ const std::string& id,
+ Profile* profile)
+ : id_(id),
+ profile_(profile) {
+}
+
+SigninNotificationDelegate::~SigninNotificationDelegate() {
+}
+
+void SigninNotificationDelegate::Display() {
+}
+
+void SigninNotificationDelegate::Error() {
+}
+
+void SigninNotificationDelegate::Close(bool by_user) {
+}
+
+bool SigninNotificationDelegate::HasClickedListener() {
+ return false;
+}
+
+void SigninNotificationDelegate::Click() {
+}
+
+void SigninNotificationDelegate::ButtonClick(int button_index) {
+#if defined(OS_CHROMEOS)
+ chrome::AttemptUserExit();
+#else
+ LoginUIService* login_ui = LoginUIServiceFactory::GetForProfile(profile_);
+ if (login_ui->current_login_ui()) {
+ login_ui->current_login_ui()->FocusUI();
+ return;
+ }
+
+ // Find a browser instance or create one.
+ chrome::ScopedTabbedBrowserDisplayer browser_displayer(
+ profile_, chrome::HOST_DESKTOP_TYPE_ASH);
+
+ // Navigate to the sync setup subpage, which will launch a login page.
+ chrome::ShowSettingsSubPage(browser_displayer.browser(),
+ chrome::kSyncSetupSubPage);
+#endif
+}
+
+std::string SigninNotificationDelegate::id() const {
+ return id_;
+}
+
+content::RenderViewHost* SigninNotificationDelegate::GetRenderViewHost() const {
+ return NULL;
+}
+
+} // namespace
+
+SigninErrorNotifier::SigninErrorNotifier(SigninErrorController* controller,
+ Profile* profile)
+ : error_controller_(controller),
+ profile_(profile) {
+ // Create a unique notification ID for this profile.
+ notification_id_ = kProfileSigninNotificationId + profile->GetProfileName();
+
+ error_controller_->AddObserver(this);
+ OnErrorChanged();
+}
+
+SigninErrorNotifier::~SigninErrorNotifier() {
+ DCHECK(!error_controller_)
+ << "SigninErrorNotifier::Shutdown() was not called";
+}
+
+void SigninErrorNotifier::Shutdown() {
+ error_controller_->RemoveObserver(this);
+ error_controller_ = NULL;
+}
+
+void SigninErrorNotifier::OnErrorChanged() {
+ NotificationUIManager* notification_ui_manager =
+ g_browser_process->notification_ui_manager();
+
+ // notification_ui_manager() may return NULL when shutting down.
+ if (!notification_ui_manager)
+ return;
+
+ if (!error_controller_->HasError()) {
+ g_browser_process->notification_ui_manager()->CancelById(notification_id_);
+ return;
+ }
+
+ // Add an accept button to sign the user out.
+ message_center::RichNotificationData data;
+ data.buttons.push_back(message_center::ButtonInfo(
+ l10n_util::GetStringUTF16(IDS_SYNC_RELOGIN_LINK_LABEL)));
+
+ // Set the delegate for the notification's sign-out button.
+ SigninNotificationDelegate* delegate =
+ new SigninNotificationDelegate(notification_id_, profile_);
+
+ Notification notification(
+ message_center::NOTIFICATION_TYPE_SIMPLE,
+ GURL(notification_id_),
+ GetMessageTitle(),
+ GetMessageBody(),
+ ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ IDR_NOTIFICATION_ALERT),
+ blink::WebTextDirectionDefault,
+ message_center::NotifierId(
+ message_center::NotifierId::SYSTEM_COMPONENT,
+ ash::system_notifier::kNotifierAuthError),
+ base::string16(), // display_source
+ base::ASCIIToUTF16(notification_id_),
+ data,
+ delegate);
+
+ // Update or add the notification.
+ if (notification_ui_manager->FindById(notification_id_))
+ notification_ui_manager->Update(notification, profile_);
+ else
+ notification_ui_manager->Add(notification, profile_);
+}
+
+base::string16 SigninErrorNotifier::GetMessageTitle() const {
+ if (ash::Shell::HasInstance() &&
+ ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) {
+ // Include the account id in the message text to differentiate between
+ // profiles.
+ return l10n_util::GetStringFUTF16(
+ IDS_SIGNIN_ERROR_NOTIFICATION_TITLE_MULTIPROFILE,
+ base::ASCIIToUTF16(error_controller_->error_account_id()));
+ }
+
+ return l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE);
+}
+
+base::string16 SigninErrorNotifier::GetMessageBody() const {
+ switch (error_controller_->auth_error().state()) {
+ // TODO(rogerta): use account id in error messages.
+
+ // User credentials are invalid (bad acct, etc).
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
+ case GoogleServiceAuthError::SERVICE_ERROR:
+ case GoogleServiceAuthError::ACCOUNT_DELETED:
+ case GoogleServiceAuthError::ACCOUNT_DISABLED:
+ return l10n_util::GetStringUTF16(
+ IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE);
+ break;
+
+ // Sync service is not available for this account's domain.
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
+ return l10n_util::GetStringUTF16(
+ IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE);
+ break;
+
+ // Generic message for "other" errors.
+ default:
+ return l10n_util::GetStringUTF16(
+ IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE);
+ }
+}
diff --git a/chrome/browser/signin/signin_error_notifier_ash.h b/chrome/browser/signin/signin_error_notifier_ash.h
new file mode 100644
index 0000000..04d7556
--- /dev/null
+++ b/chrome/browser/signin/signin_error_notifier_ash.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_ASH_H_
+#define CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_ASH_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/signin/signin_error_controller.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+
+class Profile;
+
+// Shows signin-related errors as notifications in Ash.
+class SigninErrorNotifier : public SigninErrorController::Observer,
+ public BrowserContextKeyedService {
+ public:
+ SigninErrorNotifier(SigninErrorController* controller, Profile* profile);
+ virtual ~SigninErrorNotifier();
+
+ // BrowserContextKeyedService:
+ virtual void Shutdown() OVERRIDE;
+
+ // SigninErrorController::Observer:
+ virtual void OnErrorChanged() OVERRIDE;
+
+ private:
+ base::string16 GetMessageTitle() const;
+ base::string16 GetMessageBody() const;
+
+ // The error controller to query for error details.
+ SigninErrorController* error_controller_;
+
+ // The Profile this service belongs to.
+ Profile* profile_;
+
+ // Used to keep track of the message center notification.
+ std::string notification_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninErrorNotifier);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_ASH_H_
diff --git a/chrome/browser/signin/signin_error_notifier_ash_unittest.cc b/chrome/browser/signin/signin_error_notifier_ash_unittest.cc
new file mode 100644
index 0000000..3161f17
--- /dev/null
+++ b/chrome/browser/signin/signin_error_notifier_ash_unittest.cc
@@ -0,0 +1,222 @@
+// 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 "chrome/browser/signin/signin_error_notifier_ash.h"
+
+#include "ash/test/ash_test_base.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/browser/signin/fake_auth_status_provider.h"
+#include "chrome/browser/signin/fake_signin_manager.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
+#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/ui/ash/test_views_delegate_with_parent.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/notification.h"
+
+#if !defined(OS_CHROMEOS)
+#include "chrome/browser/ui/ash/ash_util.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/screen_type_delegate.h"
+#endif
+
+namespace ash {
+namespace test {
+
+namespace {
+
+static const char kTestAccountId[] = "testuser@test.com";
+
+// Notification ID corresponding to kProfileSigninNotificationId +
+// kTestAccountId.
+static const std::string kNotificationId =
+ "chrome://settings/signin/testuser@test.com";
+}
+
+#if !defined(OS_CHROMEOS)
+class ScreenTypeDelegateDesktop : public gfx::ScreenTypeDelegate {
+ public:
+ ScreenTypeDelegateDesktop() {}
+ virtual gfx::ScreenType GetScreenTypeForNativeView(
+ gfx::NativeView view) OVERRIDE {
+ return chrome::IsNativeViewInAsh(view) ?
+ gfx::SCREEN_TYPE_ALTERNATE :
+ gfx::SCREEN_TYPE_NATIVE;
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenTypeDelegateDesktop);
+};
+#endif
+
+class SigninErrorNotifierTest : public AshTestBase {
+ public:
+ virtual void SetUp() OVERRIDE {
+ views::ViewsDelegate::views_delegate = &views_delegate_;
+
+ // Create a signed-in profile.
+ profile_.reset(new TestingProfile());
+ profile_->set_profile_name(kTestAccountId);
+
+ SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile_.get(), FakeSigninManagerBase::Build);
+
+ profile_manager_.reset(
+ new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
+ ASSERT_TRUE(profile_manager_->SetUp());
+
+ TestingBrowserProcess::GetGlobal();
+ AshTestBase::SetUp();
+
+ // Set up screen for Windows.
+#if !defined(OS_CHROMEOS)
+ aura::TestScreen* test_screen = aura::TestScreen::Create();
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen);
+ gfx::Screen::SetScreenTypeDelegate(new ScreenTypeDelegateDesktop);
+#endif
+
+ error_controller_ =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())->
+ signin_error_controller();
+ SigninErrorNotifierFactory::GetForProfile(profile_.get());
+ notification_ui_manager_ = g_browser_process->notification_ui_manager();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ profile_manager_.reset();
+
+ AshTestBase::TearDown();
+ }
+
+ protected:
+ void GetMessage(base::string16* message) {
+ const Notification* notification =
+ g_browser_process->notification_ui_manager()->FindById(kNotificationId);
+ ASSERT_FALSE(notification == NULL);
+ *message = notification->message();
+ }
+
+ scoped_ptr<TestingProfileManager> profile_manager_;
+ scoped_ptr<TestingProfile> profile_;
+ SigninErrorController* error_controller_;
+ NotificationUIManager* notification_ui_manager_;
+ TestViewsDelegateWithParent views_delegate_;
+};
+
+TEST_F(SigninErrorNotifierTest, NoErrorAuthStatusProviders) {
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+ {
+ // Add a provider (removes itself on exiting this scope).
+ FakeAuthStatusProvider provider(error_controller_);
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+ }
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+}
+
+TEST_F(SigninErrorNotifierTest, ErrorAuthStatusProvider) {
+ {
+ FakeAuthStatusProvider provider(error_controller_);
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+ {
+ FakeAuthStatusProvider error_provider(error_controller_);
+ LOG(ERROR) << "Setting auth error";
+ error_provider.SetAuthError(kTestAccountId, GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_TRUE(notification_ui_manager_->FindById(kNotificationId));
+ }
+ // error_provider is removed now that we've left that scope.
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+ }
+ // All providers should be removed now.
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+}
+
+TEST_F(SigninErrorNotifierTest, AuthStatusProviderErrorTransition) {
+ {
+ FakeAuthStatusProvider provider0(error_controller_);
+ FakeAuthStatusProvider provider1(error_controller_);
+ provider0.SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_TRUE(notification_ui_manager_->FindById(kNotificationId));
+
+ base::string16 message;
+ GetMessage(&message);
+ ASSERT_FALSE(message.empty());
+
+ // Now set another auth error and clear the original.
+ provider1.SetAuthError(
+ kTestAccountId,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
+ provider0.SetAuthError(
+ kTestAccountId, GoogleServiceAuthError::AuthErrorNone());
+
+ ASSERT_TRUE(notification_ui_manager_->FindById(kNotificationId));
+
+ base::string16 new_message;
+ GetMessage(&new_message);
+ ASSERT_FALSE(new_message.empty());
+
+ ASSERT_NE(new_message, message);
+
+ provider1.SetAuthError(
+ kTestAccountId, GoogleServiceAuthError::AuthErrorNone());
+ ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
+ }
+}
+
+// Verify that SigninErrorNotifier ignores certain errors.
+TEST_F(SigninErrorNotifierTest, AuthStatusEnumerateAllErrors) {
+ typedef struct {
+ GoogleServiceAuthError::State error_state;
+ bool is_error;
+ } ErrorTableEntry;
+
+ ErrorTableEntry table[] = {
+ { GoogleServiceAuthError::NONE, false },
+ { GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true },
+ { GoogleServiceAuthError::USER_NOT_SIGNED_UP, true },
+ { GoogleServiceAuthError::CONNECTION_FAILED, false },
+ { GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
+ { GoogleServiceAuthError::ACCOUNT_DELETED, true },
+ { GoogleServiceAuthError::ACCOUNT_DISABLED, true },
+ { GoogleServiceAuthError::SERVICE_UNAVAILABLE, true },
+ { GoogleServiceAuthError::TWO_FACTOR, true },
+ { GoogleServiceAuthError::REQUEST_CANCELED, true },
+ { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true },
+ { GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
+ { GoogleServiceAuthError::SERVICE_ERROR, true },
+ };
+ COMPILE_ASSERT(ARRAYSIZE_UNSAFE(table) == GoogleServiceAuthError::NUM_STATES,
+ kTable_size_does_not_match_number_of_auth_error_types);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(table); ++i) {
+ FakeAuthStatusProvider provider(error_controller_);
+ provider.SetAuthError(kTestAccountId,
+ GoogleServiceAuthError(table[i].error_state));
+ const Notification* notification = notification_ui_manager_->
+ FindById(kNotificationId);
+ ASSERT_EQ(table[i].is_error, notification != NULL);
+ if (table[i].is_error) {
+ EXPECT_FALSE(notification->title().empty());
+ EXPECT_FALSE(notification->message().empty());
+ EXPECT_EQ((size_t)1, notification->buttons().size());
+ }
+ }
+}
+
+} // namespace test
+} // namespace ash
diff --git a/chrome/browser/signin/signin_error_notifier_factory_ash.cc b/chrome/browser/signin/signin_error_notifier_factory_ash.cc
new file mode 100644
index 0000000..b22a27c
--- /dev/null
+++ b/chrome/browser/signin/signin_error_notifier_factory_ash.cc
@@ -0,0 +1,48 @@
+// 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 "chrome/browser/signin/signin_error_notifier_factory_ash.h"
+
+#include "ash/shell.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_notifier_ash.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+SigninErrorNotifierFactory::SigninErrorNotifierFactory()
+ : BrowserContextKeyedServiceFactory(
+ "SigninErrorNotifier",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
+}
+
+SigninErrorNotifierFactory::~SigninErrorNotifierFactory() {}
+
+// static
+SigninErrorNotifier* SigninErrorNotifierFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<SigninErrorNotifier*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+SigninErrorNotifierFactory* SigninErrorNotifierFactory::GetInstance() {
+ return Singleton<SigninErrorNotifierFactory>::get();
+}
+
+BrowserContextKeyedService* SigninErrorNotifierFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ if (!ash::Shell::HasInstance())
+ return NULL;
+
+ Profile* profile = static_cast<Profile*>(context);
+
+ SigninErrorController* controller =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller();
+
+ return new SigninErrorNotifier(controller, profile);
+}
diff --git a/chrome/browser/signin/signin_error_notifier_factory_ash.h b/chrome/browser/signin/signin_error_notifier_factory_ash.h
new file mode 100644
index 0000000..4320a5c
--- /dev/null
+++ b/chrome/browser/signin/signin_error_notifier_factory_ash.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_FACTORY_ASH_H_
+#define CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_FACTORY_ASH_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+class SigninErrorNotifier;
+class Profile;
+
+// Singleton that owns all SigninErrorNotifiers and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated SigninErrorNotifier.
+class SigninErrorNotifierFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the instance of SigninErrorNotifier associated with this
+ // profile, creating one if none exists and the shell exists.
+ static SigninErrorNotifier* GetForProfile(Profile* profile);
+
+ // Returns an instance of the SigninErrorNotifierFactory singleton.
+ static SigninErrorNotifierFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<SigninErrorNotifierFactory>;
+
+ SigninErrorNotifierFactory();
+ virtual ~SigninErrorNotifierFactory();
+
+ // BrowserContextKeyedServiceFactory:
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninErrorNotifierFactory);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_SIGNIN_ERROR_NOTIFIER_FACTORY_ASH_H_
diff --git a/chrome/browser/signin/signin_global_error.cc b/chrome/browser/signin/signin_global_error.cc
index ebba063..654e549 100644
--- a/chrome/browser/signin/signin_global_error.cc
+++ b/chrome/browser/signin/signin_global_error.cc
@@ -5,11 +5,8 @@
#include "chrome/browser/signin/signin_global_error.h"
#include "base/logging.h"
-#include "base/prefs/pref_service.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/profile_oauth2_token_service.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_promo.h"
@@ -20,79 +17,34 @@
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/webui/signin/login_ui_service.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/url_util.h"
#include "ui/base/l10n/l10n_util.h"
-SigninGlobalError::SigninGlobalError(Profile* profile)
- : auth_error_(GoogleServiceAuthError::AuthErrorNone()), profile_(profile) {
+SigninGlobalError::SigninGlobalError(
+ SigninErrorController* error_controller,
+ Profile* profile)
+ : profile_(profile),
+ error_controller_(error_controller) {
+ error_controller_->AddObserver(this);
+ GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(this);
}
SigninGlobalError::~SigninGlobalError() {
- DCHECK(provider_set_.empty())
- << "All AuthStatusProviders should be unregistered before"
- << " SigninManager::Shutdown() is called";
+ DCHECK(!error_controller_)
+ << "SigninGlobalError::Shutdown() was not called";
}
-void SigninGlobalError::AddProvider(const AuthStatusProvider* provider) {
- DCHECK(provider_set_.find(provider) == provider_set_.end())
- << "Adding same AuthStatusProvider multiple times";
- provider_set_.insert(provider);
- AuthStatusChanged();
-}
-
-void SigninGlobalError::RemoveProvider(const AuthStatusProvider* provider) {
- std::set<const AuthStatusProvider*>::iterator iter =
- provider_set_.find(provider);
- DCHECK(iter != provider_set_.end())
- << "Removing provider that was never added";
- provider_set_.erase(iter);
- AuthStatusChanged();
-}
-
-SigninGlobalError::AuthStatusProvider::AuthStatusProvider() {
-}
-
-SigninGlobalError::AuthStatusProvider::~AuthStatusProvider() {
-}
-
-void SigninGlobalError::AuthStatusChanged() {
- // Walk all of the status providers and collect any error.
- GoogleServiceAuthError current_error(GoogleServiceAuthError::AuthErrorNone());
- std::string current_account_id;
- for (std::set<const AuthStatusProvider*>::const_iterator it =
- provider_set_.begin(); it != provider_set_.end(); ++it) {
- current_account_id = (*it)->GetAccountId();
- current_error = (*it)->GetAuthStatus();
-
- // Break out if any provider reports an error (ignoring ordinary network
- // errors, which are not surfaced to the user). This logic may eventually
- // need to be extended to prioritize different auth errors, but for now
- // all auth errors are treated the same.
- if (current_error.state() != GoogleServiceAuthError::NONE &&
- current_error.state() != GoogleServiceAuthError::CONNECTION_FAILED) {
- break;
- }
- }
- if (current_error.state() != auth_error_.state() ||
- account_id_ != current_account_id) {
- auth_error_ = current_error;
- if (auth_error_.state() == GoogleServiceAuthError::NONE) {
- account_id_.clear();
- } else {
- account_id_ = current_account_id;
- }
-
- GlobalErrorServiceFactory::GetForProfile(profile_)->NotifyErrorsChanged(
- this);
- }
+void SigninGlobalError::Shutdown() {
+ GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(this);
+ error_controller_->RemoveObserver(this);
+ error_controller_ = NULL;
}
bool SigninGlobalError::HasMenuItem() {
- return !MenuItemLabel().empty();
+ return error_controller_->HasError();
}
int SigninGlobalError::MenuItemCommandID() {
@@ -100,21 +52,16 @@ int SigninGlobalError::MenuItemCommandID() {
}
base::string16 SigninGlobalError::MenuItemLabel() {
- if (account_id_.empty() ||
- auth_error_.state() == GoogleServiceAuthError::NONE ||
- auth_error_.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
- // If the user isn't signed in, or there's no auth error worth elevating to
- // the user, don't display any menu item.
- return base::string16();
- } else {
- // There's an auth error the user should know about - notify the user.
+ // Notify the user if there's an auth error the user should know about.
+ if (error_controller_->HasError())
return l10n_util::GetStringUTF16(IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM);
- }
+ return base::string16();
}
void SigninGlobalError::ExecuteMenuItem(Browser* browser) {
#if defined(OS_CHROMEOS)
- if (auth_error_.state() != GoogleServiceAuthError::NONE) {
+ if (error_controller_->auth_error().state() !=
+ GoogleServiceAuthError::NONE) {
DVLOG(1) << "Signing out the user to fix a sync error.";
// TODO(beng): seems like this could just call chrome::AttemptUserExit().
chrome::ExecuteCommand(browser, IDC_EXIT);
@@ -130,8 +77,9 @@ void SigninGlobalError::ExecuteMenuItem(Browser* browser) {
return;
}
- chrome::ShowSingletonTab(browser, signin::GetReauthURL(profile_,
- account_id_));
+ chrome::ShowSingletonTab(
+ browser,
+ signin::GetReauthURL(profile_, error_controller_->error_account_id()));
#endif
}
@@ -155,13 +103,10 @@ std::vector<base::string16> SigninGlobalError::GetBubbleViewMessages() {
return messages;
}
- switch (auth_error_.state()) {
- // In the case of no error, or a simple network error, don't bother
- // displaying a popup bubble.
- case GoogleServiceAuthError::CONNECTION_FAILED:
- case GoogleServiceAuthError::NONE:
- return messages;
+ if (!error_controller_->HasError())
+ return messages;
+ switch (error_controller_->auth_error().state()) {
// TODO(rogerta): use account id in error messages.
// User credentials are invalid (bad acct, etc).
@@ -188,9 +133,10 @@ std::vector<base::string16> SigninGlobalError::GetBubbleViewMessages() {
}
base::string16 SigninGlobalError::GetBubbleViewAcceptButtonLabel() {
- // If the service is unavailable, don't give the user the option to try
+ // If the auth service is unavailable, don't give the user the option to try
// signing in again.
- if (auth_error_.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
+ if (error_controller_->auth_error().state() ==
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
return l10n_util::GetStringUTF16(
IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_ACCEPT);
} else {
@@ -213,8 +159,6 @@ void SigninGlobalError::BubbleViewCancelButtonPressed(Browser* browser) {
NOTREACHED();
}
-// static
-SigninGlobalError* SigninGlobalError::GetForProfile(Profile* profile) {
- return ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
- signin_global_error();
+void SigninGlobalError::OnErrorChanged() {
+ GlobalErrorServiceFactory::GetForProfile(profile_)->NotifyErrorsChanged(this);
}
diff --git a/chrome/browser/signin/signin_global_error.h b/chrome/browser/signin/signin_global_error.h
index b68b1be..ab71b8b 100644
--- a/chrome/browser/signin/signin_global_error.h
+++ b/chrome/browser/signin/signin_global_error.h
@@ -8,50 +8,25 @@
#include <set>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/ui/global_error/global_error.h"
-#include "google_apis/gaia/google_service_auth_error.h"
+#include "components/keyed_service/core/keyed_service.h"
class Profile;
-// Shows auth errors on the wrench menu using a bubble view and a
-// menu item. Services that wish to expose auth errors to the user should
-// register an AuthStatusProvider to report their current authentication state,
-// and should invoke AuthStatusChanged() when their authentication state may
-// have changed.
-class SigninGlobalError : public GlobalErrorWithStandardBubble {
+// Shows auth errors on the wrench menu using a bubble view and a menu item.
+class SigninGlobalError : public GlobalErrorWithStandardBubble,
+ public SigninErrorController::Observer,
+ public KeyedService {
public:
- class AuthStatusProvider {
- public:
- AuthStatusProvider();
- virtual ~AuthStatusProvider();
-
- // Returns the account id with the status specified by GetAuthStatus().
- virtual std::string GetAccountId() const = 0;
-
- // API invoked by SigninGlobalError to get the current auth status of
- // the various signed in services.
- virtual GoogleServiceAuthError GetAuthStatus() const = 0;
- };
-
- explicit SigninGlobalError(Profile* profile);
+ SigninGlobalError(SigninErrorController* error_controller,
+ Profile* profile);
virtual ~SigninGlobalError();
- // Adds a provider which the SigninGlobalError object will start querying for
- // auth status.
- void AddProvider(const AuthStatusProvider* provider);
-
- // Removes a provider previously added by SigninGlobalError (generally only
- // called in preparation for shutdown).
- void RemoveProvider(const AuthStatusProvider* provider);
-
- // Invoked when the auth status of an AuthStatusProvider has changed.
- void AuthStatusChanged();
+ // KeyedService:
+ virtual void Shutdown() OVERRIDE;
- std::string GetAccountIdOfLastAuthError() const { return account_id_; }
-
- GoogleServiceAuthError GetLastAuthError() const { return auth_error_; }
-
- // GlobalError implementation.
+ // GlobalErrorWithStandardBubble:
virtual bool HasMenuItem() OVERRIDE;
virtual int MenuItemCommandID() OVERRIDE;
virtual base::string16 MenuItemLabel() OVERRIDE;
@@ -65,21 +40,17 @@ class SigninGlobalError : public GlobalErrorWithStandardBubble {
virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
- // Returns the SigninGlobalError instance for the given profile.
- static SigninGlobalError* GetForProfile(Profile* profile);
+ // SigninErrorController::Observer:
+ virtual void OnErrorChanged() OVERRIDE;
private:
- std::set<const AuthStatusProvider*> provider_set_;
-
- // The account that generated the last auth error.
- std::string account_id_;
+ // The Profile this service belongs to.
+ Profile* profile_;
- // The auth error detected the last time AuthStatusChanged() was invoked (or
- // NONE if AuthStatusChanged() has never been invoked).
- GoogleServiceAuthError auth_error_;
+ // The SigninErrorController that provides auth status.
+ SigninErrorController* error_controller_;
- // The Profile this object belongs to.
- Profile* profile_;
+ DISALLOW_COPY_AND_ASSIGN(SigninGlobalError);
};
#endif // CHROME_BROWSER_SIGNIN_SIGNIN_GLOBAL_ERROR_H_
diff --git a/chrome/browser/signin/signin_global_error_factory.cc b/chrome/browser/signin/signin_global_error_factory.cc
new file mode 100644
index 0000000..2396937
--- /dev/null
+++ b/chrome/browser/signin/signin_global_error_factory.cc
@@ -0,0 +1,55 @@
+// 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 "chrome/browser/signin/signin_global_error_factory.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+#if defined(USE_ASH)
+#include "ash/shell.h"
+#endif
+
+SigninGlobalErrorFactory::SigninGlobalErrorFactory()
+ : BrowserContextKeyedServiceFactory(
+ "SigninGlobalError",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
+ DependsOn(GlobalErrorServiceFactory::GetInstance());
+}
+
+SigninGlobalErrorFactory::~SigninGlobalErrorFactory() {}
+
+// static
+SigninGlobalError* SigninGlobalErrorFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<SigninGlobalError*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+SigninGlobalErrorFactory* SigninGlobalErrorFactory::GetInstance() {
+ return Singleton<SigninGlobalErrorFactory>::get();
+}
+
+KeyedService* SigninGlobalErrorFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+#if defined(USE_ASH)
+ if (ash::Shell::HasInstance())
+ return NULL;
+#endif
+
+ Profile* profile = static_cast<Profile*>(context);
+
+ SigninErrorController* controller =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller();
+
+ return new SigninGlobalError(controller, profile);
+}
diff --git a/chrome/browser/signin/signin_global_error_factory.h b/chrome/browser/signin/signin_global_error_factory.h
new file mode 100644
index 0000000..26e9b19
--- /dev/null
+++ b/chrome/browser/signin/signin_global_error_factory.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_GLOBAL_ERROR_FACTORY_H_
+#define CHROME_BROWSER_SIGNIN_SIGNIN_GLOBAL_ERROR_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class SigninGlobalError;
+class Profile;
+
+// Singleton that owns all SigninGlobalErrors and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated SigninGlobalError.
+class SigninGlobalErrorFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ // Returns the instance of SigninGlobalError associated with this
+ // profile, creating one if none exists. In Ash, this will return NULL.
+ static SigninGlobalError* GetForProfile(Profile* profile);
+
+ // Returns an instance of the SigninGlobalErrorFactory singleton.
+ static SigninGlobalErrorFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<SigninGlobalErrorFactory>;
+
+ SigninGlobalErrorFactory();
+ virtual ~SigninGlobalErrorFactory();
+
+ // BrowserContextKeyedServiceFactory:
+ virtual KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninGlobalErrorFactory);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_SIGNIN_GLOBAL_ERROR_FACTORY_H_
diff --git a/chrome/browser/signin/signin_global_error_unittest.cc b/chrome/browser/signin/signin_global_error_unittest.cc
index 8a9e61e..9284e68 100644
--- a/chrome/browser/signin/signin_global_error_unittest.cc
+++ b/chrome/browser/signin/signin_global_error_unittest.cc
@@ -11,6 +11,8 @@
#include "chrome/browser/signin/fake_profile_oauth2_token_service_wrapper.h"
#include "chrome/browser/signin/fake_signin_manager.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
+#include "chrome/browser/signin/signin_global_error_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/global_error/global_error_service.h"
@@ -21,7 +23,6 @@
#include "testing/gtest/include/gtest/gtest.h"
static const char kTestAccountId[] = "testuser@test.com";
-static const char kOtherTestAccountId[] = "otheruser@test.com";
class SigninGlobalErrorTest : public testing::Test {
public:
@@ -33,111 +34,54 @@ class SigninGlobalErrorTest : public testing::Test {
builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
FakeSigninManagerBase::Build);
profile_ = builder.Build();
- SigninManagerFactory::GetForProfile(profile_.get());
+
profile_->GetPrefs()->SetString(
prefs::kGoogleServicesUsername, kTestAccountId);
SigninManagerFactory::GetForProfile(profile_.get())
->SetAuthenticatedUsername(kTestAccountId);
- global_error_ = SigninGlobalError::GetForProfile(profile_.get());
+
+ global_error_ = SigninGlobalErrorFactory::GetForProfile(profile_.get());
+ error_controller_ = ProfileOAuth2TokenServiceFactory::GetForProfile(
+ profile_.get())->signin_error_controller();
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestingProfile> profile_;
SigninGlobalError* global_error_;
+ SigninErrorController* error_controller_;
};
-TEST_F(SigninGlobalErrorTest, NoAuthStatusProviders) {
+TEST_F(SigninGlobalErrorTest, NoErrorAuthStatusProviders) {
+ scoped_ptr<FakeAuthStatusProvider> provider;
+
ASSERT_FALSE(global_error_->HasMenuItem());
-}
-TEST_F(SigninGlobalErrorTest, NoErrorAuthStatusProviders) {
- {
- // Add a provider (removes itself on exiting this scope).
- FakeAuthStatusProvider provider(global_error_);
- ASSERT_FALSE(global_error_->HasMenuItem());
- }
+ // Add a provider.
+ provider.reset(new FakeAuthStatusProvider(error_controller_));
+ ASSERT_FALSE(global_error_->HasMenuItem());
+
+ // Remove the provider.
+ provider.reset();
ASSERT_FALSE(global_error_->HasMenuItem());
}
TEST_F(SigninGlobalErrorTest, ErrorAuthStatusProvider) {
- {
- FakeAuthStatusProvider provider(global_error_);
- ASSERT_FALSE(global_error_->HasMenuItem());
- {
- FakeAuthStatusProvider error_provider(global_error_);
- error_provider.SetAuthError(kTestAccountId, GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- ASSERT_TRUE(global_error_->HasMenuItem());
- }
- // error_provider is removed now that we've left that scope.
- ASSERT_FALSE(global_error_->HasMenuItem());
- }
- // All providers should be removed now.
+ scoped_ptr<FakeAuthStatusProvider> provider;
+ scoped_ptr<FakeAuthStatusProvider> error_provider;
+
+ provider.reset(new FakeAuthStatusProvider(error_controller_));
ASSERT_FALSE(global_error_->HasMenuItem());
-}
-TEST_F(SigninGlobalErrorTest, AuthStatusProviderErrorTransition) {
- {
- FakeAuthStatusProvider provider0(global_error_);
- FakeAuthStatusProvider provider1(global_error_);
- ASSERT_FALSE(global_error_->HasMenuItem());
- provider0.SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- ASSERT_TRUE(global_error_->HasMenuItem());
- provider1.SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED));
- ASSERT_TRUE(global_error_->HasMenuItem());
-
- // Now resolve the auth errors - the menu item should go away.
- provider0.SetAuthError(kTestAccountId,
- GoogleServiceAuthError::AuthErrorNone());
- ASSERT_TRUE(global_error_->HasMenuItem());
- provider1.SetAuthError(kTestAccountId,
- GoogleServiceAuthError::AuthErrorNone());
- ASSERT_FALSE(global_error_->HasMenuItem());
- }
+ error_provider.reset(new FakeAuthStatusProvider(error_controller_));
+ error_provider->SetAuthError(kTestAccountId, GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ ASSERT_TRUE(global_error_->HasMenuItem());
+
+ error_provider.reset();
ASSERT_FALSE(global_error_->HasMenuItem());
-}
-TEST_F(SigninGlobalErrorTest, AuthStatusProviderAccountTransition) {
- {
- FakeAuthStatusProvider provider0(global_error_);
- FakeAuthStatusProvider provider1(global_error_);
- ASSERT_FALSE(global_error_->HasMenuItem());
-
- provider0.SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- provider1.SetAuthError(
- kOtherTestAccountId,
- GoogleServiceAuthError(GoogleServiceAuthError::NONE));
- ASSERT_TRUE(global_error_->HasMenuItem());
- ASSERT_STREQ(kTestAccountId,
- global_error_->GetAccountIdOfLastAuthError().c_str());
-
- // Swap providers reporting errors.
- provider1.set_error_without_status_change(
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- provider0.set_error_without_status_change(
- GoogleServiceAuthError(GoogleServiceAuthError::NONE));
- global_error_->AuthStatusChanged();
- ASSERT_TRUE(global_error_->HasMenuItem());
- ASSERT_STREQ(kOtherTestAccountId,
- global_error_->GetAccountIdOfLastAuthError().c_str());
-
- // Now resolve the auth errors - the menu item should go away.
- provider0.set_error_without_status_change(
- GoogleServiceAuthError::AuthErrorNone());
- provider1.set_error_without_status_change(
- GoogleServiceAuthError::AuthErrorNone());
- global_error_->AuthStatusChanged();
- ASSERT_FALSE(global_error_->HasMenuItem());
- }
+ provider.reset();
+ error_provider.reset();
ASSERT_FALSE(global_error_->HasMenuItem());
}
@@ -167,13 +111,10 @@ TEST_F(SigninGlobalErrorTest, AuthStatusEnumerateAllErrors) {
kTable_size_does_not_match_number_of_auth_error_types);
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(table); ++i) {
- FakeAuthStatusProvider provider(global_error_);
+ FakeAuthStatusProvider provider(error_controller_);
provider.SetAuthError(kTestAccountId,
GoogleServiceAuthError(table[i].error_state));
- EXPECT_EQ(global_error_->HasMenuItem(), table[i].is_error);
- // Only on chromeos do we have a separate menu item - on other platforms
- // there's code in WrenchMenuModel to re-use the "sign in to chrome"
- // menu item to display auth status/errors.
+
EXPECT_EQ(global_error_->HasMenuItem(), table[i].is_error);
EXPECT_EQ(global_error_->MenuItemLabel().empty(), !table[i].is_error);
EXPECT_EQ(global_error_->GetBubbleViewMessages().empty(),
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index f22ec8e..e567165 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -21,7 +21,6 @@
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_account_id_helper.h"
-#include "chrome/browser/signin/signin_global_error.h"
#include "chrome/browser/signin/signin_internals_util.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/global_error/global_error_service.h"
diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h
index a0e5622..4fef21b 100644
--- a/chrome/browser/signin/signin_manager.h
+++ b/chrome/browser/signin/signin_manager.h
@@ -46,7 +46,6 @@ class GaiaAuthFetcher;
class ProfileIOData;
class PrefService;
class SigninAccountIdHelper;
-class SigninGlobalError;
class SigninClient;
class SigninManager : public SigninManagerBase,
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 314f67b..aee3bb9 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -7,7 +7,10 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_global_error_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -37,11 +40,16 @@ GlobalError* GetSignedInServiceError(Profile* profile) {
std::vector<GlobalError*> GetSignedInServiceErrors(Profile* profile) {
std::vector<GlobalError*> errors;
+ // On Chrome OS, we don't use SigninGlobalError. Other platforms use
+ // SigninGlobalError to show sign-in errors in the toolbar menu.
+#if !defined(OS_CHROMEOS)
// Auth errors have the highest priority - after that, individual service
// errors.
- SigninGlobalError* signin_error = SigninGlobalError::GetForProfile(profile);
+ SigninGlobalError* signin_error =
+ SigninGlobalErrorFactory::GetForProfile(profile);
if (signin_error && signin_error->HasMenuItem())
errors.push_back(signin_error);
+#endif
// No auth error - now try other services. Currently the list is just hard-
// coded but in the future if we add more we can create some kind of
@@ -98,7 +106,8 @@ void GetStatusLabelsForAuthError(Profile* profile,
link_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_RELOGIN_LINK_LABEL));
const GoogleServiceAuthError::State state =
- SigninGlobalError::GetForProfile(profile)->GetLastAuthError().state();
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller()->auth_error().state();
switch (state) {
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
case GoogleServiceAuthError::SERVICE_ERROR:
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index ccdf8d0..9c3c037 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -11,7 +11,9 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager_base.h"
#include "chrome/browser/signin/signin_ui_util.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -169,8 +171,8 @@ MessageType GetStatusInfo(ProfileSyncService* service,
if (service) {
// Since there is no auth in progress, check for an auth error first.
AuthError auth_error =
- SigninGlobalError::GetForProfile(service->profile())->
- GetLastAuthError();
+ ProfileOAuth2TokenServiceFactory::GetForProfile(service->profile())->
+ signin_error_controller()->auth_error();
if (auth_error.state() != AuthError::NONE) {
if (status_label && link_label)
signin_ui_util::GetStatusLabelsForAuthError(
@@ -232,8 +234,8 @@ MessageType GetStatusInfo(ProfileSyncService* service,
ProfileSyncService::Status status;
service->QueryDetailedSyncStatus(&status);
AuthError auth_error =
- SigninGlobalError::GetForProfile(
- service->profile())->GetLastAuthError();
+ ProfileOAuth2TokenServiceFactory::GetForProfile(service->profile())->
+ signin_error_controller()->auth_error();
if (status_label) {
status_label->assign(
l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS));
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index 7728606..1fb6ee6 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -8,6 +8,8 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/fake_auth_status_provider.h"
#include "chrome/browser/signin/fake_signin_manager.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/sync/profile_sync_service_mock.h"
#include "chrome/browser/sync/sync_ui_util.h"
@@ -88,6 +90,7 @@ TEST_F(SyncUIUtilTest, PassphraseGlobalError) {
.WillRepeatedly(Return(true));
EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
.WillRepeatedly(Return(true));
+
VerifySyncGlobalErrorResult(
&service, signin, GoogleServiceAuthError::NONE, true, true);
}
@@ -331,9 +334,9 @@ TEST_F(SyncUIUtilTest, DistinctCasesReportUniqueMessageSets) {
EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
FakeSigninManagerForSyncUIUtilTest signin(profile.get());
signin.SetAuthenticatedUsername(kTestUser);
- scoped_ptr<FakeAuthStatusProvider> provider(
- new FakeAuthStatusProvider(
- SigninGlobalError::GetForProfile(profile.get())));
+ scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get())->
+ signin_error_controller()));
GetDistinctCase(service, &signin, provider.get(), idx);
base::string16 status_label;
base::string16 link_label;
@@ -371,9 +374,9 @@ TEST_F(SyncUIUtilTest, HtmlNotIncludedInStatusIfNotRequested) {
EXPECT_CALL(service, GetAuthError()).WillRepeatedly(ReturnRef(error));
FakeSigninManagerForSyncUIUtilTest signin(profile.get());
signin.SetAuthenticatedUsername(kTestUser);
- scoped_ptr<FakeAuthStatusProvider> provider(
- new FakeAuthStatusProvider(
- SigninGlobalError::GetForProfile(profile.get())));
+ scoped_ptr<FakeAuthStatusProvider> provider(new FakeAuthStatusProvider(
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get())->
+ signin_error_controller()));
GetDistinctCase(service, &signin, provider.get(), idx);
base::string16 status_label;
base::string16 link_label;
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index ed0a0f0..39ba0d3 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -22,7 +22,10 @@
#include "chrome/browser/chromeos/display/display_preferences.h"
#include "chrome/browser/chromeos/extensions/media_player_api.h"
#include "chrome/browser/chromeos/extensions/media_player_event_router.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h"
#include "chrome/browser/ui/ash/session_state_delegate_chromeos.h"
@@ -268,9 +271,16 @@ void ChromeShellDelegate::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
- case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED:
+ case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED: {
+ Profile* profile = content::Details<Profile>(details).ptr();
+ if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
+ !profile->IsGuestSession() && !profile->IsManaged()) {
+ // Start the error notifier service to show auth notifications.
+ SigninErrorNotifierFactory::GetForProfile(profile);
+ }
ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
break;
+ }
case chrome::NOTIFICATION_SESSION_STARTED:
InitAfterSessionStart();
ash::Shell::GetInstance()->ShowShelf();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
index 883bb75..be2e38d 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_views.cc
@@ -13,7 +13,9 @@
#include "chrome/browser/accessibility/accessibility_events.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
#include "chrome/browser/ui/ash/chrome_new_window_delegate.h"
#include "chrome/browser/ui/ash/session_state_delegate_views.h"
#include "chrome/browser/ui/browser.h"
@@ -194,6 +196,10 @@ void ChromeShellDelegate::Observe(int type,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_ASH_SESSION_STARTED: {
+ Profile* profile = ProfileManager::GetActiveUserProfile();
+ // Start the error notifier service to show auth notifications.
+ SigninErrorNotifierFactory::GetForProfile(profile);
+
#if defined(OS_WIN)
// If we are launched to service a windows 8 search request then let the
// IPC which carries the search string create the browser and initiate
@@ -219,7 +225,7 @@ void ChromeShellDelegate::Observe(int type,
dummy,
chrome::startup::IS_NOT_FIRST_RUN);
startup_impl.Launch(
- ProfileManager::GetActiveUserProfile(),
+ profile,
std::vector<GURL>(),
true,
chrome::HOST_DESKTOP_TYPE_ASH);
@@ -232,7 +238,7 @@ void ChromeShellDelegate::Observe(int type,
}
chrome::ScopedTabbedBrowserDisplayer displayer(
- ProfileManager::GetActiveUserProfile(),
+ profile,
chrome::HOST_DESKTOP_TYPE_ASH);
chrome::AddTabAt(displayer.browser(), GURL(), -1, true);
}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index e104fc1..a17509e 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/ash/test_views_delegate_with_parent.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
@@ -64,7 +65,6 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/test_utils.h"
#include "ui/aura/window.h"
-#include "ui/views/test/test_views_delegate.h"
#endif
using base::ASCIIToUTF16;
@@ -684,27 +684,6 @@ scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow(
return browser_window.Pass();
}
-// A views delegate which allows creating app windows.
-class TestViewsDelegateForAppTest : public views::TestViewsDelegate {
- public:
- TestViewsDelegateForAppTest() {}
- virtual ~TestViewsDelegateForAppTest() {}
-
- // views::TestViewsDelegate overrides.
- virtual void OnBeforeWidgetInit(
- views::Widget::InitParams* params,
- views::internal::NativeWidgetDelegate* delegate) OVERRIDE {
- if (!params->parent && !params->context) {
- // If the window has neither a parent nor a context we add the root window
- // as parent.
- params->parent = ash::Shell::GetInstance()->GetPrimaryRootWindow();
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestViewsDelegateForAppTest);
-};
-
// Watches WebContents and blocks until it is destroyed. This is needed for
// the destruction of a V2 application.
class WebContentsDestroyedWatcher : public content::WebContentsObserver {
@@ -947,7 +926,7 @@ class MultiProfileMultiBrowserShelfLayoutChromeLauncherControllerTest
}
virtual views::ViewsDelegate* CreateViewsDelegate() OVERRIDE {
- return new TestViewsDelegateForAppTest;
+ return new TestViewsDelegateWithParent;
}
private:
diff --git a/chrome/browser/ui/ash/test_views_delegate_with_parent.cc b/chrome/browser/ui/ash/test_views_delegate_with_parent.cc
new file mode 100644
index 0000000..27feacb
--- /dev/null
+++ b/chrome/browser/ui/ash/test_views_delegate_with_parent.cc
@@ -0,0 +1,23 @@
+// 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 "chrome/browser/ui/ash/test_views_delegate_with_parent.h"
+
+#include "ash/shell.h"
+
+TestViewsDelegateWithParent::TestViewsDelegateWithParent() {
+}
+
+TestViewsDelegateWithParent::~TestViewsDelegateWithParent() {
+}
+
+void TestViewsDelegateWithParent::OnBeforeWidgetInit(
+ views::Widget::InitParams* params,
+ views::internal::NativeWidgetDelegate* delegate) {
+ if (!params->parent && !params->context) {
+ // If the window has neither a parent nor a context we add the root window
+ // as parent.
+ params->parent = ash::Shell::GetInstance()->GetPrimaryRootWindow();
+ }
+}
diff --git a/chrome/browser/ui/ash/test_views_delegate_with_parent.h b/chrome/browser/ui/ash/test_views_delegate_with_parent.h
new file mode 100644
index 0000000..f876c73
--- /dev/null
+++ b/chrome/browser/ui/ash/test_views_delegate_with_parent.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_ASH_TEST_VIEWS_DELEGATE_WITH_PARENT_H_
+#define CHROME_BROWSER_UI_ASH_TEST_VIEWS_DELEGATE_WITH_PARENT_H_
+
+#include "ui/views/test/test_views_delegate.h"
+
+// A views delegate which allows creating shell windows.
+class TestViewsDelegateWithParent : public views::TestViewsDelegate {
+ public:
+ TestViewsDelegateWithParent();
+ virtual ~TestViewsDelegateWithParent();
+
+ // views::TestViewsDelegate overrides.
+ virtual void OnBeforeWidgetInit(
+ views::Widget::InitParams* params,
+ views::internal::NativeWidgetDelegate* delegate) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestViewsDelegateWithParent);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_TEST_VIEWS_DELEGATE_WITH_PARENT_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index 8611ec6..40fee0c 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -13,13 +13,14 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/signin/fake_auth_status_provider.h"
#include "chrome/browser/signin/fake_signin_manager.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync/profile_sync_service_mock.h"
-#include "chrome/browser/sync/sync_global_error.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
@@ -688,7 +689,9 @@ TEST_F(BrowserWindowControllerTest, TestSigninMenuItemAuthError) {
ProfileSyncServiceFactory::GetForProfile(profile());
sync->SetSyncSetupCompleted();
// Force an auth error.
- FakeAuthStatusProvider provider(SigninGlobalError::GetForProfile(profile()));
+ FakeAuthStatusProvider provider(
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile())->
+ signin_error_controller());
GoogleServiceAuthError error(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
provider.SetAuthError("user@gmail.com", error);
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 75f129f..162cb0c 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -36,7 +36,9 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/signin/chrome_signin_client.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_names_io_thread.h"
@@ -1418,9 +1420,13 @@ void OneClickSigninHelper::DidStopLoading(
// sync was already setup, simply navigate back to the settings page.
ProfileSyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(profile);
+ SigninErrorController* error_controller =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller();
+
OneClickSigninSyncStarter::StartSyncMode start_mode =
source_ == signin::SOURCE_SETTINGS ?
- (SigninGlobalError::GetForProfile(profile)->HasMenuItem() &&
+ (error_controller->HasError() &&
sync_service && sync_service->HasSyncSetupCompleted()) ?
OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 5b52304..a02e454 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -84,6 +84,14 @@
#include "ui/native_theme/native_theme_aura.h"
#endif
+#if !defined(OS_CHROMEOS)
+#include "chrome/browser/signin/signin_global_error_factory.h"
+#endif
+
+#if defined(USE_ASH)
+#include "ash/shell.h"
+#endif
+
using base::UserMetricsAction;
using content::WebContents;
@@ -110,6 +118,16 @@ bool IsStreamlinedHostedAppsEnabled() {
switches::kEnableStreamlinedHostedApps);
}
+#if !defined(OS_CHROMEOS)
+bool HasAshShell() {
+#if defined(USE_ASH)
+ return ash::Shell::HasInstance();
+#else
+ return false;
+#endif // USE_ASH
+}
+#endif // OS_CHROMEOS
+
} // namespace
// static
@@ -245,6 +263,13 @@ void ToolbarView::Init() {
LoadImages();
+ // Start signin global error service now so we badge the menu correctly
+ // in non-Ash.
+#if !defined(OS_CHROMEOS)
+ if (!HasAshShell())
+ SigninGlobalErrorFactory::GetForProfile(browser_->profile());
+#endif // OS_CHROMEOS
+
// Add any necessary badges to the menu item based on the system state.
// Do this after |app_menu_| has been added as a bubble may be shown that
// needs the widget (widget found by way of app_menu_->GetWidget()).
diff --git a/chrome/browser/ui/views/toolbar/wrench_menu.cc b/chrome/browser/ui/views/toolbar/wrench_menu.cc
index 936799d2..8a0e57e 100644
--- a/chrome/browser/ui/views/toolbar/wrench_menu.cc
+++ b/chrome/browser/ui/views/toolbar/wrench_menu.cc
@@ -1202,7 +1202,8 @@ void WrenchMenu::Observe(int type,
case chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED:
// A change in the global errors list can add or remove items from the
// menu. Close the menu to avoid have a stale menu on-screen.
- root_->Cancel();
+ if (root_)
+ root_->Cancel();
break;
default:
NOTREACHED();
diff --git a/chrome/browser/ui/webui/options/managed_user_import_handler.cc b/chrome/browser/ui/webui/options/managed_user_import_handler.cc
index e72152a..aae1c85 100644
--- a/chrome/browser/ui/webui/options/managed_user_import_handler.cc
+++ b/chrome/browser/ui/webui/options/managed_user_import_handler.cc
@@ -10,7 +10,6 @@
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/managed_mode/managed_user_constants.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service_factory.h"
@@ -19,13 +18,13 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_ui.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -48,7 +47,8 @@ scoped_ptr<base::ListValue> GetAvatarIcons() {
namespace options {
ManagedUserImportHandler::ManagedUserImportHandler()
- : weak_ptr_factory_(this) {}
+ : observer_(this),
+ weak_ptr_factory_(this) {}
ManagedUserImportHandler::~ManagedUserImportHandler() {
Profile* profile = Profile::FromWebUI(web_ui());
@@ -85,8 +85,6 @@ void ManagedUserImportHandler::GetLocalizedValues(
void ManagedUserImportHandler::InitializeHandler() {
Profile* profile = Profile::FromWebUI(web_ui());
- registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
- content::Source<Profile>(profile));
if (!profile->IsManaged()) {
ManagedUserSyncService* sync_service =
ManagedUserSyncServiceFactory::GetForProfile(profile);
@@ -103,6 +101,9 @@ void ManagedUserImportHandler::InitializeHandler() {
profile));
}
}
+
+ observer_.Add(ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller());
}
void ManagedUserImportHandler::RegisterMessages() {
@@ -111,18 +112,6 @@ void ManagedUserImportHandler::RegisterMessages() {
base::Unretained(this)));
}
-void ManagedUserImportHandler::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- if (type == chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED) {
- SigninGlobalError* error =
- SigninGlobalError::GetForProfile(Profile::FromWebUI(web_ui()));
- if (content::Details<SigninGlobalError>(details).ptr() == error)
- FetchManagedUsers();
- }
-}
-
void ManagedUserImportHandler::OnManagedUsersChanged() {
FetchManagedUsers();
}
@@ -226,10 +215,11 @@ bool ManagedUserImportHandler::IsAccountConnected() const {
bool ManagedUserImportHandler::HasAuthError() const {
Profile* profile = Profile::FromWebUI(web_ui());
- SigninGlobalError* signin_global_error =
- SigninGlobalError::GetForProfile(profile);
- GoogleServiceAuthError::State state =
- signin_global_error->GetLastAuthError().state();
+ SigninErrorController* error_controller =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller();
+
+ GoogleServiceAuthError::State state = error_controller->auth_error().state();
return state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
@@ -244,4 +234,8 @@ void ManagedUserImportHandler::OnSharedSettingChanged(
FetchManagedUsers();
}
+void ManagedUserImportHandler::OnErrorChanged() {
+ FetchManagedUsers();
+}
+
} // namespace options
diff --git a/chrome/browser/ui/webui/options/managed_user_import_handler.h b/chrome/browser/ui/webui/options/managed_user_import_handler.h
index 55dbd9c..a3ce80f 100644
--- a/chrome/browser/ui/webui/options/managed_user_import_handler.h
+++ b/chrome/browser/ui/webui/options/managed_user_import_handler.h
@@ -7,10 +7,10 @@
#include "base/callback_list.h"
#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
#include "chrome/browser/managed_mode/managed_user_sync_service_observer.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/ui/webui/options/options_ui.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
namespace base {
class DictionaryValue;
@@ -21,8 +21,8 @@ namespace options {
// Handler for the 'import existing managed user' dialog.
class ManagedUserImportHandler : public OptionsPageUIHandler,
- public content::NotificationObserver,
- public ManagedUserSyncServiceObserver {
+ public ManagedUserSyncServiceObserver,
+ public SigninErrorController::Observer {
public:
typedef base::CallbackList<void(const std::string&, const std::string&)>
CallbackList;
@@ -38,17 +38,15 @@ class ManagedUserImportHandler : public OptionsPageUIHandler,
// WebUIMessageHandler implementation.
virtual void RegisterMessages() OVERRIDE;
- // content::NotificationObserver implementation.
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
// ManagedUserSyncServiceObserver implementation.
virtual void OnManagedUserAcknowledged(const std::string& managed_user_id)
OVERRIDE {}
virtual void OnManagedUsersSyncingStopped() OVERRIDE {}
virtual void OnManagedUsersChanged() OVERRIDE;
+ // SigninErrorController::Observer implementation.
+ virtual void OnErrorChanged() OVERRIDE;
+
private:
// Clears the cached list of managed users and fetches the new list of managed
// users.
@@ -86,6 +84,8 @@ class ManagedUserImportHandler : public OptionsPageUIHandler,
scoped_ptr<CallbackList::Subscription> subscription_;
+ ScopedObserver<SigninErrorController, ManagedUserImportHandler> observer_;
+
base::WeakPtrFactory<ManagedUserImportHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ManagedUserImportHandler);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 45ca4f1..cc5f925 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -11,7 +11,9 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_oauth_helper.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -231,10 +233,13 @@ void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
weak_factory_.GetWeakPtr()));
}
} else {
+ SigninErrorController* error_controller =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
+ signin_error_controller();
OneClickSigninSyncStarter::StartSyncMode start_mode =
source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
- (SigninGlobalError::GetForProfile(profile)->HasMenuItem() &&
- sync_service && sync_service->HasSyncSetupCompleted()) ?
+ (error_controller->HasError() &&
+ sync_service && sync_service->HasSyncSetupCompleted()) ?
OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index 23ae8b1e..75e862b 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -25,7 +25,7 @@
#include "chrome/browser/profiles/profile_metrics.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_global_error.h"
+#include "chrome/browser/signin/signin_error_controller.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -510,12 +510,12 @@ void SyncSetupHandler::DisplayGaiaLoginInNewTabOrWindow() {
signin::HISTOGRAM_SHOWN,
signin::HISTOGRAM_MAX);
- SigninGlobalError* signin_error =
+ SigninErrorController* error_controller =
ProfileOAuth2TokenServiceFactory::GetForProfile(browser->profile())->
- signin_global_error();
- DCHECK(signin_error->HasMenuItem());
+ signin_error_controller();
+ DCHECK(error_controller->HasError());
url = signin::GetReauthURL(browser->profile(),
- signin_error->GetAccountIdOfLastAuthError());
+ error_controller->error_account_id());
} else {
url = signin::GetPromoURL(signin::SOURCE_SETTINGS, true);
}
@@ -854,7 +854,8 @@ void SyncSetupHandler::OpenSyncSetup() {
SigninManagerFactory::GetForProfile(GetProfile());
if (signin->GetAuthenticatedUsername().empty() ||
- SigninGlobalError::GetForProfile(GetProfile())->HasMenuItem()) {
+ ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile())->
+ signin_error_controller()->HasError()) {
// User is not logged in (cases 1-2), or login has been specially requested
// because previously working credentials have expired (case 3). Close sync
// setup including any visible overlays, and display the gaia auth page.
diff --git a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
index d8a029e..b68d0c6 100644
--- a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc
@@ -857,7 +857,8 @@ TEST_F(SyncSetupHandlerTest, ShowSigninOnAuthError) {
SetupInitializedProfileSyncService();
mock_signin_->SetAuthenticatedUsername(kTestUser);
FakeAuthStatusProvider provider(
- SigninGlobalError::GetForProfile(profile_.get()));
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())->
+ signin_error_controller());
provider.SetAuthError(kTestUser, error_);
EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
.WillRepeatedly(Return(true));
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index de3e35d..8f47ae9 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2127,8 +2127,16 @@
'browser/signin/profile_oauth2_token_service_request.h',
'browser/signin/signin_account_id_helper.cc',
'browser/signin/signin_account_id_helper.h',
+ 'browser/signin/signin_error_controller.cc',
+ 'browser/signin/signin_error_controller.h',
+ 'browser/signin/signin_error_notifier_ash.cc',
+ 'browser/signin/signin_error_notifier_ash.h',
+ 'browser/signin/signin_error_notifier_factory_ash.cc',
+ 'browser/signin/signin_error_notifier_factory_ash.h',
'browser/signin/signin_global_error.cc',
'browser/signin/signin_global_error.h',
+ 'browser/signin/signin_global_error_factory.cc',
+ 'browser/signin/signin_global_error_factory.h',
'browser/signin/signin_internals_util.cc',
'browser/signin/signin_internals_util.h',
'browser/signin/signin_manager.cc',
@@ -3045,6 +3053,10 @@
'browser/screensaver_window_finder_x11.h',
'browser/shell_integration_linux.cc',
'browser/shell_integration_linux.h',
+ 'browser/signin/signin_global_error.cc',
+ 'browser/signin/signin_global_error.h',
+ 'browser/signin/signin_global_error_factory.cc',
+ 'browser/signin/signin_global_error_factory.h',
'browser/signin/signin_manager.cc',
'browser/speech/tts_linux.cc',
'browser/sxs_linux.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 8def4e0..bcb378c 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1269,6 +1269,8 @@
'browser/signin/local_auth_unittest.cc',
'browser/signin/mutable_profile_oauth2_token_service_unittest.cc',
'browser/signin/profile_oauth2_token_service_request_unittest.cc',
+ 'browser/signin/signin_error_controller_unittest.cc',
+ 'browser/signin/signin_error_notifier_ash_unittest.cc',
'browser/signin/signin_global_error_unittest.cc',
'browser/signin/signin_manager_unittest.cc',
'browser/signin/signin_names_io_thread_unittest.cc',
@@ -1430,6 +1432,8 @@
'browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc',
'browser/ui/ash/screenshot_taker_unittest.cc',
'browser/ui/ash/session_state_delegate_chromeos_unittest.cc',
+ 'browser/ui/ash/test_views_delegate_with_parent.cc',
+ 'browser/ui/ash/test_views_delegate_with_parent.h',
'browser/ui/ash/window_positioner_unittest.cc',
'browser/ui/autofill/account_chooser_model_unittest.cc',
'browser/ui/autofill/autofill_dialog_controller_unittest.cc',
@@ -2288,6 +2292,7 @@
'browser/profiles/profile_list_desktop_unittest.cc',
'browser/safe_browsing/download_protection_service_unittest.cc',
'browser/shell_integration_linux_unittest.cc',
+ 'browser/signin/signin_global_error_unittest.cc',
'browser/signin/signin_manager_unittest.cc',
'browser/signin/signin_names_io_thread_unittest.cc',
'browser/ui/sync/one_click_signin_helper_unittest.cc',