Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / sync / sync_ui_util.cc
blobf686a3057493be77d41e4d066cfe6cfb003d39c0
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/metrics/field_trial.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/signin/signin_error_controller_factory.h"
16 #include "chrome/browser/signin/signin_ui_util.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
22 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/url_constants.h"
25 #include "chrome/grit/chromium_strings.h"
26 #include "chrome/grit/generated_resources.h"
27 #include "chrome/grit/locale_settings.h"
28 #include "components/signin/core/browser/signin_error_controller.h"
29 #include "components/signin/core/browser/signin_manager_base.h"
30 #include "google_apis/gaia/google_service_auth_error.h"
31 #include "sync/internal_api/public/base/model_type.h"
32 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
33 #include "sync/protocol/proto_enum_conversions.h"
34 #include "sync/protocol/sync_protocol_error.h"
35 #include "ui/base/l10n/l10n_util.h"
37 #if defined(OS_CHROMEOS)
38 #include "components/user_manager/user_manager.h"
39 #endif // defined(OS_CHROMEOS)
41 typedef GoogleServiceAuthError AuthError;
43 namespace sync_ui_util {
45 namespace {
47 bool IsChromeDashboardEnabled() {
48 const std::string group_name =
49 base::FieldTrialList::FindFullName("ChromeDashboard");
50 return group_name == "Enabled";
53 // Returns the message that should be displayed when the user is authenticated
54 // and can connect to the sync server. If the user hasn't yet authenticated, an
55 // empty string is returned.
56 base::string16 GetSyncedStateStatusLabel(ProfileSyncService* service,
57 const SigninManagerBase& signin,
58 StatusLabelStyle style) {
59 std::string user_display_name = signin.GetAuthenticatedUsername();
61 #if defined(OS_CHROMEOS)
62 if (user_manager::UserManager::IsInitialized()) {
63 // On CrOS user email is sanitized and then passed to the signin manager.
64 // Original email (containing dots) is stored as "display email".
65 user_display_name = user_manager::UserManager::Get()->GetUserDisplayEmail(
66 user_display_name);
68 #endif // defined(OS_CHROMEOS)
70 base::string16 user_name = base::UTF8ToUTF16(user_display_name);
72 if (!user_name.empty()) {
73 if (!service || service->IsManaged()) {
74 // User is signed in, but sync is disabled.
75 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_DISABLED,
76 user_name);
77 } else if (!service->IsSyncRequested()) {
78 // User is signed in, but sync has been stopped.
79 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
80 user_name);
84 if (!service || !service->IsSyncActive()) {
85 // User is not signed in, or sync is still initializing.
86 return base::string16();
89 DCHECK(!user_name.empty());
91 // Message may also carry additional advice with an HTML link, if acceptable.
92 switch (style) {
93 case PLAIN_TEXT:
94 return l10n_util::GetStringFUTF16(
95 IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
96 user_name);
97 case WITH_HTML:
98 if (IsChromeDashboardEnabled()) {
99 return l10n_util::GetStringFUTF16(
100 IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK_NEW,
101 user_name,
102 base::ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
104 return l10n_util::GetStringFUTF16(
105 IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK,
106 user_name,
107 base::ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
108 default:
109 NOTREACHED();
110 return NULL;
114 void GetStatusForActionableError(
115 const syncer::SyncProtocolError& error,
116 base::string16* status_label) {
117 DCHECK(status_label);
118 switch (error.action) {
119 case syncer::STOP_AND_RESTART_SYNC:
120 status_label->assign(
121 l10n_util::GetStringUTF16(IDS_SYNC_STOP_AND_RESTART_SYNC));
122 break;
123 case syncer::UPGRADE_CLIENT:
124 status_label->assign(
125 l10n_util::GetStringFUTF16(IDS_SYNC_UPGRADE_CLIENT,
126 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
127 break;
128 case syncer::ENABLE_SYNC_ON_ACCOUNT:
129 status_label->assign(
130 l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT));
131 break;
132 case syncer::CLEAR_USER_DATA_AND_RESYNC:
133 status_label->assign(
134 l10n_util::GetStringUTF16(IDS_SYNC_CLEAR_USER_DATA));
135 break;
136 default:
137 NOTREACHED();
141 // TODO(akalin): Write unit tests for these three functions below.
143 // status_label and link_label must either be both NULL or both non-NULL.
144 MessageType GetStatusInfo(ProfileSyncService* service,
145 const SigninManagerBase& signin,
146 StatusLabelStyle style,
147 base::string16* status_label,
148 base::string16* link_label) {
149 DCHECK_EQ(status_label == NULL, link_label == NULL);
151 MessageType result_type(SYNCED);
153 if (!signin.IsAuthenticated())
154 return PRE_SYNCED;
156 if (!service || service->IsManaged() || service->HasSyncSetupCompleted() ||
157 !service->IsSyncRequested()) {
158 // The order or priority is going to be: 1. Unrecoverable errors.
159 // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors.
161 if (service && service->HasUnrecoverableError()) {
162 if (status_label) {
163 status_label->assign(l10n_util::GetStringFUTF16(
164 IDS_SYNC_STATUS_UNRECOVERABLE_ERROR,
165 l10n_util::GetStringUTF16(IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL)));
167 return SYNC_ERROR;
170 // For auth errors first check if an auth is in progress.
171 if (signin.AuthInProgress()) {
172 if (status_label) {
173 status_label->assign(
174 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
176 return PRE_SYNCED;
179 // Check for sync errors if the sync service is enabled.
180 if (service) {
181 // Since there is no auth in progress, check for an auth error first.
182 AuthError auth_error =
183 SigninErrorControllerFactory::GetForProfile(service->profile())->
184 auth_error();
185 if (auth_error.state() != AuthError::NONE) {
186 if (status_label && link_label)
187 signin_ui_util::GetStatusLabelsForAuthError(
188 service->profile(), signin, status_label, link_label);
189 return SYNC_ERROR;
192 // We don't have an auth error. Check for an actionable error.
193 ProfileSyncService::Status status;
194 service->QueryDetailedSyncStatus(&status);
195 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
196 if (status_label) {
197 GetStatusForActionableError(status.sync_protocol_error,
198 status_label);
200 return SYNC_ERROR;
203 // Check for a passphrase error.
204 if (service->IsPassphraseRequired()) {
205 if (service->IsPassphraseRequiredForDecryption()) {
206 // TODO(lipalani) : Ask tim if this is still needed.
207 // NOT first machine.
208 // Show a link ("needs attention"), but still indicate the
209 // current synced status. Return SYNC_PROMO so that
210 // the configure link will still be shown.
211 if (status_label && link_label) {
212 status_label->assign(GetSyncedStateStatusLabel(
213 service, signin, style));
214 link_label->assign(
215 l10n_util::GetStringUTF16(IDS_SYNC_PASSWORD_SYNC_ATTENTION));
217 return SYNC_PROMO;
221 // Check to see if sync has been disabled via the dasboard and needs to be
222 // set up once again.
223 if (!service->IsSyncRequested() &&
224 status.sync_protocol_error.error_type == syncer::NOT_MY_BIRTHDAY) {
225 if (status_label) {
226 status_label->assign(GetSyncedStateStatusLabel(service,
227 signin,
228 style));
230 return PRE_SYNCED;
234 // There is no error. Display "Last synced..." message.
235 if (status_label)
236 status_label->assign(GetSyncedStateStatusLabel(service, signin, style));
237 return SYNCED;
238 } else {
239 // Either show auth error information with a link to re-login, auth in prog,
240 // or provide a link to continue with setup.
241 if (service->FirstSetupInProgress()) {
242 result_type = PRE_SYNCED;
243 ProfileSyncService::Status status;
244 service->QueryDetailedSyncStatus(&status);
245 AuthError auth_error =
246 SigninErrorControllerFactory::GetForProfile(service->profile())->
247 auth_error();
248 if (status_label) {
249 status_label->assign(
250 l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS));
252 if (signin.AuthInProgress()) {
253 if (status_label) {
254 status_label->assign(
255 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
257 } else if (auth_error.state() != AuthError::NONE &&
258 auth_error.state() != AuthError::TWO_FACTOR) {
259 if (status_label && link_label) {
260 status_label->clear();
261 signin_ui_util::GetStatusLabelsForAuthError(
262 service->profile(), signin, status_label, link_label);
264 result_type = SYNC_ERROR;
266 } else if (service->HasUnrecoverableError()) {
267 result_type = SYNC_ERROR;
268 ProfileSyncService::Status status;
269 service->QueryDetailedSyncStatus(&status);
270 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
271 if (status_label) {
272 GetStatusForActionableError(status.sync_protocol_error,
273 status_label);
275 } else if (status_label) {
276 status_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ERROR));
278 } else if (signin.IsAuthenticated()) {
279 // The user is signed in, but sync has been stopped.
280 if (status_label) {
281 base::string16 label = l10n_util::GetStringFUTF16(
282 IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
283 base::UTF8ToUTF16(signin.GetAuthenticatedUsername()));
284 status_label->assign(label);
285 result_type = PRE_SYNCED;
289 return result_type;
292 // Returns the status info for use on the new tab page, where we want slightly
293 // different information than in the settings panel.
294 MessageType GetStatusInfoForNewTabPage(ProfileSyncService* service,
295 const SigninManagerBase& signin,
296 base::string16* status_label,
297 base::string16* link_label) {
298 DCHECK(status_label);
299 DCHECK(link_label);
301 if (service->HasSyncSetupCompleted() &&
302 service->IsPassphraseRequired()) {
303 if (service->passphrase_required_reason() == syncer::REASON_ENCRYPTION) {
304 // First machine migrating to passwords. Show as a promotion.
305 if (status_label && link_label) {
306 status_label->assign(
307 l10n_util::GetStringFUTF16(
308 IDS_SYNC_NTP_PASSWORD_PROMO,
309 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
310 link_label->assign(
311 l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
313 return SYNC_PROMO;
314 } else {
315 // NOT first machine.
316 // Show a link and present as an error ("needs attention").
317 if (status_label && link_label) {
318 status_label->assign(base::string16());
319 link_label->assign(
320 l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
322 return SYNC_ERROR;
326 // Fallback to default.
327 return GetStatusInfo(service, signin, WITH_HTML, status_label, link_label);
330 } // namespace
332 MessageType GetStatusLabels(ProfileSyncService* service,
333 const SigninManagerBase& signin,
334 StatusLabelStyle style,
335 base::string16* status_label,
336 base::string16* link_label) {
337 DCHECK(status_label);
338 DCHECK(link_label);
339 return sync_ui_util::GetStatusInfo(
340 service, signin, style, status_label, link_label);
343 MessageType GetStatusLabelsForNewTabPage(ProfileSyncService* service,
344 const SigninManagerBase& signin,
345 base::string16* status_label,
346 base::string16* link_label) {
347 DCHECK(status_label);
348 DCHECK(link_label);
349 return sync_ui_util::GetStatusInfoForNewTabPage(
350 service, signin, status_label, link_label);
353 #if !defined(OS_CHROMEOS)
354 void GetStatusLabelsForSyncGlobalError(const ProfileSyncService* service,
355 base::string16* menu_label,
356 base::string16* bubble_message,
357 base::string16* bubble_accept_label) {
358 DCHECK(menu_label);
359 DCHECK(bubble_message);
360 DCHECK(bubble_accept_label);
361 *menu_label = base::string16();
362 *bubble_message = base::string16();
363 *bubble_accept_label = base::string16();
365 // Only display an error if we've completed sync setup.
366 if (!service->HasSyncSetupCompleted())
367 return;
369 // Display a passphrase error if we have one.
370 if (service->IsPassphraseRequired() &&
371 service->IsPassphraseRequiredForDecryption()) {
372 // This is not the first machine so ask user to enter passphrase.
373 *menu_label = l10n_util::GetStringUTF16(
374 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM);
375 *bubble_message = l10n_util::GetStringUTF16(
376 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE);
377 *bubble_accept_label = l10n_util::GetStringUTF16(
378 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT);
379 return;
382 #endif
384 MessageType GetStatus(
385 ProfileSyncService* service, const SigninManagerBase& signin) {
386 return sync_ui_util::GetStatusInfo(service, signin, WITH_HTML, NULL, NULL);
389 base::string16 ConstructTime(int64 time_in_int) {
390 base::Time time = base::Time::FromInternalValue(time_in_int);
392 // If time is null the format function returns a time in 1969.
393 if (time.is_null())
394 return base::string16();
395 return base::TimeFormatFriendlyDateAndTime(time);
398 } // namespace sync_ui_util