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_ui_util.h"
6
7#include "base/prefs/pref_service.h"
8#include "base/strings/sys_string_conversions.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/signin/account_tracker_service_factory.h"
12#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
13#include "chrome/browser/signin/signin_global_error.h"
14#include "chrome/browser/signin/signin_global_error_factory.h"
15#include "chrome/browser/signin/signin_manager_factory.h"
16#include "chrome/browser/sync/profile_sync_service.h"
17#include "chrome/browser/sync/profile_sync_service_factory.h"
18#include "chrome/browser/sync/sync_global_error.h"
19#include "chrome/browser/sync/sync_global_error_factory.h"
20#include "chrome/browser/ui/browser_navigator.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/grit/chromium_strings.h"
23#include "chrome/grit/generated_resources.h"
24#include "components/signin/core/browser/account_tracker_service.h"
25#include "components/signin/core/browser/profile_oauth2_token_service.h"
26#include "components/signin/core/browser/signin_manager.h"
27#include "components/signin/core/common/profile_management_switches.h"
28#include "ui/base/l10n/l10n_util.h"
29#include "ui/gfx/font_list.h"
30#include "ui/gfx/text_elider.h"
31
32namespace {
33// Maximum width of a username - we trim emails that are wider than this so
34// the wrench menu doesn't get ridiculously wide.
35const int kUsernameMaxWidth = 200;
36}  // namespace
37
38namespace signin_ui_util {
39
40GlobalError* GetSignedInServiceError(Profile* profile) {
41  std::vector<GlobalError*> errors = GetSignedInServiceErrors(profile);
42  if (errors.empty())
43    return NULL;
44  return errors[0];
45}
46
47std::vector<GlobalError*> GetSignedInServiceErrors(Profile* profile) {
48  std::vector<GlobalError*> errors;
49  // Chrome OS doesn't use SigninGlobalError or SyncGlobalError. Other platforms
50  // may use these services to show auth and sync errors in the toolbar menu.
51#if !defined(OS_CHROMEOS)
52  // Auth errors have the highest priority - after that, individual service
53  // errors.
54  SigninGlobalError* signin_error =
55      SigninGlobalErrorFactory::GetForProfile(profile);
56  if (signin_error && signin_error->HasError())
57    errors.push_back(signin_error);
58
59  // No auth error - now try other services. Currently the list is just hard-
60  // coded but in the future if we add more we can create some kind of
61  // registration framework.
62  if (profile->IsSyncAccessible()) {
63    SyncGlobalError* error = SyncGlobalErrorFactory::GetForProfile(profile);
64    if (error && error->HasMenuItem())
65      errors.push_back(error);
66  }
67#endif
68
69  return errors;
70}
71
72base::string16 GetSigninMenuLabel(Profile* profile) {
73  GlobalError* error = signin_ui_util::GetSignedInServiceError(profile);
74  if (error)
75    return error->MenuItemLabel();
76
77  // No errors, so just display the signed in user, if any.
78  ProfileSyncService* service = profile->IsSyncAccessible() ?
79      ProfileSyncServiceFactory::GetForProfile(profile) : NULL;
80
81  // Even if the user is signed in, don't display the "signed in as..."
82  // label if we're still setting up sync.
83  if (!service || !service->FirstSetupInProgress()) {
84    std::string username;
85    SigninManagerBase* signin_manager =
86        SigninManagerFactory::GetForProfileIfExists(profile);
87    if (signin_manager)
88      username = signin_manager->GetAuthenticatedUsername();
89    if (!username.empty() && !signin_manager->AuthInProgress()) {
90      const base::string16 elided = gfx::ElideText(base::UTF8ToUTF16(username),
91          gfx::FontList(), kUsernameMaxWidth, gfx::ELIDE_EMAIL);
92      return l10n_util::GetStringFUTF16(IDS_SYNC_MENU_SYNCED_LABEL, elided);
93    }
94  }
95  return l10n_util::GetStringFUTF16(IDS_SYNC_MENU_PRE_SYNCED_LABEL,
96      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
97}
98
99// Given an authentication state this helper function returns various labels
100// that can be used to display information about the state.
101void GetStatusLabelsForAuthError(Profile* profile,
102                                 const SigninManagerBase& signin_manager,
103                                 base::string16* status_label,
104                                 base::string16* link_label) {
105  base::string16 username =
106      base::UTF8ToUTF16(signin_manager.GetAuthenticatedUsername());
107  base::string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
108  if (link_label)
109    link_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_RELOGIN_LINK_LABEL));
110
111  const GoogleServiceAuthError::State state =
112      ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
113          signin_error_controller()->auth_error().state();
114  switch (state) {
115    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
116    case GoogleServiceAuthError::SERVICE_ERROR:
117    case GoogleServiceAuthError::ACCOUNT_DELETED:
118    case GoogleServiceAuthError::ACCOUNT_DISABLED:
119      // If the user name is empty then the first login failed, otherwise the
120      // credentials are out-of-date.
121      if (username.empty()) {
122        if (status_label) {
123          status_label->assign(
124              l10n_util::GetStringUTF16(IDS_SYNC_INVALID_USER_CREDENTIALS));
125        }
126      } else {
127        if (status_label) {
128          status_label->assign(
129              l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_INFO_OUT_OF_DATE));
130        }
131      }
132      break;
133    case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
134      if (status_label) {
135        status_label->assign(
136            l10n_util::GetStringUTF16(IDS_SYNC_SERVICE_UNAVAILABLE));
137      }
138      if (link_label)
139        link_label->clear();
140      break;
141    case GoogleServiceAuthError::CONNECTION_FAILED:
142      if (status_label) {
143        status_label->assign(
144            l10n_util::GetStringFUTF16(IDS_SYNC_SERVER_IS_UNREACHABLE,
145                                       product_name));
146      }
147      // Note that there is little the user can do if the server is not
148      // reachable. Since attempting to re-connect is done automatically by
149      // the Syncer, we do not show the (re)login link.
150      if (link_label)
151        link_label->clear();
152      break;
153    default:
154      if (status_label) {
155        status_label->assign(l10n_util::GetStringUTF16(
156            IDS_SYNC_ERROR_SIGNING_IN));
157      }
158      break;
159  }
160}
161
162void InitializePrefsForProfile(Profile* profile) {
163  // Suppresses the upgrade tutorial for a new profile.
164  if (profile->IsNewProfile() && switches::IsNewAvatarMenu()) {
165    profile->GetPrefs()->SetInteger(
166        prefs::kProfileAvatarTutorialShown, kUpgradeWelcomeTutorialShowMax + 1);
167  }
168}
169
170void ShowSigninErrorLearnMorePage(Profile* profile) {
171  static const char kSigninErrorLearnMoreUrl[] =
172      "https://support.google.com/chrome/answer/1181420?";
173  chrome::NavigateParams params(
174      profile, GURL(kSigninErrorLearnMoreUrl), ui::PAGE_TRANSITION_LINK);
175  params.disposition = NEW_FOREGROUND_TAB;
176  chrome::Navigate(&params);
177}
178
179std::string GetDisplayEmail(Profile* profile, const std::string& account_id) {
180  AccountTrackerService* account_tracker =
181      AccountTrackerServiceFactory::GetForProfile(profile);
182  std::string email = account_tracker->GetAccountInfo(account_id).email;
183  if (email.empty()) {
184    DCHECK_EQ(AccountTrackerService::MIGRATION_NOT_STARTED,
185              account_tracker->GetMigrationState());
186    return account_id;
187  }
188  return email;
189}
190
191}  // namespace signin_ui_util
192