Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: chrome/browser/ui/webui/settings/sync_handler.cc

Issue 1503333003: Settings People Rewrite: Make Sync/Sign-in naming consistent to People. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix an egreious git cl format error Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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/ui/webui/settings/sync_handler.h"
6
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/i18n/time_formatting.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/values.h"
18 #include "chrome/browser/lifetime/application_lifetime.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_info_cache.h"
21 #include "chrome/browser/profiles/profile_metrics.h"
22 #include "chrome/browser/profiles/profile_window.h"
23 #include "chrome/browser/signin/chrome_signin_helper.h"
24 #include "chrome/browser/signin/signin_error_controller_factory.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/browser/signin/signin_promo.h"
27 #include "chrome/browser/sync/profile_sync_service_factory.h"
28 #include "chrome/browser/sync/sync_ui_util.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #include "chrome/browser/ui/singleton_tabs.h"
32 #include "chrome/browser/ui/user_manager.h"
33 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
34 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
35 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
36 #include "chrome/common/chrome_switches.h"
37 #include "chrome/grit/generated_resources.h"
38 #include "components/browser_sync/browser/profile_sync_service.h"
39 #include "components/signin/core/browser/signin_error_controller.h"
40 #include "components/signin/core/browser/signin_header_helper.h"
41 #include "components/signin/core/browser/signin_metrics.h"
42 #include "components/signin/core/common/profile_management_switches.h"
43 #include "components/signin/core/common/signin_pref_names.h"
44 #include "components/sync_driver/sync_prefs.h"
45 #include "content/public/browser/render_view_host.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/browser/web_contents_delegate.h"
48 #include "google_apis/gaia/gaia_auth_util.h"
49 #include "google_apis/gaia/gaia_constants.h"
50 #include "net/base/url_util.h"
51 #include "ui/base/l10n/l10n_util.h"
52
53 #if defined(OS_CHROMEOS)
54 #include "components/signin/core/browser/signin_manager_base.h"
55 #else
56 #include "components/signin/core/browser/signin_manager.h"
57 #endif
58
59 using content::WebContents;
60 using l10n_util::GetStringFUTF16;
61 using l10n_util::GetStringUTF16;
62
63 namespace {
64
65 // A structure which contains all the configuration information for sync.
66 struct SyncConfigInfo {
67 SyncConfigInfo();
68 ~SyncConfigInfo();
69
70 bool encrypt_all;
71 bool sync_everything;
72 bool sync_nothing;
73 syncer::ModelTypeSet data_types;
74 std::string passphrase;
75 bool passphrase_is_gaia;
76 };
77
78 SyncConfigInfo::SyncConfigInfo()
79 : encrypt_all(false),
80 sync_everything(false),
81 sync_nothing(false),
82 passphrase_is_gaia(false) {
83 }
84
85 SyncConfigInfo::~SyncConfigInfo() {}
86
87 bool GetConfiguration(const std::string& json, SyncConfigInfo* config) {
88 scoped_ptr<base::Value> parsed_value = base::JSONReader::Read(json);
89 base::DictionaryValue* result;
90 if (!parsed_value || !parsed_value->GetAsDictionary(&result)) {
91 DLOG(ERROR) << "GetConfiguration() not passed a Dictionary";
92 return false;
93 }
94
95 if (!result->GetBoolean("syncAllDataTypes", &config->sync_everything)) {
96 DLOG(ERROR) << "GetConfiguration() not passed a syncAllDataTypes value";
97 return false;
98 }
99
100 if (!result->GetBoolean("syncNothing", &config->sync_nothing)) {
101 DLOG(ERROR) << "GetConfiguration() not passed a syncNothing value";
102 return false;
103 }
104
105 DCHECK(!(config->sync_everything && config->sync_nothing))
106 << "syncAllDataTypes and syncNothing cannot both be true";
107
108 syncer::ModelTypeNameMap type_names = syncer::GetUserSelectableTypeNameMap();
109
110 for (syncer::ModelTypeNameMap::const_iterator it = type_names.begin();
111 it != type_names.end(); ++it) {
112 std::string key_name = it->second + std::string("Synced");
113 bool sync_value;
114 if (!result->GetBoolean(key_name, &sync_value)) {
115 DLOG(ERROR) << "GetConfiguration() not passed a value for " << key_name;
116 return false;
117 }
118 if (sync_value)
119 config->data_types.Put(it->first);
120 }
121
122 // Encryption settings.
123 if (!result->GetBoolean("encryptAllData", &config->encrypt_all)) {
124 DLOG(ERROR) << "GetConfiguration() not passed a value for encryptAllData";
125 return false;
126 }
127
128 // Passphrase settings.
129 bool have_passphrase;
130 if (!result->GetBoolean("usePassphrase", &have_passphrase)) {
131 DLOG(ERROR) << "GetConfiguration() not passed a usePassphrase value";
132 return false;
133 }
134
135 if (have_passphrase) {
136 if (!result->GetBoolean("isGooglePassphrase",
137 &config->passphrase_is_gaia)) {
138 DLOG(ERROR) << "GetConfiguration() not passed isGooglePassphrase value";
139 return false;
140 }
141 if (!result->GetString("passphrase", &config->passphrase)) {
142 DLOG(ERROR) << "GetConfiguration() not passed a passphrase value";
143 return false;
144 }
145 }
146 return true;
147 }
148
149 } // namespace
150
151 namespace settings {
152
153 SyncHandler::SyncHandler(Profile* profile)
154 : profile_(profile),
155 configuring_sync_(false),
156 sync_service_observer_(this) {
157 PrefService* prefs = profile_->GetPrefs();
158 profile_pref_registrar_.Init(prefs);
159 profile_pref_registrar_.Add(
160 prefs::kSigninAllowed, base::Bind(&SyncHandler::OnSigninAllowedPrefChange,
161 base::Unretained(this)));
162
163 ProfileSyncService* sync_service(
164 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_));
165 if (sync_service)
166 sync_service_observer_.Add(sync_service);
167 }
168
169 SyncHandler::~SyncHandler() {
170 // Just exit if running unit tests (no actual WebUI is attached).
171 if (!web_ui())
172 return;
173
174 // This case is hit when the user performs a back navigation.
175 CloseSyncSetup();
176 }
177
178 void SyncHandler::ConfigureSyncDone() {
179 base::StringValue page("done");
180 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.showSyncSetupPage",
181 page);
182
183 // Suppress the sign in promo once the user starts sync. This way the user
184 // doesn't see the sign in promo even if they sign out later on.
185 signin::SetUserSkippedPromo(profile_);
186
187 ProfileSyncService* service = GetSyncService();
188 DCHECK(service);
189 if (!service->HasSyncSetupCompleted()) {
190 // This is the first time configuring sync, so log it.
191 base::FilePath profile_file_path = profile_->GetPath();
192 ProfileMetrics::LogProfileSyncSignIn(profile_file_path);
193
194 // We're done configuring, so notify ProfileSyncService that it is OK to
195 // start syncing.
196 service->SetSetupInProgress(false);
197 service->SetSyncSetupCompleted();
198 }
199 }
200
201 bool SyncHandler::IsActiveLogin() const {
202 // LoginUIService can be nullptr if page is brought up in incognito mode
203 // (i.e. if the user is running in guest mode in cros and brings up settings).
204 LoginUIService* service = GetLoginUIService();
205 return service && (service->current_login_ui() == this);
206 }
207
208 void SyncHandler::RegisterMessages() {
209 web_ui()->RegisterMessageCallback(
210 "SyncSetupDidClosePage",
211 base::Bind(&SyncHandler::OnDidClosePage,
212 base::Unretained(this)));
213 web_ui()->RegisterMessageCallback(
214 "SyncSetupConfigure",
215 base::Bind(&SyncHandler::HandleConfigure,
216 base::Unretained(this)));
217 web_ui()->RegisterMessageCallback(
218 "SyncSetupShowSetupUI",
219 base::Bind(&SyncHandler::HandleShowSetupUI,
220 base::Unretained(this)));
221 web_ui()->RegisterMessageCallback(
222 "SyncSetupCloseTimeout",
223 base::Bind(&SyncHandler::HandleCloseTimeout, base::Unretained(this)));
224 web_ui()->RegisterMessageCallback(
225 "SyncSetupGetSyncStatus",
226 base::Bind(&SyncHandler::HandleGetSyncStatus, base::Unretained(this)));
227 web_ui()->RegisterMessageCallback(
228 "SyncSetupManageOtherPeople",
229 base::Bind(&SyncHandler::HandleManageOtherPeople,
230 base::Unretained(this)));
231 #if defined(OS_CHROMEOS)
232 web_ui()->RegisterMessageCallback(
233 "SyncSetupDoSignOutOnAuthError",
234 base::Bind(&SyncHandler::HandleDoSignOutOnAuthError,
235 base::Unretained(this)));
236 #else
237 web_ui()->RegisterMessageCallback("SyncSetupStopSyncing",
238 base::Bind(&SyncHandler::HandleStopSyncing,
239 base::Unretained(this)));
240 web_ui()->RegisterMessageCallback("SyncSetupStartSignIn",
241 base::Bind(&SyncHandler::HandleStartSignin,
242 base::Unretained(this)));
243 #endif
244 }
245
246 #if !defined(OS_CHROMEOS)
247 void SyncHandler::DisplayGaiaLogin(signin_metrics::AccessPoint access_point) {
248 DCHECK(!sync_startup_tracker_);
249 // Advanced options are no longer being configured if the login screen is
250 // visible. If the user exits the signin wizard after this without
251 // configuring sync, CloseSyncSetup() will ensure they are logged out.
252 configuring_sync_ = false;
253 DisplayGaiaLoginInNewTabOrWindow(access_point);
254 }
255
256 void SyncHandler::DisplayGaiaLoginInNewTabOrWindow(
257 signin_metrics::AccessPoint access_point) {
258 Browser* browser = chrome::FindBrowserWithWebContents(
259 web_ui()->GetWebContents());
260 bool force_new_tab = false;
261 if (!browser) {
262 // Settings is not displayed in a browser window. Open a new window.
263 browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile_,
264 chrome::GetActiveDesktop()));
265 force_new_tab = true;
266 }
267
268 // If the signin manager already has an authenticated username, this is a
269 // re-auth scenario, and we need to ensure that the user signs in with the
270 // same email address.
271 GURL url;
272 if (SigninManagerFactory::GetForProfile(
273 browser->profile())->IsAuthenticated()) {
274 UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
275 signin_metrics::HISTOGRAM_REAUTH_SHOWN,
276 signin_metrics::HISTOGRAM_REAUTH_MAX);
277
278 SigninErrorController* error_controller =
279 SigninErrorControllerFactory::GetForProfile(browser->profile());
280 DCHECK(error_controller->HasError());
281 if (!force_new_tab) {
282 browser->window()->ShowAvatarBubbleFromAvatarButton(
283 BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH,
284 signin::ManageAccountsParams(), access_point);
285 } else {
286 url = signin::GetReauthURL(
287 access_point, signin_metrics::Reason::REASON_REAUTHENTICATION,
288 browser->profile(), error_controller->error_account_id());
289 }
290 } else {
291 if (!force_new_tab) {
292 browser->window()->ShowAvatarBubbleFromAvatarButton(
293 BrowserWindow::AVATAR_BUBBLE_MODE_SIGNIN,
294 signin::ManageAccountsParams(), access_point);
295 } else {
296 url = signin::GetPromoURL(
297 access_point, signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT,
298 true);
299 }
300 }
301
302 if (url.is_valid())
303 chrome::ShowSingletonTab(browser, url);
304 }
305 #endif
306
307 bool SyncHandler::PrepareSyncSetup() {
308 // If the wizard is already visible, just focus that one.
309 if (FocusExistingWizardIfPresent()) {
310 if (!IsActiveLogin())
311 CloseSyncSetup();
312 return false;
313 }
314
315 // Notify services that login UI is now active.
316 GetLoginUIService()->SetLoginUI(this);
317
318 ProfileSyncService* service = GetSyncService();
319 if (service)
320 service->SetSetupInProgress(true);
321
322 return true;
323 }
324
325 void SyncHandler::DisplaySpinner() {
326 configuring_sync_ = true;
327 base::StringValue page("spinner");
328 base::DictionaryValue args;
329
330 const int kTimeoutSec = 30;
331 DCHECK(!backend_start_timer_);
332 backend_start_timer_.reset(new base::OneShotTimer());
333 backend_start_timer_->Start(FROM_HERE,
334 base::TimeDelta::FromSeconds(kTimeoutSec),
335 this, &SyncHandler::DisplayTimeout);
336
337 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.showSyncSetupPage",
338 page, args);
339 }
340
341 // TODO(kochi): Handle error conditions other than timeout.
342 // http://crbug.com/128692
343 void SyncHandler::DisplayTimeout() {
344 // Stop a timer to handle timeout in waiting for checking network connection.
345 backend_start_timer_.reset();
346
347 // Do not listen to sync startup events.
348 sync_startup_tracker_.reset();
349
350 base::StringValue page("timeout");
351 base::DictionaryValue args;
352 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.showSyncSetupPage",
353 page, args);
354 }
355
356 void SyncHandler::OnDidClosePage(const base::ListValue* args) {
357 CloseSyncSetup();
358 }
359
360 void SyncHandler::SyncStartupFailed() {
361 // Stop a timer to handle timeout in waiting for checking network connection.
362 backend_start_timer_.reset();
363
364 // Just close the sync overlay (the idea is that the base settings page will
365 // display the current error.)
366 CloseUI();
367 }
368
369 void SyncHandler::SyncStartupCompleted() {
370 ProfileSyncService* service = GetSyncService();
371 DCHECK(service->IsBackendInitialized());
372
373 // Stop a timer to handle timeout in waiting for checking network connection.
374 backend_start_timer_.reset();
375
376 DisplayConfigureSync(false);
377 }
378
379 ProfileSyncService* SyncHandler::GetSyncService() const {
380 return profile_->IsSyncAllowed()
381 ? ProfileSyncServiceFactory::GetForProfile(profile_)
382 : nullptr;
383 }
384
385 void SyncHandler::HandleConfigure(const base::ListValue* args) {
386 DCHECK(!sync_startup_tracker_);
387 std::string json;
388 if (!args->GetString(0, &json)) {
389 NOTREACHED() << "Could not read JSON argument";
390 return;
391 }
392 if (json.empty()) {
393 NOTREACHED();
394 return;
395 }
396
397 SyncConfigInfo configuration;
398 if (!GetConfiguration(json, &configuration)) {
399 // The page sent us something that we didn't understand.
400 // This probably indicates a programming error.
401 NOTREACHED();
402 return;
403 }
404
405 // Start configuring the ProfileSyncService using the configuration passed
406 // to us from the JS layer.
407 ProfileSyncService* service = GetSyncService();
408
409 // If the sync engine has shutdown for some reason, just close the sync
410 // dialog.
411 if (!service || !service->IsBackendInitialized()) {
412 CloseUI();
413 return;
414 }
415
416 // Disable sync, but remain signed in if the user selected "Sync nothing" in
417 // the advanced settings dialog. Note: In order to disable sync across
418 // restarts on Chrome OS, we must call RequestStop(CLEAR_DATA), which
419 // suppresses sync startup in addition to disabling it.
420 if (configuration.sync_nothing) {
421 ProfileSyncService::SyncEvent(
422 ProfileSyncService::STOP_FROM_ADVANCED_DIALOG);
423 CloseUI();
424 service->RequestStop(ProfileSyncService::CLEAR_DATA);
425 service->SetSetupInProgress(false);
426 return;
427 }
428
429 // Don't allow "encrypt all" if the ProfileSyncService doesn't allow it.
430 // The UI is hidden, but the user may have enabled it e.g. by fiddling with
431 // the web inspector.
432 if (!service->IsEncryptEverythingAllowed())
433 configuration.encrypt_all = false;
434
435 // Note: Data encryption will not occur until configuration is complete
436 // (when the PSS receives its CONFIGURE_DONE notification from the sync
437 // backend), so the user still has a chance to cancel out of the operation
438 // if (for example) some kind of passphrase error is encountered.
439 if (configuration.encrypt_all)
440 service->EnableEncryptEverything();
441
442 bool passphrase_failed = false;
443 if (!configuration.passphrase.empty()) {
444 // We call IsPassphraseRequired() here (instead of
445 // IsPassphraseRequiredForDecryption()) because the user may try to enter
446 // a passphrase even though no encrypted data types are enabled.
447 if (service->IsPassphraseRequired()) {
448 // If we have pending keys, try to decrypt them with the provided
449 // passphrase. We track if this succeeds or fails because a failed
450 // decryption should result in an error even if there aren't any encrypted
451 // data types.
452 passphrase_failed =
453 !service->SetDecryptionPassphrase(configuration.passphrase);
454 } else {
455 // OK, the user sent us a passphrase, but we don't have pending keys. So
456 // it either means that the pending keys were resolved somehow since the
457 // time the UI was displayed (re-encryption, pending passphrase change,
458 // etc) or the user wants to re-encrypt.
459 if (!configuration.passphrase_is_gaia &&
460 !service->IsUsingSecondaryPassphrase()) {
461 // User passed us a secondary passphrase, and the data is encrypted
462 // with a GAIA passphrase so they must want to encrypt.
463 service->SetEncryptionPassphrase(configuration.passphrase,
464 ProfileSyncService::EXPLICIT);
465 }
466 }
467 }
468
469 bool user_was_prompted_for_passphrase =
470 service->IsPassphraseRequiredForDecryption();
471 service->OnUserChoseDatatypes(configuration.sync_everything,
472 configuration.data_types);
473
474 // Need to call IsPassphraseRequiredForDecryption() *after* calling
475 // OnUserChoseDatatypes() because the user may have just disabled the
476 // encrypted datatypes (in which case we just want to exit, not prompt the
477 // user for a passphrase).
478 if (passphrase_failed || service->IsPassphraseRequiredForDecryption()) {
479 // We need a passphrase, or the user's attempt to set a passphrase failed -
480 // prompt them again. This covers a few subtle cases:
481 // 1) The user enters an incorrect passphrase *and* disabled the encrypted
482 // data types. In that case we want to notify the user that the
483 // passphrase was incorrect even though there are no longer any encrypted
484 // types enabled (IsPassphraseRequiredForDecryption() == false).
485 // 2) The user doesn't enter any passphrase. In this case, we won't call
486 // SetDecryptionPassphrase() (passphrase_failed == false), but we still
487 // want to display an error message to let the user know that their
488 // blank passphrase entry is not acceptable.
489 // 3) The user just enabled an encrypted data type - in this case we don't
490 // want to display an "invalid passphrase" error, since it's the first
491 // time the user is seeing the prompt.
492 DisplayConfigureSync(passphrase_failed || user_was_prompted_for_passphrase);
493 } else {
494 // No passphrase is required from the user so mark the configuration as
495 // complete and close the sync setup overlay.
496 ConfigureSyncDone();
497 }
498
499 ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_CUSTOMIZE);
500 if (configuration.encrypt_all)
501 ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_ENCRYPT);
502 if (configuration.passphrase_is_gaia && !configuration.passphrase.empty())
503 ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_PASSPHRASE);
504 if (!configuration.sync_everything)
505 ProfileMetrics::LogProfileSyncInfo(ProfileMetrics::SYNC_CHOOSE);
506 }
507
508 void SyncHandler::HandleShowSetupUI(const base::ListValue* args) {
509 if (!GetSyncService()) {
510 CloseUI();
511 return;
512 }
513
514 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
515 if (!signin->IsAuthenticated()) {
516 // For web-based signin, the signin page is not displayed in an overlay
517 // on the settings page. So if we get here, it must be due to the user
518 // cancelling signin (by reloading the sync settings page during initial
519 // signin) or by directly navigating to settings/syncSetup
520 // (http://crbug.com/229836). So just exit and go back to the settings page.
521 DLOG(WARNING) << "Cannot display sync setup UI when not signed in";
522 CloseUI();
523 return;
524 }
525
526 // If a setup wizard is already present, but not on this page, close the
527 // blank setup overlay on this page by showing the "done" page. This can
528 // happen if the user navigates to chrome://settings/syncSetup in more than
529 // one tab. See crbug.com/261566.
530 // Note: The following block will transfer focus to the existing wizard.
531 if (IsExistingWizardPresent() && !IsActiveLogin())
532 CloseUI();
533
534 // If a setup wizard is present on this page or another, bring it to focus.
535 // Otherwise, display a new one on this page.
536 if (!FocusExistingWizardIfPresent())
537 OpenSyncSetup(args);
538 }
539
540 #if defined(OS_CHROMEOS)
541 // On ChromeOS, we need to sign out the user session to fix an auth error, so
542 // the user goes through the real signin flow to generate a new auth token.
543 void SyncHandler::HandleDoSignOutOnAuthError(const base::ListValue* args) {
544 DVLOG(1) << "Signing out the user to fix a sync error.";
545 chrome::AttemptUserExit();
546 }
547 #endif
548
549 #if !defined(OS_CHROMEOS)
550 void SyncHandler::HandleStartSignin(const base::ListValue* args) {
551 // Should only be called if the user is not already signed in.
552 DCHECK(!SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated());
553 OpenSyncSetup(args);
554 }
555
556 void SyncHandler::HandleStopSyncing(const base::ListValue* args) {
557 if (GetSyncService())
558 ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
559 SigninManagerFactory::GetForProfile(profile_)
560 ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS);
561
562 bool delete_profile = false;
563 if (args->GetBoolean(0, &delete_profile) && delete_profile) {
564 // Do as BrowserOptionsHandler::DeleteProfile().
565 options::helper::DeleteProfileAtPath(profile_->GetPath(), web_ui());
566 }
567 }
568 #endif
569
570 void SyncHandler::HandleCloseTimeout(const base::ListValue* args) {
571 CloseSyncSetup();
572 }
573
574 void SyncHandler::HandleGetSyncStatus(const base::ListValue* /* args */) {
575 UpdateSyncState();
576 }
577
578 void SyncHandler::HandleManageOtherPeople(const base::ListValue* /* args */) {
579 UserManager::Show(base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL,
580 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
581 }
582
583 void SyncHandler::CloseSyncSetup() {
584 // Stop a timer to handle timeout in waiting for checking network connection.
585 backend_start_timer_.reset();
586
587 // Clear the sync startup tracker, since the setup wizard is being closed.
588 sync_startup_tracker_.reset();
589
590 ProfileSyncService* sync_service = GetSyncService();
591 if (IsActiveLogin()) {
592 // Don't log a cancel event if the sync setup dialog is being
593 // automatically closed due to an auth error.
594 if (!sync_service || (!sync_service->HasSyncSetupCompleted() &&
595 sync_service->GetAuthError().state() == GoogleServiceAuthError::NONE)) {
596 if (configuring_sync_) {
597 ProfileSyncService::SyncEvent(
598 ProfileSyncService::CANCEL_DURING_CONFIGURE);
599
600 // If the user clicked "Cancel" while setting up sync, disable sync
601 // because we don't want the sync backend to remain in the
602 // first-setup-incomplete state.
603 // Note: In order to disable sync across restarts on Chrome OS,
604 // we must call RequestStop(CLEAR_DATA), which suppresses sync startup
605 // in addition to disabling it.
606 if (sync_service) {
607 DVLOG(1) << "Sync setup aborted by user action";
608 sync_service->RequestStop(ProfileSyncService::CLEAR_DATA);
609 #if !defined(OS_CHROMEOS)
610 // Sign out the user on desktop Chrome if they click cancel during
611 // initial setup.
612 // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049.
613 if (sync_service->IsFirstSetupInProgress()) {
614 SigninManagerFactory::GetForProfile(profile_)
615 ->SignOut(signin_metrics::ABORT_SIGNIN);
616 }
617 #endif
618 }
619 }
620 }
621
622 GetLoginUIService()->LoginUIClosed(this);
623 }
624
625 // Alert the sync service anytime the sync setup dialog is closed. This can
626 // happen due to the user clicking the OK or Cancel button, or due to the
627 // dialog being closed by virtue of sync being disabled in the background.
628 if (sync_service)
629 sync_service->SetSetupInProgress(false);
630
631 configuring_sync_ = false;
632 }
633
634 void SyncHandler::OpenSyncSetup(const base::ListValue* args) {
635 if (!PrepareSyncSetup())
636 return;
637
638 // There are several different UI flows that can bring the user here:
639 // 1) Signin promo.
640 // 2) Normal signin through settings page (IsAuthenticated() is false).
641 // 3) Previously working credentials have expired.
642 // 4) User is signed in, but has stopped sync via the google dashboard, and
643 // signout is prohibited by policy so we need to force a re-auth.
644 // 5) User clicks [Advanced Settings] button on options page while already
645 // logged in.
646 // 6) One-click signin (credentials are already available, so should display
647 // sync configure UI, not login UI).
648 // 7) User re-enables sync after disabling it via advanced settings.
649 #if !defined(OS_CHROMEOS)
650 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
651
652 if (!signin->IsAuthenticated() ||
653 SigninErrorControllerFactory::GetForProfile(profile_)->HasError()) {
654 // User is not logged in (cases 1-2), or login has been specially requested
655 // because previously working credentials have expired (case 3). Close sync
656 // setup including any visible overlays, and display the gaia auth page.
657 // Control will be returned to the sync settings page once auth is complete.
658 CloseUI();
659 if (args) {
660 std::string access_point = base::UTF16ToUTF8(ExtractStringValue(args));
661 if (access_point == "access-point-supervised-user") {
662 DisplayGaiaLogin(
663 signin_metrics::AccessPoint::ACCESS_POINT_SUPERVISED_USER);
664 return;
665 }
666 }
667 DisplayGaiaLogin(signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS);
668 return;
669 }
670 #endif
671 if (!GetSyncService()) {
672 // This can happen if the user directly navigates to /settings/syncSetup.
673 DLOG(WARNING) << "Cannot display sync UI when sync is disabled";
674 CloseUI();
675 return;
676 }
677
678 // User is already logged in. They must have brought up the config wizard
679 // via the "Advanced..." button or through One-Click signin (cases 4-6), or
680 // they are re-enabling sync after having disabled it (case 7).
681 DisplayConfigureSync(false);
682 }
683
684 void SyncHandler::OpenConfigureSync() {
685 if (!PrepareSyncSetup())
686 return;
687
688 DisplayConfigureSync(false);
689 }
690
691 void SyncHandler::FocusUI() {
692 DCHECK(IsActiveLogin());
693 WebContents* web_contents = web_ui()->GetWebContents();
694 web_contents->GetDelegate()->ActivateContents(web_contents);
695 }
696
697 void SyncHandler::CloseUI() {
698 CloseSyncSetup();
699 base::StringValue page("done");
700 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.showSyncSetupPage",
701 page);
702 }
703
704 void SyncHandler::GoogleSigninSucceeded(const std::string& /* account_id */,
705 const std::string& /* username */,
706 const std::string& /* password */) {
707 UpdateSyncState();
708 }
709
710 void SyncHandler::GoogleSignedOut(const std::string& /* account_id */,
711 const std::string& /* username */) {
712 UpdateSyncState();
713 }
714
715 void SyncHandler::OnStateChanged() {
716 UpdateSyncState();
717 }
718
719 scoped_ptr<base::DictionaryValue> SyncHandler::GetSyncStateDictionary() {
720 // The items which are to be written into |sync_status| are also described in
721 // chrome/browser/resources/options/browser_options.js in @typedef
722 // for SyncStatus. Please update it whenever you add or remove any keys here.
723 scoped_ptr<base::DictionaryValue> sync_status(new base::DictionaryValue);
724 if (profile_->IsGuestSession()) {
725 // Cannot display signin status when running in guest mode on chromeos
726 // because there is no SigninManager.
727 sync_status->SetBoolean("signinAllowed", false);
728 return sync_status.Pass();
729 }
730
731 sync_status->SetBoolean("supervisedUser", profile_->IsSupervised());
732 sync_status->SetBoolean("childUser", profile_->IsChild());
733
734 bool signout_prohibited = false;
735 #if !defined(OS_CHROMEOS)
736 // Signout is not allowed if the user has policy (crbug.com/172204).
737 signout_prohibited =
738 SigninManagerFactory::GetForProfile(profile_)->IsSignoutProhibited();
739 #endif
740
741 ProfileSyncService* service =
742 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_);
743 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
744 DCHECK(signin);
745 sync_status->SetBoolean("signoutAllowed", !signout_prohibited);
746 sync_status->SetBoolean("signinAllowed", signin->IsSigninAllowed());
747 sync_status->SetBoolean("syncSystemEnabled", (service != nullptr));
748 sync_status->SetBoolean("setupCompleted",
749 service && service->HasSyncSetupCompleted());
750 sync_status->SetBoolean(
751 "setupInProgress",
752 service && !service->IsManaged() && service->IsFirstSetupInProgress());
753
754 base::string16 status_label;
755 base::string16 link_label;
756 bool status_has_error =
757 sync_ui_util::GetStatusLabels(profile_, service, *signin,
758 sync_ui_util::WITH_HTML, &status_label,
759 &link_label) == sync_ui_util::SYNC_ERROR;
760 sync_status->SetString("statusText", status_label);
761 sync_status->SetString("actionLinkText", link_label);
762 sync_status->SetBoolean("hasError", status_has_error);
763
764 sync_status->SetBoolean("managed", service && service->IsManaged());
765 sync_status->SetBoolean("signedIn", signin->IsAuthenticated());
766 sync_status->SetBoolean("hasUnrecoverableError",
767 service && service->HasUnrecoverableError());
768
769 return sync_status.Pass();
770 }
771
772 bool SyncHandler::IsExistingWizardPresent() {
773 LoginUIService* service = GetLoginUIService();
774 DCHECK(service);
775 return service->current_login_ui() != nullptr;
776 }
777
778 bool SyncHandler::FocusExistingWizardIfPresent() {
779 if (!IsExistingWizardPresent())
780 return false;
781
782 LoginUIService* service = GetLoginUIService();
783 DCHECK(service);
784 service->current_login_ui()->FocusUI();
785 return true;
786 }
787
788 void SyncHandler::DisplayConfigureSync(bool passphrase_failed) {
789 // Should never call this when we are not signed in.
790 DCHECK(SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated());
791 ProfileSyncService* service = GetSyncService();
792 DCHECK(service);
793 if (!service->IsBackendInitialized()) {
794 service->RequestStart();
795
796 // See if it's even possible to bring up the sync backend - if not
797 // (unrecoverable error?), don't bother displaying a spinner that will be
798 // immediately closed because this leads to some ugly infinite UI loop (see
799 // http://crbug.com/244769).
800 if (SyncStartupTracker::GetSyncServiceState(profile_) !=
801 SyncStartupTracker::SYNC_STARTUP_ERROR) {
802 DisplaySpinner();
803 }
804
805 // Start SyncSetupTracker to wait for sync to initialize.
806 sync_startup_tracker_.reset(new SyncStartupTracker(profile_, this));
807 return;
808 }
809
810 // Should only get here if user is signed in and sync is initialized, so no
811 // longer need a SyncStartupTracker.
812 sync_startup_tracker_.reset();
813 configuring_sync_ = true;
814 DCHECK(service->IsBackendInitialized())
815 << "Cannot configure sync until the sync backend is initialized";
816
817 // Setup args for the sync configure screen:
818 // syncAllDataTypes: true if the user wants to sync everything
819 // syncNothing: true if the user wants to sync nothing
820 // <data_type>Registered: true if the associated data type is supported
821 // <data_type>Synced: true if the user wants to sync that specific data type
822 // encryptionEnabled: true if sync supports encryption
823 // encryptAllData: true if user wants to encrypt all data (not just
824 // passwords)
825 // usePassphrase: true if the data is encrypted with a secondary passphrase
826 // show_passphrase: true if a passphrase is needed to decrypt the sync data
827 base::DictionaryValue args;
828
829 // Tell the UI layer which data types are registered/enabled by the user.
830 const syncer::ModelTypeSet registered_types =
831 service->GetRegisteredDataTypes();
832 const syncer::ModelTypeSet preferred_types = service->GetPreferredDataTypes();
833 const syncer::ModelTypeSet enforced_types = service->GetForcedDataTypes();
834 syncer::ModelTypeNameMap type_names = syncer::GetUserSelectableTypeNameMap();
835 for (syncer::ModelTypeNameMap::const_iterator it = type_names.begin();
836 it != type_names.end(); ++it) {
837 syncer::ModelType sync_type = it->first;
838 const std::string key_name = it->second;
839 args.SetBoolean(key_name + "Registered", registered_types.Has(sync_type));
840 args.SetBoolean(key_name + "Synced", preferred_types.Has(sync_type));
841 args.SetBoolean(key_name + "Enforced", enforced_types.Has(sync_type));
842 // TODO(treib): How do we want to handle pref groups, i.e. when only some of
843 // the sync types behind a checkbox are force-enabled? crbug.com/403326
844 }
845 sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
846 args.SetBoolean("passphraseFailed", passphrase_failed);
847 args.SetBoolean("syncAllDataTypes", sync_prefs.HasKeepEverythingSynced());
848 args.SetBoolean("syncNothing", false); // Always false during initial setup.
849 args.SetBoolean("encryptAllData", service->IsEncryptEverythingEnabled());
850 args.SetBoolean("encryptAllDataAllowed",
851 service->IsEncryptEverythingAllowed());
852
853 // We call IsPassphraseRequired() here, instead of calling
854 // IsPassphraseRequiredForDecryption(), because we want to show the passphrase
855 // UI even if no encrypted data types are enabled.
856 args.SetBoolean("showPassphrase", service->IsPassphraseRequired());
857
858 // To distinguish between FROZEN_IMPLICIT_PASSPHRASE and CUSTOM_PASSPHRASE
859 // we only set usePassphrase for CUSTOM_PASSPHRASE.
860 args.SetBoolean("usePassphrase",
861 service->GetPassphraseType() == syncer::CUSTOM_PASSPHRASE);
862 base::Time passphrase_time = service->GetExplicitPassphraseTime();
863 syncer::PassphraseType passphrase_type = service->GetPassphraseType();
864 if (!passphrase_time.is_null()) {
865 base::string16 passphrase_time_str =
866 base::TimeFormatShortDate(passphrase_time);
867 args.SetString(
868 "enterPassphraseBody",
869 GetStringFUTF16(IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE,
870 passphrase_time_str));
871 args.SetString(
872 "enterGooglePassphraseBody",
873 GetStringFUTF16(IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY_WITH_DATE,
874 passphrase_time_str));
875 switch (passphrase_type) {
876 case syncer::FROZEN_IMPLICIT_PASSPHRASE:
877 args.SetString(
878 "fullEncryptionBody",
879 GetStringFUTF16(IDS_SYNC_FULL_ENCRYPTION_BODY_GOOGLE_WITH_DATE,
880 passphrase_time_str));
881 break;
882 case syncer::CUSTOM_PASSPHRASE:
883 args.SetString(
884 "fullEncryptionBody",
885 GetStringFUTF16(IDS_SYNC_FULL_ENCRYPTION_BODY_CUSTOM_WITH_DATE,
886 passphrase_time_str));
887 break;
888 default:
889 args.SetString(
890 "fullEncryptionBody",
891 GetStringUTF16(IDS_SYNC_FULL_ENCRYPTION_BODY_CUSTOM));
892 break;
893 }
894 } else if (passphrase_type == syncer::CUSTOM_PASSPHRASE) {
895 args.SetString(
896 "fullEncryptionBody",
897 GetStringUTF16(IDS_SYNC_FULL_ENCRYPTION_BODY_CUSTOM));
898 } else {
899 args.SetString(
900 "fullEncryptionBody",
901 GetStringUTF16(IDS_SYNC_FULL_ENCRYPTION_DATA));
902 }
903
904 base::StringValue page("configure");
905 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.showSyncSetupPage",
906 page, args);
907
908 // Make sure the tab used for the Gaia sign in does not cover the settings
909 // tab.
910 FocusUI();
911 }
912
913 LoginUIService* SyncHandler::GetLoginUIService() const {
914 return LoginUIServiceFactory::GetForProfile(profile_);
915 }
916
917 void SyncHandler::UpdateSyncState() {
918 web_ui()->CallJavascriptFunction("settings.SyncPrivateApi.sendSyncStatus",
919 *GetSyncStateDictionary());
920 }
921
922 void SyncHandler::OnSigninAllowedPrefChange() {
923 UpdateSyncState();
924 }
925
926 } // namespace settings
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698