- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / sync_ui_util.cc
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/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"
37
38 typedef GoogleServiceAuthError AuthError;
39
40 namespace sync_ui_util {
41
42 namespace {
43
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());
51
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,
56                                         user_name);
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,
60                                         user_name);
61     }
62   }
63
64   if (!service || !service->sync_initialized()) {
65     // User is not signed in, or sync is still initializing.
66     return string16();
67   }
68
69   DCHECK(!user_name.empty());
70
71   // Message may also carry additional advice with an HTML link, if acceptable.
72   switch (style) {
73     case PLAIN_TEXT:
74       return l10n_util::GetStringFUTF16(
75           IDS_SYNC_ACCOUNT_SYNCING_TO_USER,
76           user_name);
77     case WITH_HTML:
78       return l10n_util::GetStringFUTF16(
79           IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK,
80           user_name,
81           ASCIIToUTF16(chrome::kSyncGoogleDashboardURL));
82     default:
83       NOTREACHED();
84       return NULL;
85   }
86 }
87
88 void GetStatusForActionableError(
89     const syncer::SyncProtocolError& error,
90     string16* status_label) {
91   DCHECK(status_label);
92   switch (error.action) {
93     case syncer::STOP_AND_RESTART_SYNC:
94        status_label->assign(
95            l10n_util::GetStringUTF16(IDS_SYNC_STOP_AND_RESTART_SYNC));
96       break;
97     case syncer::UPGRADE_CLIENT:
98        status_label->assign(
99            l10n_util::GetStringFUTF16(IDS_SYNC_UPGRADE_CLIENT,
100                l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
101       break;
102     case syncer::ENABLE_SYNC_ON_ACCOUNT:
103        status_label->assign(
104            l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT));
105     break;
106     case syncer::CLEAR_USER_DATA_AND_RESYNC:
107        status_label->assign(
108            l10n_util::GetStringUTF16(IDS_SYNC_CLEAR_USER_DATA));
109       break;
110     default:
111       NOTREACHED();
112   }
113 }
114
115 // TODO(akalin): Write unit tests for these three functions below.
116
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);
124
125   MessageType result_type(SYNCED);
126
127   if (signin.GetAuthenticatedUsername().empty())
128     return PRE_SYNCED;
129
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.
134
135     if (service && service->HasUnrecoverableError()) {
136       if (status_label) {
137         status_label->assign(l10n_util::GetStringFUTF16(
138             IDS_SYNC_STATUS_UNRECOVERABLE_ERROR,
139             l10n_util::GetStringUTF16(IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL)));
140       }
141       return SYNC_ERROR;
142     }
143
144     // For auth errors first check if an auth is in progress.
145     if (signin.AuthInProgress()) {
146       if (status_label) {
147         status_label->assign(
148           l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
149       }
150       return PRE_SYNCED;
151     }
152
153     // Check for sync errors if the sync service is enabled.
154     if (service) {
155       // Since there is no auth in progress, check for an auth error first.
156       AuthError auth_error =
157           SigninGlobalError::GetForProfile(service->profile())->
158               GetLastAuthError();
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);
163         return SYNC_ERROR;
164       }
165
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)) {
170         if (status_label) {
171           GetStatusForActionableError(status.sync_protocol_error,
172                                       status_label);
173         }
174         return SYNC_ERROR;
175       }
176
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));
188             link_label->assign(
189                 l10n_util::GetStringUTF16(IDS_SYNC_PASSWORD_SYNC_ATTENTION));
190           }
191           return SYNC_PROMO;
192         }
193       }
194
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) {
199         if (status_label) {
200           status_label->assign(GetSyncedStateStatusLabel(service,
201                                                          signin,
202                                                          style));
203         }
204         return PRE_SYNCED;
205       }
206     }
207
208     // There is no error. Display "Last synced..." message.
209     if (status_label)
210       status_label->assign(GetSyncedStateStatusLabel(service, signin, style));
211     return SYNCED;
212   } else {
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();
222       if (status_label) {
223         status_label->assign(
224             l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS));
225       }
226       if (signin.AuthInProgress()) {
227         if (status_label) {
228           status_label->assign(
229               l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL));
230         }
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);
237         }
238         result_type = SYNC_ERROR;
239       }
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)) {
245         if (status_label) {
246           GetStatusForActionableError(status.sync_protocol_error,
247               status_label);
248         }
249       } else if (status_label) {
250         status_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ERROR));
251       }
252     } else if (!signin.GetAuthenticatedUsername().empty()) {
253       // The user is signed in, but sync has been stopped.
254       if (status_label) {
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;
260       }
261     }
262   }
263   return result_type;
264 }
265
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);
273   DCHECK(link_label);
274
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)));
284         link_label->assign(
285             l10n_util::GetStringUTF16(IDS_SYNC_NTP_PASSWORD_ENABLE));
286       }
287       return SYNC_PROMO;
288     } else {
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());
293         link_label->assign(
294             l10n_util::GetStringUTF16(IDS_SYNC_CONFIGURE_ENCRYPTION));
295       }
296       return SYNC_ERROR;
297     }
298   }
299
300   // Fallback to default.
301   return GetStatusInfo(service, signin, WITH_HTML, status_label, link_label);
302 }
303
304 }  // namespace
305
306 MessageType GetStatusLabels(ProfileSyncService* service,
307                             const SigninManagerBase& signin,
308                             StatusLabelStyle style,
309                             string16* status_label,
310                             string16* link_label) {
311   DCHECK(status_label);
312   DCHECK(link_label);
313   return sync_ui_util::GetStatusInfo(
314       service, signin, style, status_label, link_label);
315 }
316
317 MessageType GetStatusLabelsForNewTabPage(ProfileSyncService* service,
318                                          const SigninManagerBase& signin,
319                                          string16* status_label,
320                                          string16* link_label) {
321   DCHECK(status_label);
322   DCHECK(link_label);
323   return sync_ui_util::GetStatusInfoForNewTabPage(
324       service, signin, status_label, link_label);
325 }
326
327 void GetStatusLabelsForSyncGlobalError(ProfileSyncService* service,
328                                        const SigninManagerBase& signin,
329                                        string16* menu_label,
330                                        string16* bubble_message,
331                                        string16* bubble_accept_label) {
332   DCHECK(menu_label);
333   DCHECK(bubble_message);
334   DCHECK(bubble_accept_label);
335   *menu_label = string16();
336   *bubble_message = string16();
337   *bubble_accept_label = string16();
338
339   // Only display an error if we've completed sync setup.
340   if (!service->HasSyncSetupCompleted())
341     return;
342
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);
354     return;
355   }
356 }
357
358 MessageType GetStatus(
359     ProfileSyncService* service, const SigninManagerBase& signin) {
360   return sync_ui_util::GetStatusInfo(service, signin, WITH_HTML, NULL, NULL);
361 }
362
363 string16 ConstructTime(int64 time_in_int) {
364   base::Time time = base::Time::FromInternalValue(time_in_int);
365
366   // If time is null the format function returns a time in 1969.
367   if (time.is_null())
368     return string16();
369   return base::TimeFormatFriendlyDateAndTime(time);
370 }
371
372 }  // namespace sync_ui_util