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