Home | History | Annotate | Download | only in signin
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/signin/signin_global_error.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/prefs/pref_service.h"
      9 #include "chrome/app/chrome_command_ids.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     12 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     13 #include "chrome/browser/signin/signin_manager.h"
     14 #include "chrome/browser/signin/signin_manager_factory.h"
     15 #include "chrome/browser/ui/browser_commands.h"
     16 #include "chrome/browser/ui/chrome_pages.h"
     17 #include "chrome/browser/ui/global_error/global_error_service.h"
     18 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
     19 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
     20 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
     21 #include "chrome/common/pref_names.h"
     22 #include "chrome/common/url_constants.h"
     23 #include "grit/chromium_strings.h"
     24 #include "grit/generated_resources.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 
     27 SigninGlobalError::SigninGlobalError(Profile* profile)
     28     : auth_error_(GoogleServiceAuthError::AuthErrorNone()), profile_(profile) {
     29 }
     30 
     31 SigninGlobalError::~SigninGlobalError() {
     32   DCHECK(provider_set_.empty())
     33       << "All AuthStatusProviders should be unregistered before"
     34       << " SigninManager::Shutdown() is called";
     35 }
     36 
     37 void SigninGlobalError::AddProvider(const AuthStatusProvider* provider) {
     38   DCHECK(provider_set_.find(provider) == provider_set_.end())
     39       << "Adding same AuthStatusProvider multiple times";
     40   provider_set_.insert(provider);
     41   AuthStatusChanged();
     42 }
     43 
     44 void SigninGlobalError::RemoveProvider(const AuthStatusProvider* provider) {
     45   std::set<const AuthStatusProvider*>::iterator iter =
     46       provider_set_.find(provider);
     47   DCHECK(iter != provider_set_.end())
     48       << "Removing provider that was never added";
     49   provider_set_.erase(iter);
     50   AuthStatusChanged();
     51 }
     52 
     53 SigninGlobalError::AuthStatusProvider::AuthStatusProvider() {
     54 }
     55 
     56 SigninGlobalError::AuthStatusProvider::~AuthStatusProvider() {
     57 }
     58 
     59 void SigninGlobalError::AuthStatusChanged() {
     60   // Walk all of the status providers and collect any error.
     61   GoogleServiceAuthError current_error(GoogleServiceAuthError::AuthErrorNone());
     62   for (std::set<const AuthStatusProvider*>::const_iterator it =
     63            provider_set_.begin(); it != provider_set_.end(); ++it) {
     64     current_error = (*it)->GetAuthStatus();
     65     // Break out if any provider reports an error (ignoring ordinary network
     66     // errors, which are not surfaced to the user). This logic may eventually
     67     // need to be extended to prioritize different auth errors, but for now
     68     // all auth errors are treated the same.
     69     if (current_error.state() != GoogleServiceAuthError::NONE &&
     70         current_error.state() != GoogleServiceAuthError::CONNECTION_FAILED) {
     71       break;
     72     }
     73   }
     74   if (current_error.state() != auth_error_.state()) {
     75     auth_error_ = current_error;
     76     GlobalErrorServiceFactory::GetForProfile(profile_)->NotifyErrorsChanged(
     77         this);
     78   }
     79 }
     80 
     81 bool SigninGlobalError::HasMenuItem() {
     82   return !MenuItemLabel().empty();
     83 }
     84 
     85 int SigninGlobalError::MenuItemCommandID() {
     86   return IDC_SHOW_SIGNIN_ERROR;
     87 }
     88 
     89 string16 SigninGlobalError::MenuItemLabel() {
     90   std::string username;
     91   SigninManagerBase* signin_manager =
     92       SigninManagerFactory::GetForProfileIfExists(profile_);
     93   if (signin_manager)
     94     username = signin_manager->GetAuthenticatedUsername();
     95   if (username.empty() ||
     96       auth_error_.state() == GoogleServiceAuthError::NONE ||
     97       auth_error_.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
     98     // If the user isn't signed in, or there's no auth error worth elevating to
     99     // the user, don't display any menu item.
    100     return string16();
    101   } else {
    102     // There's an auth error the user should know about - notify the user.
    103     return l10n_util::GetStringUTF16(IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM);
    104   }
    105 }
    106 
    107 void SigninGlobalError::ExecuteMenuItem(Browser* browser) {
    108 #if defined(OS_CHROMEOS)
    109   if (auth_error_.state() != GoogleServiceAuthError::NONE) {
    110     DLOG(INFO) << "Signing out the user to fix a sync error.";
    111     // TODO(beng): seems like this could just call chrome::AttemptUserExit().
    112     chrome::ExecuteCommand(browser, IDC_EXIT);
    113     return;
    114   }
    115 #endif
    116 
    117   // Global errors don't show up in the wrench menu on android.
    118 #if !defined(OS_ANDROID)
    119   LoginUIService* login_ui = LoginUIServiceFactory::GetForProfile(profile_);
    120   if (login_ui->current_login_ui()) {
    121     login_ui->current_login_ui()->FocusUI();
    122     return;
    123   }
    124   // Need to navigate to the settings page and display the UI.
    125   chrome::ShowSettingsSubPage(browser, chrome::kSyncSetupSubPage);
    126 #endif
    127 }
    128 
    129 bool SigninGlobalError::HasBubbleView() {
    130   return !GetBubbleViewMessages().empty();
    131 }
    132 
    133 string16 SigninGlobalError::GetBubbleViewTitle() {
    134   return l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE);
    135 }
    136 
    137 std::vector<string16> SigninGlobalError::GetBubbleViewMessages() {
    138   std::vector<string16> messages;
    139 
    140   // If the user isn't signed in, no need to display an error bubble.
    141   SigninManagerBase* signin_manager =
    142       SigninManagerFactory::GetForProfileIfExists(profile_);
    143   if (signin_manager) {
    144     std::string username = signin_manager->GetAuthenticatedUsername();
    145     if (username.empty())
    146       return messages;
    147   }
    148 
    149   switch (auth_error_.state()) {
    150     // In the case of no error, or a simple network error, don't bother
    151     // displaying a popup bubble.
    152     case GoogleServiceAuthError::CONNECTION_FAILED:
    153     case GoogleServiceAuthError::NONE:
    154       return messages;
    155 
    156     // User credentials are invalid (bad acct, etc).
    157     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    158     case GoogleServiceAuthError::ACCOUNT_DELETED:
    159     case GoogleServiceAuthError::ACCOUNT_DISABLED:
    160       messages.push_back(l10n_util::GetStringFUTF16(
    161           IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE,
    162           l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
    163       break;
    164 
    165     // Sync service is not available for this account's domain.
    166     case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    167       messages.push_back(l10n_util::GetStringFUTF16(
    168           IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE,
    169           l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
    170       break;
    171 
    172     // Generic message for "other" errors.
    173     default:
    174       messages.push_back(l10n_util::GetStringFUTF16(
    175           IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE,
    176           l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
    177   }
    178   return messages;
    179 }
    180 
    181 string16 SigninGlobalError::GetBubbleViewAcceptButtonLabel() {
    182   // If the service is unavailable, don't give the user the option to try
    183   // signing in again.
    184   if (auth_error_.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
    185     return l10n_util::GetStringUTF16(
    186         IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_ACCEPT);
    187   } else {
    188     return l10n_util::GetStringUTF16(IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_ACCEPT);
    189   }
    190 }
    191 
    192 string16 SigninGlobalError::GetBubbleViewCancelButtonLabel() {
    193   return string16();
    194 }
    195 
    196 void SigninGlobalError::OnBubbleViewDidClose(Browser* browser) {
    197 }
    198 
    199 void SigninGlobalError::BubbleViewAcceptButtonPressed(Browser* browser) {
    200   ExecuteMenuItem(browser);
    201 }
    202 
    203 void SigninGlobalError::BubbleViewCancelButtonPressed(Browser* browser) {
    204   NOTREACHED();
    205 }
    206 
    207 // static
    208 SigninGlobalError* SigninGlobalError::GetForProfile(Profile* profile) {
    209   return ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
    210       signin_global_error();
    211 }
    212