Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / chrome / browser / sync / sync_ui_util.cc
blob8b1a59f5195e251cfe440555a903f6d756ff2c14
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/sync_ui_util.h"
7 #include "base/i18n/number_formatting.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/signin/signin_error_controller_factory.h"
15 #include "chrome/browser/signin/signin_ui_util.h"
16 #include "chrome/browser/sync/profile_sync_service.h"
17 #include "chrome/browser/sync/profile_sync_service_factory.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_window.h"
20 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
21 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/url_constants.h"
24 #include "chrome/grit/chromium_strings.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "chrome/grit/locale_settings.h"
27 #include "components/signin/core/browser/signin_error_controller.h"
28 #include "components/signin/core/browser/signin_manager_base.h"
29 #include "google_apis/gaia/google_service_auth_error.h"
30 #include "sync/internal_api/public/base/model_type.h"
31 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
32 #include "sync/protocol/proto_enum_conversions.h"
33 #include "sync/protocol/sync_protocol_error.h"
34 #include "ui/base/l10n/l10n_util.h"
36 #if defined(OS_CHROMEOS)
37 #include "components/user_manager/user_manager.h"
38 #endif // defined(OS_CHROMEOS)
40 typedef GoogleServiceAuthError AuthError;
42 namespace sync_ui_util {
44 namespace {
46 // Returns the message that should be displayed when the user is authenticated
47 // and can connect to the sync server. If the user hasn't yet authenticated, an
48 // empty string is returned.
49 base::string16 GetSyncedStateStatusLabel(ProfileSyncService* service,
50 const SigninManagerBase& signin,
51 StatusLabelStyle style) {
52 std::string user_display_name = signin.GetAuthenticatedUsername();
54 #if defined(OS_CHROMEOS)
55 if (user_manager::UserManager::IsInitialized()) {
56 // On CrOS user email is sanitized and then passed to the signin manager.
57 // Original email (containing dots) is stored as "display email".
58 user_display_name = user_manager::UserManager::Get()->GetUserDisplayEmail(
59 user_display_name);
61 #endif // defined(OS_CHROMEOS)
63 base::string16 user_name = base::UTF8ToUTF16(user_display_name);
65 if (!user_name.empty()) {
66 if (!service || service->IsManaged()) {
67 // User is signed in, but sync is disabled.
68 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_DISABLED,
69 user_name);
70 } else if (service->IsStartSuppressed()) {
71 // User is signed in, but sync has been stopped.
72 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
73 user_name);
77 if (!service || !service->SyncActive()) {
78 // User is not signed in, or sync is still initializing.
79 return base::string16();
82 DCHECK(!user_name.empty());
84 // Message may also carry additional advice with an HTML link, if acceptable.
85 switch (style) {
86 case PLAIN_TEXT:
87 return l10n_util::GetStringFUTF16(
88 IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
89 user_name);
90 case WITH_HTML:
91 return l10n_util::GetStringFUTF16(
92 IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK,
93 user_name,
94 base::ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
95 default:
96 NOTREACHED();
97 return NULL;
101 void GetStatusForActionableError(
102 const syncer::SyncProtocolError& error,
103 base::string16* status_label) {
104 DCHECK(status_label);
105 switch (error.action) {
106 case syncer::STOP_AND_RESTART_SYNC:
107 status_label->assign(
108 l10n_util::GetStringUTF16(IDS_SYNC_STOP_AND_RESTART_SYNC));
109 break;
110 case syncer::UPGRADE_CLIENT:
111 status_label->assign(
112 l10n_util::GetStringFUTF16(IDS_SYNC_UPGRADE_CLIENT,
113 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
114 break;
115 case syncer::ENABLE_SYNC_ON_ACCOUNT:
116 status_label->assign(
117 l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT));
118 break;
119 case syncer::CLEAR_USER_DATA_AND_RESYNC:
120 status_label->assign(
121 l10n_util::GetStringUTF16(IDS_SYNC_CLEAR_USER_DATA));
122 break;
123 default:
124 NOTREACHED();
128 // TODO(akalin): Write unit tests for these three functions below.
130 // status_label and link_label must either be both NULL or both non-NULL.
131 MessageType GetStatusInfo(ProfileSyncService* service,
132 const SigninManagerBase& signin,
133 StatusLabelStyle style,
134 base::string16* status_label,
135 base::string16* link_label) {
136 DCHECK_EQ(status_label == NULL, link_label == NULL);
138 MessageType result_type(SYNCED);
140 if (!signin.IsAuthenticated())
141 return PRE_SYNCED;
143 if (!service || service->IsManaged() || service->HasSyncSetupCompleted() ||
144 service->IsStartSuppressed()) {
145 // The order or priority is going to be: 1. Unrecoverable errors.
146 // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors.
148 if (service && service->HasUnrecoverableError()) {
149 if (status_label) {
150 status_label->assign(l10n_util::GetStringFUTF16(
151 IDS_SYNC_STATUS_UNRECOVERABLE_ERROR,
152 l10n_util::GetStringUTF16(IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL)));
154 return SYNC_ERROR;
157 // For auth errors first check if an auth is in progress.
158 if (signin.AuthInProgress()) {
159 if (status_label) {
160 status_label->assign(
161 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
163 return PRE_SYNCED;
166 // Check for sync errors if the sync service is enabled.
167 if (service) {
168 // Since there is no auth in progress, check for an auth error first.
169 AuthError auth_error =
170 SigninErrorControllerFactory::GetForProfile(service->profile())->
171 auth_error();
172 if (auth_error.state() != AuthError::NONE) {
173 if (status_label && link_label)
174 signin_ui_util::GetStatusLabelsForAuthError(
175 service->profile(), signin, status_label, link_label);
176 return SYNC_ERROR;
179 // We don't have an auth error. Check for an actionable error.
180 ProfileSyncService::Status status;
181 service->QueryDetailedSyncStatus(&status);
182 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
183 if (status_label) {
184 GetStatusForActionableError(status.sync_protocol_error,
185 status_label);
187 return SYNC_ERROR;
190 // Check for a passphrase error.
191 if (service->IsPassphraseRequired()) {
192 if (service->IsPassphraseRequiredForDecryption()) {
193 // TODO(lipalani) : Ask tim if this is still needed.
194 // NOT first machine.
195 // Show a link ("needs attention"), but still indicate the
196 // current synced status. Return SYNC_PROMO so that
197 // the configure link will still be shown.
198 if (status_label && link_label) {
199 status_label->assign(GetSyncedStateStatusLabel(
200 service, signin, style));
201 link_label->assign(
202 l10n_util::GetStringUTF16(IDS_SYNC_PASSWORD_SYNC_ATTENTION));
204 return SYNC_PROMO;
208 // Check to see if sync has been disabled via the dasboard and needs to be
209 // set up once again.
210 if (service->IsStartSuppressed() &&
211 status.sync_protocol_error.error_type == syncer::NOT_MY_BIRTHDAY) {
212 if (status_label) {
213 status_label->assign(GetSyncedStateStatusLabel(service,
214 signin,
215 style));
217 return PRE_SYNCED;
221 // There is no error. Display "Last synced..." message.
222 if (status_label)
223 status_label->assign(GetSyncedStateStatusLabel(service, signin, style));
224 return SYNCED;
225 } else {
226 // Either show auth error information with a link to re-login, auth in prog,
227 // or provide a link to continue with setup.
228 if (service->FirstSetupInProgress()) {
229 result_type = PRE_SYNCED;
230 ProfileSyncService::Status status;
231 service->QueryDetailedSyncStatus(&status);
232 AuthError auth_error =
233 SigninErrorControllerFactory::GetForProfile(service->profile())->
234 auth_error();
235 if (status_label) {
236 status_label->assign(
237 l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS));
239 if (signin.AuthInProgress()) {
240 if (status_label) {
241 status_label->assign(
242 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
244 } else if (auth_error.state() != AuthError::NONE &&
245 auth_error.state() != AuthError::TWO_FACTOR) {
246 if (status_label && link_label) {
247 status_label->clear();
248 signin_ui_util::GetStatusLabelsForAuthError(
249 service->profile(), signin, status_label, link_label);
251 result_type = SYNC_ERROR;
253 } else if (service->HasUnrecoverableError()) {
254 result_type = SYNC_ERROR;
255 ProfileSyncService::Status status;
256 service->QueryDetailedSyncStatus(&status);
257 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
258 if (status_label) {
259 GetStatusForActionableError(status.sync_protocol_error,
260 status_label);
262 } else if (status_label) {
263 status_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ERROR));
265 } else if (signin.IsAuthenticated()) {
266 // The user is signed in, but sync has been stopped.
267 if (status_label) {
268 base::string16 label = l10n_util::GetStringFUTF16(
269 IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
270 base::UTF8ToUTF16(signin.GetAuthenticatedUsername()));
271 status_label->assign(label);
272 result_type = PRE_SYNCED;
276 return result_type;
279 // Returns the status info for use on the new tab page, where we want slightly
280 // different information than in the settings panel.
281 MessageType GetStatusInfoForNewTabPage(ProfileSyncService* service,
282 const SigninManagerBase& signin,
283 base::string16* status_label,
284 base::string16* link_label) {
285 DCHECK(status_label);
286 DCHECK(link_label);
288 if (service->HasSyncSetupCompleted() &&
289 service->IsPassphraseRequired()) {
290 if (service->passphrase_required_reason() == syncer::REASON_ENCRYPTION) {
291 // First machine migrating to passwords. Show as a promotion.
292 if (status_label && link_label) {
293 status_label->assign(
294 l10n_util::GetStringFUTF16(
295 IDS_SYNC_NTP_PASSWORD_PROMO,
296 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
297 link_label->assign(
298 l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
300 return SYNC_PROMO;
301 } else {
302 // NOT first machine.
303 // Show a link and present as an error ("needs attention").
304 if (status_label && link_label) {
305 status_label->assign(base::string16());
306 link_label->assign(
307 l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
309 return SYNC_ERROR;
313 // Fallback to default.
314 return GetStatusInfo(service, signin, WITH_HTML, status_label, link_label);
317 } // namespace
319 MessageType GetStatusLabels(ProfileSyncService* service,
320 const SigninManagerBase& signin,
321 StatusLabelStyle style,
322 base::string16* status_label,
323 base::string16* link_label) {
324 DCHECK(status_label);
325 DCHECK(link_label);
326 return sync_ui_util::GetStatusInfo(
327 service, signin, style, status_label, link_label);
330 MessageType GetStatusLabelsForNewTabPage(ProfileSyncService* service,
331 const SigninManagerBase& signin,
332 base::string16* status_label,
333 base::string16* link_label) {
334 DCHECK(status_label);
335 DCHECK(link_label);
336 return sync_ui_util::GetStatusInfoForNewTabPage(
337 service, signin, status_label, link_label);
340 #if !defined(OS_CHROMEOS)
341 void GetStatusLabelsForSyncGlobalError(const ProfileSyncService* service,
342 base::string16* menu_label,
343 base::string16* bubble_message,
344 base::string16* bubble_accept_label) {
345 DCHECK(menu_label);
346 DCHECK(bubble_message);
347 DCHECK(bubble_accept_label);
348 *menu_label = base::string16();
349 *bubble_message = base::string16();
350 *bubble_accept_label = base::string16();
352 // Only display an error if we've completed sync setup.
353 if (!service->HasSyncSetupCompleted())
354 return;
356 // Display a passphrase error if we have one.
357 if (service->IsPassphraseRequired() &&
358 service->IsPassphraseRequiredForDecryption()) {
359 // This is not the first machine so ask user to enter passphrase.
360 *menu_label = l10n_util::GetStringUTF16(
361 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM);
362 *bubble_message = l10n_util::GetStringUTF16(
363 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE);
364 *bubble_accept_label = l10n_util::GetStringUTF16(
365 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT);
366 return;
369 #endif
371 MessageType GetStatus(
372 ProfileSyncService* service, const SigninManagerBase& signin) {
373 return sync_ui_util::GetStatusInfo(service, signin, WITH_HTML, NULL, NULL);
376 base::string16 ConstructTime(int64 time_in_int) {
377 base::Time time = base::Time::FromInternalValue(time_in_int);
379 // If time is null the format function returns a time in 1969.
380 if (time.is_null())
381 return base::string16();
382 return base::TimeFormatFriendlyDateAndTime(time);
385 } // namespace sync_ui_util