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_global_error.h"
15 #include "chrome/browser/signin/signin_manager_base.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/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "google_apis/gaia/google_service_auth_error.h"
27 #include "grit/browser_resources.h"
28 #include "grit/chromium_strings.h"
29 #include "grit/generated_resources.h"
30 #include "grit/locale_settings.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"
36 #include "ui/base/resource/resource_bundle.h"
38 typedef GoogleServiceAuthError AuthError;
40 namespace sync_ui_util {
44 // Returns the message that should be displayed when the user is authenticated
45 // and can connect to the sync server. If the user hasn't yet authenticated, an
46 // empty string is returned.
47 string16 GetSyncedStateStatusLabel(ProfileSyncService* service,
48 const SigninManagerBase& signin,
49 StatusLabelStyle style) {
50 string16 user_name = UTF8ToUTF16(signin.GetAuthenticatedUsername());
52 if (!user_name.empty()) {
53 if (!service || service->IsManaged()) {
54 // User is signed in, but sync is disabled.
55 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_DISABLED,
57 } else if (service->IsStartSuppressed()) {
58 // User is signed in, but sync has been stopped.
59 return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
64 if (!service || !service->sync_initialized()) {
65 // User is not signed in, or sync is still initializing.
69 DCHECK(!user_name.empty());
71 // Message may also carry additional advice with an HTML link, if acceptable.
74 return l10n_util::GetStringFUTF16(
75 IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
78 return l10n_util::GetStringFUTF16(
79 IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK,
81 ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
88 void GetStatusForActionableError(
89 const syncer::SyncProtocolError& error,
90 string16* status_label) {
92 switch (error.action) {
93 case syncer::STOP_AND_RESTART_SYNC:
95 l10n_util::GetStringUTF16(IDS_SYNC_STOP_AND_RESTART_SYNC));
97 case syncer::UPGRADE_CLIENT:
99 l10n_util::GetStringFUTF16(IDS_SYNC_UPGRADE_CLIENT,
100 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
102 case syncer::ENABLE_SYNC_ON_ACCOUNT:
103 status_label->assign(
104 l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT));
106 case syncer::CLEAR_USER_DATA_AND_RESYNC:
107 status_label->assign(
108 l10n_util::GetStringUTF16(IDS_SYNC_CLEAR_USER_DATA));
115 // TODO(akalin): Write unit tests for these three functions below.
117 // status_label and link_label must either be both NULL or both non-NULL.
118 MessageType GetStatusInfo(ProfileSyncService* service,
119 const SigninManagerBase& signin,
120 StatusLabelStyle style,
121 string16* status_label,
122 string16* link_label) {
123 DCHECK_EQ(status_label == NULL, link_label == NULL);
125 MessageType result_type(SYNCED);
127 if (signin.GetAuthenticatedUsername().empty())
130 if (!service || service->IsManaged() || service->HasSyncSetupCompleted() ||
131 service->IsStartSuppressed()) {
132 // The order or priority is going to be: 1. Unrecoverable errors.
133 // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors.
135 if (service && service->HasUnrecoverableError()) {
137 status_label->assign(l10n_util::GetStringFUTF16(
138 IDS_SYNC_STATUS_UNRECOVERABLE_ERROR,
139 l10n_util::GetStringUTF16(IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL)));
144 // For auth errors first check if an auth is in progress.
145 if (signin.AuthInProgress()) {
147 status_label->assign(
148 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
153 // Check for sync errors if the sync service is enabled.
155 // Since there is no auth in progress, check for an auth error first.
156 AuthError auth_error =
157 SigninGlobalError::GetForProfile(service->profile())->
159 if (auth_error.state() != AuthError::NONE) {
160 if (status_label && link_label)
161 signin_ui_util::GetStatusLabelsForAuthError(
162 service->profile(), signin, status_label, link_label);
166 // We don't have an auth error. Check for an actionable error.
167 ProfileSyncService::Status status;
168 service->QueryDetailedSyncStatus(&status);
169 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
171 GetStatusForActionableError(status.sync_protocol_error,
177 // Check for a passphrase error.
178 if (service->IsPassphraseRequired()) {
179 if (service->IsPassphraseRequiredForDecryption()) {
180 // TODO(lipalani) : Ask tim if this is still needed.
181 // NOT first machine.
182 // Show a link ("needs attention"), but still indicate the
183 // current synced status. Return SYNC_PROMO so that
184 // the configure link will still be shown.
185 if (status_label && link_label) {
186 status_label->assign(GetSyncedStateStatusLabel(
187 service, signin, style));
189 l10n_util::GetStringUTF16(IDS_SYNC_PASSWORD_SYNC_ATTENTION));
195 // Check to see if sync has been disabled via the dasboard and needs to be
196 // set up once again.
197 if (service->IsStartSuppressed() &&
198 status.sync_protocol_error.error_type == syncer::NOT_MY_BIRTHDAY) {
200 status_label->assign(GetSyncedStateStatusLabel(service,
208 // There is no error. Display "Last synced..." message.
210 status_label->assign(GetSyncedStateStatusLabel(service, signin, style));
213 // Either show auth error information with a link to re-login, auth in prog,
214 // or provide a link to continue with setup.
215 if (service->FirstSetupInProgress()) {
216 result_type = PRE_SYNCED;
217 ProfileSyncService::Status status;
218 service->QueryDetailedSyncStatus(&status);
219 AuthError auth_error =
220 SigninGlobalError::GetForProfile(
221 service->profile())->GetLastAuthError();
223 status_label->assign(
224 l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS));
226 if (signin.AuthInProgress()) {
228 status_label->assign(
229 l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
231 } else if (auth_error.state() != AuthError::NONE &&
232 auth_error.state() != AuthError::TWO_FACTOR) {
233 if (status_label && link_label) {
234 status_label->clear();
235 signin_ui_util::GetStatusLabelsForAuthError(
236 service->profile(), signin, status_label, link_label);
238 result_type = SYNC_ERROR;
240 } else if (service->HasUnrecoverableError()) {
241 result_type = SYNC_ERROR;
242 ProfileSyncService::Status status;
243 service->QueryDetailedSyncStatus(&status);
244 if (ShouldShowActionOnUI(status.sync_protocol_error)) {
246 GetStatusForActionableError(status.sync_protocol_error,
249 } else if (status_label) {
250 status_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ERROR));
252 } else if (!signin.GetAuthenticatedUsername().empty()) {
253 // The user is signed in, but sync has been stopped.
255 string16 label = l10n_util::GetStringFUTF16(
256 IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
257 UTF8ToUTF16(signin.GetAuthenticatedUsername()));
258 status_label->assign(label);
259 result_type = PRE_SYNCED;
266 // Returns the status info for use on the new tab page, where we want slightly
267 // different information than in the settings panel.
268 MessageType GetStatusInfoForNewTabPage(ProfileSyncService* service,
269 const SigninManagerBase& signin,
270 string16* status_label,
271 string16* link_label) {
272 DCHECK(status_label);
275 if (service->HasSyncSetupCompleted() &&
276 service->IsPassphraseRequired()) {
277 if (service->passphrase_required_reason() == syncer::REASON_ENCRYPTION) {
278 // First machine migrating to passwords. Show as a promotion.
279 if (status_label && link_label) {
280 status_label->assign(
281 l10n_util::GetStringFUTF16(
282 IDS_SYNC_NTP_PASSWORD_PROMO,
283 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
285 l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
289 // NOT first machine.
290 // Show a link and present as an error ("needs attention").
291 if (status_label && link_label) {
292 status_label->assign(string16());
294 l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
300 // Fallback to default.
301 return GetStatusInfo(service, signin, WITH_HTML, status_label, link_label);
306 MessageType GetStatusLabels(ProfileSyncService* service,
307 const SigninManagerBase& signin,
308 StatusLabelStyle style,
309 string16* status_label,
310 string16* link_label) {
311 DCHECK(status_label);
313 return sync_ui_util::GetStatusInfo(
314 service, signin, style, status_label, link_label);
317 MessageType GetStatusLabelsForNewTabPage(ProfileSyncService* service,
318 const SigninManagerBase& signin,
319 string16* status_label,
320 string16* link_label) {
321 DCHECK(status_label);
323 return sync_ui_util::GetStatusInfoForNewTabPage(
324 service, signin, status_label, link_label);
327 void GetStatusLabelsForSyncGlobalError(ProfileSyncService* service,
328 const SigninManagerBase& signin,
329 string16* menu_label,
330 string16* bubble_message,
331 string16* bubble_accept_label) {
333 DCHECK(bubble_message);
334 DCHECK(bubble_accept_label);
335 *menu_label = string16();
336 *bubble_message = string16();
337 *bubble_accept_label = string16();
339 // Only display an error if we've completed sync setup.
340 if (!service->HasSyncSetupCompleted())
343 // Display a passphrase error if we have one.
344 if (service->IsPassphraseRequired() &&
345 service->IsPassphraseRequiredForDecryption()) {
346 // This is not the first machine so ask user to enter passphrase.
347 *menu_label = l10n_util::GetStringUTF16(
348 IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM);
349 string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
350 *bubble_message = l10n_util::GetStringFUTF16(
351 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE, product_name);
352 *bubble_accept_label = l10n_util::GetStringUTF16(
353 IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT);
358 MessageType GetStatus(
359 ProfileSyncService* service, const SigninManagerBase& signin) {
360 return sync_ui_util::GetStatusInfo(service, signin, WITH_HTML, NULL, NULL);
363 string16 ConstructTime(int64 time_in_int) {
364 base::Time time = base::Time::FromInternalValue(time_in_int);
366 // If time is null the format function returns a time in 1969.
369 return base::TimeFormatFriendlyDateAndTime(time);
372 } // namespace sync_ui_util