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

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

Powered by Google App Engine
This is Rietveld 408576698