sync_setup_flow.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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_setup_flow.h" 6 7#include "app/gfx/font_util.h" 8#include "base/callback.h" 9#include "base/json/json_reader.h" 10#include "base/json/json_writer.h" 11#include "base/metrics/histogram.h" 12#include "base/string_util.h" 13#include "base/utf_string_conversions.h" 14#include "base/values.h" 15#include "chrome/browser/dom_ui/dom_ui_util.h" 16#include "chrome/browser/platform_util.h" 17#include "chrome/browser/prefs/pref_service.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/renderer_host/render_view_host.h" 20#include "chrome/browser/sync/profile_sync_service.h" 21#include "chrome/browser/tab_contents/tab_contents.h" 22#include "chrome/browser/ui/browser.h" 23#include "chrome/browser/ui/browser_list.h" 24#if defined(OS_MACOSX) 25#include "chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h" 26#endif 27#include "chrome/common/net/gaia/google_service_auth_error.h" 28#include "chrome/common/pref_names.h" 29#include "gfx/font.h" 30#include "grit/locale_settings.h" 31 32// XPath expression for finding specific iframes. 33static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']"; 34static const wchar_t* kChooseDataTypesIFrameXPath = 35 L"//iframe[@id='configure']"; 36static const wchar_t* kPassphraseIFrameXPath = 37 L"//iframe[@id='passphrase']"; 38static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']"; 39 40void FlowHandler::RegisterMessages() { 41 dom_ui_->RegisterMessageCallback("SubmitAuth", 42 NewCallback(this, &FlowHandler::HandleSubmitAuth)); 43 dom_ui_->RegisterMessageCallback("Configure", 44 NewCallback(this, &FlowHandler::HandleConfigure)); 45 dom_ui_->RegisterMessageCallback("Passphrase", 46 NewCallback(this, &FlowHandler::HandlePassphraseEntry)); 47 dom_ui_->RegisterMessageCallback("FirstPassphrase", 48 NewCallback(this, &FlowHandler::HandleFirstPassphrase)); 49 dom_ui_->RegisterMessageCallback("GoToDashboard", 50 NewCallback(this, &FlowHandler::HandleGoToDashboard)); 51} 52 53static bool GetAuthData(const std::string& json, 54 std::string* username, 55 std::string* password, 56 std::string* captcha, 57 std::string* access_code) { 58 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false)); 59 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) 60 return false; 61 62 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get()); 63 if (!result->GetString("user", username) || 64 !result->GetString("pass", password) || 65 !result->GetString("captcha", captcha) || 66 !result->GetString("access_code", access_code)) { 67 return false; 68 } 69 return true; 70} 71 72bool GetPassphrase(const std::string& json, std::string* passphrase, 73 std::string* mode) { 74 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false)); 75 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) 76 return false; 77 78 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get()); 79 return result->GetString("passphrase", passphrase) && 80 result->GetString("mode", mode); 81} 82 83bool GetFirstPassphrase(const std::string& json, 84 std::string* option, 85 std::string* passphrase) { 86 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false)); 87 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) 88 return false; 89 90 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get()); 91 return result->GetString("option", option) && 92 result->GetString("passphrase", passphrase); 93} 94 95static bool GetConfiguration(const std::string& json, 96 SyncConfiguration* config) { 97 scoped_ptr<Value> parsed_value(base::JSONReader::Read(json, false)); 98 if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) 99 return false; 100 101 DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get()); 102 if (!result->GetBoolean("keepEverythingSynced", &config->sync_everything)) 103 return false; 104 105 // These values need to be kept in sync with where they are written in 106 // choose_datatypes.html. 107 bool sync_bookmarks; 108 if (!result->GetBoolean("syncBookmarks", &sync_bookmarks)) 109 return false; 110 if (sync_bookmarks) 111 config->data_types.insert(syncable::BOOKMARKS); 112 113 bool sync_preferences; 114 if (!result->GetBoolean("syncPreferences", &sync_preferences)) 115 return false; 116 if (sync_preferences) 117 config->data_types.insert(syncable::PREFERENCES); 118 119 bool sync_themes; 120 if (!result->GetBoolean("syncThemes", &sync_themes)) 121 return false; 122 if (sync_themes) 123 config->data_types.insert(syncable::THEMES); 124 125 bool sync_passwords; 126 if (!result->GetBoolean("syncPasswords", &sync_passwords)) 127 return false; 128 if (sync_passwords) 129 config->data_types.insert(syncable::PASSWORDS); 130 131 bool sync_autofill; 132 if (!result->GetBoolean("syncAutofill", &sync_autofill)) 133 return false; 134 if (sync_autofill) 135 config->data_types.insert(syncable::AUTOFILL); 136 137 bool sync_extensions; 138 if (!result->GetBoolean("syncExtensions", &sync_extensions)) 139 return false; 140 if (sync_extensions) 141 config->data_types.insert(syncable::EXTENSIONS); 142 143 bool sync_typed_urls; 144 if (!result->GetBoolean("syncTypedUrls", &sync_typed_urls)) 145 return false; 146 if (sync_typed_urls) 147 config->data_types.insert(syncable::TYPED_URLS); 148 149 bool sync_sessions; 150 if (!result->GetBoolean("syncSessions", &sync_sessions)) 151 return false; 152 if (sync_sessions) 153 config->data_types.insert(syncable::SESSIONS); 154 155 bool sync_apps; 156 if (!result->GetBoolean("syncApps", &sync_apps)) 157 return false; 158 if (sync_apps) 159 config->data_types.insert(syncable::APPS); 160 161 // Encyption settings. 162 if (!result->GetBoolean("usePassphrase", &config->use_secondary_passphrase)) 163 return false; 164 if (config->use_secondary_passphrase && 165 !result->GetString("passphrase", &config->secondary_passphrase)) 166 return false; 167 168 return true; 169} 170 171void FlowHandler::HandleSubmitAuth(const ListValue* args) { 172 std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args)); 173 std::string username, password, captcha, access_code; 174 if (json.empty()) 175 return; 176 177 if (!GetAuthData(json, &username, &password, &captcha, &access_code)) { 178 // The page sent us something that we didn't understand. 179 // This probably indicates a programming error. 180 NOTREACHED(); 181 return; 182 } 183 184 if (flow_) 185 flow_->OnUserSubmittedAuth(username, password, captcha, access_code); 186} 187 188void FlowHandler::HandleConfigure(const ListValue* args) { 189 std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args)); 190 SyncConfiguration configuration; 191 192 if (json.empty()) 193 return; 194 195 if (!GetConfiguration(json, &configuration)) { 196 // The page sent us something that we didn't understand. 197 // This probably indicates a programming error. 198 NOTREACHED(); 199 return; 200 } 201 202 DCHECK(flow_); 203 flow_->OnUserConfigured(configuration); 204 205 return; 206} 207 208void FlowHandler::HandlePassphraseEntry(const ListValue* args) { 209 std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args)); 210 211 if (json.empty()) 212 return; 213 214 std::string passphrase; 215 std::string mode; 216 if (!GetPassphrase(json, &passphrase, &mode)) { 217 // Couldn't understand what the page sent. Indicates a programming error. 218 NOTREACHED(); 219 return; 220 } 221 222 DCHECK(flow_); 223 flow_->OnPassphraseEntry(passphrase, mode); 224} 225 226void FlowHandler::HandleFirstPassphrase(const ListValue* args) { 227 std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args)); 228 229 if (json.empty()) 230 return; 231 232 std::string option; 233 std::string passphrase; 234 if (!GetFirstPassphrase(json, &option, &passphrase)) { 235 // Page sent result which couldn't be parsed. Programming error. 236 NOTREACHED(); 237 return; 238 } 239 240 DCHECK(flow_); 241 flow_->OnFirstPassphraseEntry(option, passphrase); 242} 243 244void FlowHandler::HandleGoToDashboard(const ListValue* args) { 245 flow_->OnGoToDashboard(); 246} 247 248// Called by SyncSetupFlow::Advance. 249void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) { 250 // Whenever you start a wizard, you pass in an arg so it starts on the right 251 // iframe (see setup_flow.html's showTheRightIframe() method). But when you 252 // transition from one flow to another, you have to explicitly call the JS 253 // function to show the next iframe. 254 // So if you ever made a wizard that involved a gaia login as not the first 255 // frame, this call would be necessary to ensure that this method actually 256 // shows the gaia login. 257 if (dom_ui_) 258 dom_ui_->CallJavascriptFunction(L"showGaiaLoginIframe"); 259 260 std::string json; 261 base::JSONWriter::Write(&args, false, &json); 262 std::wstring javascript = std::wstring(L"showGaiaLogin") + 263 L"(" + UTF8ToWide(json) + L");"; 264 ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); 265} 266 267void FlowHandler::ShowGaiaSuccessAndClose() { 268 ExecuteJavascriptInIFrame(kLoginIFrameXPath, L"showGaiaSuccessAndClose();"); 269} 270 271void FlowHandler::ShowGaiaSuccessAndSettingUp() { 272 ExecuteJavascriptInIFrame(kLoginIFrameXPath, 273 L"showGaiaSuccessAndSettingUp();"); 274} 275 276// Called by SyncSetupFlow::Advance. 277void FlowHandler::ShowConfigure(const DictionaryValue& args) { 278 // If you're starting the wizard at the configure screen (i.e. from 279 // "Customize Sync"), this will be redundant. However, if you're coming from 280 // another wizard state, this will make sure Choose Data Types is on top. 281 if (dom_ui_) 282 dom_ui_->CallJavascriptFunction(L"showConfigure"); 283 284 std::string json; 285 base::JSONWriter::Write(&args, false, &json); 286 std::wstring javascript = std::wstring(L"initializeConfigureDialog") + 287 L"(" + UTF8ToWide(json) + L");"; 288 ExecuteJavascriptInIFrame(kChooseDataTypesIFrameXPath, javascript); 289} 290 291void FlowHandler::ShowPassphraseEntry(const DictionaryValue& args) { 292 if (dom_ui_) 293 dom_ui_->CallJavascriptFunction(L"showPassphrase"); 294 295 std::string json; 296 base::JSONWriter::Write(&args, false, &json); 297 std::wstring script = std::wstring(L"setupPassphraseDialog") + 298 L"(" + UTF8ToWide(json) + L");"; 299 ExecuteJavascriptInIFrame(kPassphraseIFrameXPath, script); 300} 301 302void FlowHandler::ShowFirstPassphrase(const DictionaryValue& args) { 303 if (dom_ui_) 304 dom_ui_->CallJavascriptFunction(L"showFirstPassphrase"); 305 306 std::string json; 307 base::JSONWriter::Write(&args, false, &json); 308 std::wstring script = std::wstring(L"setupDialog") + 309 L"(" + UTF8ToWide(json) + L");"; 310 ExecuteJavascriptInIFrame(kPassphraseIFrameXPath, script); 311} 312 313void FlowHandler::ShowSettingUp() { 314 if (dom_ui_) 315 dom_ui_->CallJavascriptFunction(L"showSettingUp"); 316} 317 318void FlowHandler::ShowSetupDone(const std::wstring& user) { 319 StringValue synced_to_string(l10n_util::GetStringFUTF8( 320 IDS_SYNC_NTP_SYNCED_TO, WideToUTF16Hack(user))); 321 std::string json; 322 base::JSONWriter::Write(&synced_to_string, false, &json); 323 std::wstring javascript = std::wstring(L"setSyncedToUser") + 324 L"(" + UTF8ToWide(json) + L");"; 325 ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); 326 327 if (dom_ui_) 328 dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string); 329 330 ExecuteJavascriptInIFrame(kDoneIframeXPath, 331 L"onPageShown();"); 332} 333 334void FlowHandler::ShowFirstTimeDone(const std::wstring& user) { 335 ExecuteJavascriptInIFrame(kDoneIframeXPath, 336 L"setShowFirstTimeSetupSummary();"); 337 ShowSetupDone(user); 338} 339 340void FlowHandler::ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, 341 const std::wstring& js) { 342 if (dom_ui_) { 343 RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); 344 rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); 345 } 346} 347 348// Use static Run method to get an instance. 349SyncSetupFlow::SyncSetupFlow(SyncSetupWizard::State start_state, 350 SyncSetupWizard::State end_state, 351 const std::string& args, 352 SyncSetupFlowContainer* container, 353 ProfileSyncService* service) 354 : container_(container), 355 dialog_start_args_(args), 356 current_state_(start_state), 357 end_state_(end_state), 358 login_start_time_(base::TimeTicks::Now()), 359 flow_handler_(new FlowHandler()), 360 owns_flow_handler_(true), 361 service_(service), 362 html_dialog_window_(NULL) { 363 flow_handler_->set_flow(this); 364} 365 366SyncSetupFlow::~SyncSetupFlow() { 367 flow_handler_->set_flow(NULL); 368 if (owns_flow_handler_) { 369 delete flow_handler_; 370 } 371} 372 373void SyncSetupFlow::GetDialogSize(gfx::Size* size) const { 374 PrefService* prefs = service_->profile()->GetPrefs(); 375 gfx::Font approximate_web_font = gfx::Font( 376 UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily)), 377 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); 378 379 *size = gfx::GetLocalizedContentsSizeForFont( 380 IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, 381 IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, 382 approximate_web_font); 383 384#if defined(OS_MACOSX) 385 // NOTE(akalin): This is a hack to work around a problem with font height on 386 // windows. Basically font metrics are incorrectly returned in logical units 387 // instead of pixels on Windows. Logical units are very commonly 96 DPI 388 // so our localized char/line counts are too small by a factor of 96/72. 389 // So we compensate for this on non-windows platform. 390 // 391 // TODO(akalin): Remove this hack once we fix the windows font problem (or at 392 // least work around it in some other place). 393 float scale_hack = 96.f/72.f; 394 size->set_width(size->width() * scale_hack); 395 size->set_height(size->height() * scale_hack); 396#endif 397} 398 399std::string SyncSetupFlow::GetDialogArgs() const { 400 return dialog_start_args_; 401} 402 403// A callback to notify the delegate that the dialog closed. 404void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) { 405 DCHECK(json_retval.empty()); 406 container_->set_flow(NULL); // Sever ties from the wizard. 407 if (current_state_ == SyncSetupWizard::DONE || 408 current_state_ == SyncSetupWizard::DONE_FIRST_TIME) { 409 service_->SetSyncSetupCompleted(); 410 } 411 412 // Record the state at which the user cancelled the signon dialog. 413 switch (current_state_) { 414 case SyncSetupWizard::GAIA_LOGIN: 415 ProfileSyncService::SyncEvent( 416 ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); 417 break; 418 case SyncSetupWizard::GAIA_SUCCESS: 419 ProfileSyncService::SyncEvent( 420 ProfileSyncService::CANCEL_DURING_SIGNON); 421 break; 422 case SyncSetupWizard::CONFIGURE: 423 case SyncSetupWizard::ENTER_PASSPHRASE: 424 case SyncSetupWizard::SETTING_UP: 425 ProfileSyncService::SyncEvent( 426 ProfileSyncService::CANCEL_DURING_CONFIGURE); 427 break; 428 case SyncSetupWizard::DONE_FIRST_TIME: 429 case SyncSetupWizard::DONE: 430 // TODO(sync): rename this histogram; it's tracking authorization AND 431 // initial sync download time. 432 UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime", 433 base::TimeTicks::Now() - login_start_time_); 434 break; 435 default: 436 break; 437 } 438 439 service_->OnUserCancelledDialog(); 440 delete this; 441} 442 443std::wstring SyncSetupFlow::GetDialogTitle() const { 444 return UTF16ToWideHack( 445 l10n_util::GetStringUTF16(IDS_SYNC_MY_BOOKMARKS_LABEL)); 446} 447 448bool SyncSetupFlow::IsDialogModal() const { 449 return false; 450} 451 452bool SyncSetupFlow::ShouldShowDialogTitle() const { 453 return true; 454} 455 456// static 457void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service, 458 DictionaryValue* args) { 459 args->SetString("iframeToShow", "login"); 460 const GoogleServiceAuthError& error = service->GetAuthError(); 461 if (!service->last_attempted_user_email().empty()) { 462 args->SetString("user", service->last_attempted_user_email()); 463 args->SetInteger("error", error.state()); 464 args->SetBoolean("editable_user", true); 465 } else { 466 string16 user; 467 if (!service->cros_user().empty()) 468 user = UTF8ToUTF16(service->cros_user()); 469 else 470 user = service->GetAuthenticatedUsername(); 471 args->SetString("user", user); 472 args->SetInteger("error", 0); 473 args->SetBoolean("editable_user", user.empty()); 474 } 475 476 args->SetString("captchaUrl", error.captcha().image_url.spec()); 477} 478 479// static 480void SyncSetupFlow::GetArgsForEnterPassphrase( 481 const ProfileSyncService* service, DictionaryValue* args) { 482 args->SetString("iframeToShow", "passphrase"); 483 if (service->IsUsingSecondaryPassphrase()) 484 args->SetString("mode", "enter"); 485 else 486 args->SetString("mode", "gaia"); 487} 488 489// static 490void SyncSetupFlow::GetArgsForConfigure(ProfileSyncService* service, 491 DictionaryValue* args) { 492 args->SetString("iframeToShow", "configure"); 493 494 // By default start on the data types tab. 495 args->SetString("initialTab", "data-type"); 496 497 args->SetBoolean("keepEverythingSynced", 498 service->profile()->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)); 499 500 // Bookmarks, Preferences, and Themes are launched for good, there's no 501 // going back now. Check if the other data types are registered though. 502 syncable::ModelTypeSet registered_types; 503 service->GetRegisteredDataTypes(®istered_types); 504 args->SetBoolean("passwordsRegistered", 505 registered_types.count(syncable::PASSWORDS) > 0); 506 args->SetBoolean("autofillRegistered", 507 registered_types.count(syncable::AUTOFILL) > 0); 508 args->SetBoolean("extensionsRegistered", 509 registered_types.count(syncable::EXTENSIONS) > 0); 510 args->SetBoolean("typedUrlsRegistered", 511 registered_types.count(syncable::TYPED_URLS) > 0); 512 args->SetBoolean("appsRegistered", 513 registered_types.count(syncable::APPS) > 0); 514 args->SetBoolean("sessionsRegistered", 515 registered_types.count(syncable::SESSIONS) > 0); 516 args->SetBoolean("syncBookmarks", 517 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncBookmarks)); 518 args->SetBoolean("syncPreferences", 519 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPreferences)); 520 args->SetBoolean("syncThemes", 521 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncThemes)); 522 args->SetBoolean("syncPasswords", 523 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPasswords)); 524 args->SetBoolean("syncAutofill", 525 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncAutofill)); 526 args->SetBoolean("syncExtensions", 527 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncExtensions)); 528 args->SetBoolean("syncSessions", 529 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncSessions)); 530 args->SetBoolean("syncTypedUrls", 531 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncTypedUrls)); 532 args->SetBoolean("syncApps", 533 service->profile()->GetPrefs()->GetBoolean(prefs::kSyncApps)); 534 535 // Load the parameters for the encryption tab. 536 args->SetBoolean("usePassphrase", service->IsUsingSecondaryPassphrase()); 537} 538 539void SyncSetupFlow::GetDOMMessageHandlers( 540 std::vector<DOMMessageHandler*>* handlers) const { 541 handlers->push_back(flow_handler_); 542 // We don't own flow_handler_ anymore, but it sticks around until at least 543 // right after OnDialogClosed() is called (and this object is destroyed). 544 owns_flow_handler_ = false; 545} 546 547// Returns true if the flow should advance to |state| based on |current_state_|. 548bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { 549 switch (state) { 550 case SyncSetupWizard::GAIA_LOGIN: 551 return current_state_ == SyncSetupWizard::FATAL_ERROR || 552 current_state_ == SyncSetupWizard::GAIA_LOGIN; 553 case SyncSetupWizard::GAIA_SUCCESS: 554 return current_state_ == SyncSetupWizard::GAIA_LOGIN; 555 case SyncSetupWizard::CONFIGURE: 556 return current_state_ == SyncSetupWizard::GAIA_SUCCESS; 557 case SyncSetupWizard::ENTER_PASSPHRASE: 558 return current_state_ == SyncSetupWizard::CONFIGURE || 559 current_state_ == SyncSetupWizard::SETTING_UP; 560 case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: 561 return current_state_ == SyncSetupWizard::CONFIGURE; 562 case SyncSetupWizard::SETTING_UP: 563 return current_state_ == SyncSetupWizard::CONFIGURE || 564 current_state_ == SyncSetupWizard::ENTER_PASSPHRASE || 565 current_state_ == SyncSetupWizard::PASSPHRASE_MIGRATION; 566 case SyncSetupWizard::FATAL_ERROR: 567 return true; // You can always hit the panic button. 568 case SyncSetupWizard::DONE_FIRST_TIME: 569 case SyncSetupWizard::DONE: 570 return current_state_ == SyncSetupWizard::SETTING_UP || 571 current_state_ == SyncSetupWizard::ENTER_PASSPHRASE; 572 default: 573 NOTREACHED() << "Unhandled State: " << state; 574 return false; 575 } 576} 577 578void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) { 579 if (!ShouldAdvance(advance_state)) { 580 LOG(WARNING) << "Invalid state change from " 581 << current_state_ << " to " << advance_state; 582 return; 583 } 584 585 switch (advance_state) { 586 case SyncSetupWizard::GAIA_LOGIN: { 587 DictionaryValue args; 588 SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); 589 flow_handler_->ShowGaiaLogin(args); 590 break; 591 } 592 case SyncSetupWizard::GAIA_SUCCESS: 593 if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) { 594 flow_handler_->ShowGaiaSuccessAndClose(); 595 break; 596 } 597 advance_state = SyncSetupWizard::CONFIGURE; 598 // Fall through. 599 case SyncSetupWizard::CONFIGURE: { 600 DictionaryValue args; 601 SyncSetupFlow::GetArgsForConfigure(service_, &args); 602 args.SetString("initialTab", "data-type"); 603 flow_handler_->ShowConfigure(args); 604 break; 605 } 606 case SyncSetupWizard::ENTER_PASSPHRASE: { 607 DictionaryValue args; 608 SyncSetupFlow::GetArgsForEnterPassphrase(service_, &args); 609 flow_handler_->ShowPassphraseEntry(args); 610 break; 611 } 612 case SyncSetupWizard::PASSPHRASE_MIGRATION: { 613 DictionaryValue args; 614 args.SetString("iframeToShow", "firstpassphrase"); 615 flow_handler_->ShowFirstPassphrase(args); 616 break; 617 } 618 case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: { 619 DictionaryValue args; 620 SyncSetupFlow::GetArgsForConfigure(service_, &args); 621 args.SetBoolean("was_aborted", true); 622 flow_handler_->ShowConfigure(args); 623 break; 624 } 625 case SyncSetupWizard::SETTING_UP: { 626 flow_handler_->ShowSettingUp(); 627 break; 628 } 629 case SyncSetupWizard::FATAL_ERROR: { 630 // This shows the user the "Could not connect to server" error. 631 // TODO(sync): Update this error messaging. 632 DictionaryValue args; 633 SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); 634 args.SetInteger("error", GoogleServiceAuthError::CONNECTION_FAILED); 635 flow_handler_->ShowGaiaLogin(args); 636 break; 637 } 638 case SyncSetupWizard::DONE_FIRST_TIME: 639 flow_handler_->ShowFirstTimeDone( 640 UTF16ToWide(service_->GetAuthenticatedUsername())); 641 break; 642 case SyncSetupWizard::DONE: 643 flow_handler_->ShowSetupDone( 644 UTF16ToWide(service_->GetAuthenticatedUsername())); 645 break; 646 default: 647 NOTREACHED() << "Invalid advance state: " << advance_state; 648 } 649 current_state_ = advance_state; 650} 651 652void SyncSetupFlow::Focus() { 653#if defined(OS_MACOSX) 654 if (html_dialog_window_) { 655 platform_util::ActivateWindow(html_dialog_window_); 656 } 657#else 658 // TODO(csilv): We don't currently have a way to get the reference to the 659 // dialog on windows/linux. This can be resolved by a cross platform 660 // implementation of HTML dialogs as described by akalin below. 661 NOTIMPLEMENTED(); 662#endif // defined(OS_MACOSX) 663} 664 665GURL SyncSetupFlow::GetDialogContentURL() const { 666 return GURL("chrome://syncresources/setup"); 667} 668 669// static 670SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service, 671 SyncSetupFlowContainer* container, 672 SyncSetupWizard::State start, 673 SyncSetupWizard::State end, 674 gfx::NativeWindow parent_window) { 675 DictionaryValue args; 676 if (start == SyncSetupWizard::GAIA_LOGIN) 677 SyncSetupFlow::GetArgsForGaiaLogin(service, &args); 678 else if (start == SyncSetupWizard::CONFIGURE) 679 SyncSetupFlow::GetArgsForConfigure(service, &args); 680 else if (start == SyncSetupWizard::ENTER_PASSPHRASE) 681 SyncSetupFlow::GetArgsForEnterPassphrase(service, &args); 682 else if (start == SyncSetupWizard::PASSPHRASE_MIGRATION) 683 args.SetString("iframeToShow", "firstpassphrase"); 684 685 std::string json_args; 686 base::JSONWriter::Write(&args, false, &json_args); 687 688 SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args, 689 container, service); 690#if defined(OS_MACOSX) 691 // TODO(akalin): Figure out a cleaner way to do this than to have this 692 // gross per-OS behavior, i.e. have a cross-platform ShowHtmlDialog() 693 // function that is not tied to a browser instance. Note that if we do 694 // that, we'll have to fix sync_setup_wizard_unittest.cc as it relies on 695 // being able to intercept ShowHtmlDialog() calls. 696 flow->html_dialog_window_ = 697 html_dialog_window_controller::ShowHtmlDialog( 698 flow, service->profile()); 699#else 700 Browser* b = BrowserList::GetLastActive(); 701 if (b) { 702 b->BrowserShowHtmlDialog(flow, parent_window); 703 } else { 704 delete flow; 705 return NULL; 706 } 707#endif // defined(OS_MACOSX) 708 return flow; 709} 710 711void SyncSetupFlow::OnUserSubmittedAuth(const std::string& username, 712 const std::string& password, 713 const std::string& captcha, 714 const std::string& access_code) { 715 service_->OnUserSubmittedAuth(username, password, captcha, access_code); 716} 717 718void SyncSetupFlow::OnUserConfigured(const SyncConfiguration& configuration) { 719 // Go to the "loading..." screen." 720 Advance(SyncSetupWizard::SETTING_UP); 721 722 // If we are activating the passphrase, we need to have one supplied. 723 DCHECK(service_->IsUsingSecondaryPassphrase() || 724 !configuration.use_secondary_passphrase || 725 configuration.secondary_passphrase.length() > 0); 726 727 if (configuration.use_secondary_passphrase && 728 !service_->IsUsingSecondaryPassphrase()) { 729 service_->SetPassphrase(configuration.secondary_passphrase, true); 730 } 731 732 service_->OnUserChoseDatatypes(configuration.sync_everything, 733 configuration.data_types); 734} 735 736void SyncSetupFlow::OnPassphraseEntry(const std::string& passphrase, 737 const std::string& mode) { 738 Advance(SyncSetupWizard::SETTING_UP); 739 service_->SetPassphrase(passphrase, true); 740} 741 742void SyncSetupFlow::OnFirstPassphraseEntry(const std::string& option, 743 const std::string& passphrase) { 744 Advance(SyncSetupWizard::SETTING_UP); 745 if (option == "explicit") { 746 service_->SetPassphrase(passphrase, true); 747 } else if (option == "nothanks") { 748 // User opted out of encrypted sync, need to turn off encrypted 749 // data types. 750 syncable::ModelTypeSet registered_types; 751 service_->GetRegisteredDataTypes(®istered_types); 752 registered_types.erase(syncable::PASSWORDS); 753 service_->OnUserChoseDatatypes(false, registered_types); 754 } else if (option == "google") { 755 // Implicit passphrase already set up. 756 Advance(SyncSetupWizard::DONE); 757 } 758} 759 760void SyncSetupFlow::OnGoToDashboard() { 761 BrowserList::GetLastActive()->OpenPrivacyDashboardTabAndActivate(); 762} 763