existing_user_controller.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/chromeos/login/existing_user_controller.h" 6 7#include <algorithm> 8#include <functional> 9#include <map> 10 11#include "app/l10n_util.h" 12#include "app/resource_bundle.h" 13#include "base/command_line.h" 14#include "base/message_loop.h" 15#include "base/stl_util-inl.h" 16#include "base/utf_string_conversions.h" 17#include "base/values.h" 18#include "chrome/browser/chromeos/boot_times_loader.h" 19#include "chrome/browser/chromeos/cros/cros_library.h" 20#include "chrome/browser/chromeos/cros/cryptohome_library.h" 21#include "chrome/browser/chromeos/cros/login_library.h" 22#include "chrome/browser/chromeos/cros/network_library.h" 23#include "chrome/browser/chromeos/login/background_view.h" 24#include "chrome/browser/chromeos/login/help_app_launcher.h" 25#include "chrome/browser/chromeos/login/helper.h" 26#include "chrome/browser/chromeos/login/login_utils.h" 27#include "chrome/browser/chromeos/login/message_bubble.h" 28#include "chrome/browser/chromeos/login/wizard_controller.h" 29#include "chrome/browser/chromeos/status/status_area_view.h" 30#include "chrome/browser/chromeos/user_cros_settings_provider.h" 31#include "chrome/browser/chromeos/view_ids.h" 32#include "chrome/browser/chromeos/wm_ipc.h" 33#include "chrome/browser/profiles/profile_manager.h" 34#include "chrome/browser/views/window.h" 35#include "chrome/common/chrome_switches.h" 36#include "chrome/common/net/gaia/google_service_auth_error.h" 37#include "gfx/native_widget_types.h" 38#include "grit/chromium_strings.h" 39#include "grit/generated_resources.h" 40#include "grit/theme_resources.h" 41#include "views/screen.h" 42#include "views/widget/widget_gtk.h" 43#include "views/window/window.h" 44 45namespace chromeos { 46 47namespace { 48 49// Max number of users we'll show. The true max is the min of this and the 50// number of windows that fit on the screen. 51const size_t kMaxUsers = 6; 52 53// Minimum number of users we'll show (including Guest and New User pods). 54const size_t kMinUsers = 3; 55 56// Used to indicate no user has been selected. 57const size_t kNotSelected = -1; 58 59// Offset of cursor in first position from edit left side. It's used to position 60// info bubble arrow to cursor. 61const int kCursorOffset = 5; 62 63// Url for setting up sync authentication. 64const char kSettingsSyncLoginUrl[] = "chrome://settings/personal"; 65 66// URL that will be opened on when user logs in first time on the device. 67const char kGetStartedURL[] = 68 "chrome-extension://nbaambmfhicobichobkkokacjbaoinda/index.html"; 69 70// Path to extracted version of Get Started app. 71const char kGetStartedPath[] = "/usr/share/chromeos-assets/getstarted"; 72 73// Used to handle the asynchronous response of deleting a cryptohome directory. 74class RemoveAttempt : public CryptohomeLibrary::Delegate { 75 public: 76 explicit RemoveAttempt(const std::string& user_email) 77 : user_email_(user_email) { 78 if (CrosLibrary::Get()->EnsureLoaded()) { 79 CrosLibrary::Get()->GetCryptohomeLibrary()->AsyncRemove( 80 user_email_, this); 81 } 82 } 83 84 void OnComplete(bool success, int return_code) { 85 // Log the error, but there's not much we can do. 86 if (!success) { 87 VLOG(1) << "Removal of cryptohome for " << user_email_ 88 << " failed, return code: " << return_code; 89 } 90 delete this; 91 } 92 93 private: 94 std::string user_email_; 95}; 96 97// Checks if display names are unique. If there are duplicates, enables 98// tooltips with full emails to let users distinguish their accounts. 99// Otherwise, disables the tooltips. 100void EnableTooltipsIfNeeded(const std::vector<UserController*>& controllers) { 101 std::map<std::string, int> visible_display_names; 102 for (size_t i = 0; i + 1 < controllers.size(); ++i) { 103 const std::string& display_name = 104 controllers[i]->user().GetDisplayName(); 105 ++visible_display_names[display_name]; 106 } 107 for (size_t i = 0; i < controllers.size(); ++i) { 108 const std::string& display_name = 109 controllers[i]->user().GetDisplayName(); 110 bool show_tooltip = controllers[i]->is_new_user() || 111 controllers[i]->is_guest() || 112 visible_display_names[display_name] > 1; 113 controllers[i]->EnableNameTooltip(show_tooltip); 114 } 115} 116 117} // namespace 118 119ExistingUserController* 120 ExistingUserController::delete_scheduled_instance_ = NULL; 121 122// TODO(xiyuan): Wait for the cached settings update before using them. 123ExistingUserController::ExistingUserController( 124 const std::vector<UserManager::User>& users, 125 const gfx::Rect& background_bounds) 126 : background_bounds_(background_bounds), 127 background_window_(NULL), 128 background_view_(NULL), 129 selected_view_index_(kNotSelected), 130 num_login_attempts_(0), 131 bubble_(NULL), 132 user_settings_(new UserCrosSettingsProvider), 133 method_factory_(this) { 134 if (delete_scheduled_instance_) 135 delete_scheduled_instance_->Delete(); 136 137 // Calculate the max number of users from available screen size. 138 bool show_guest = UserCrosSettingsProvider::cached_allow_guest(); 139 bool show_new_user = true; 140 if (UserCrosSettingsProvider::cached_show_users_on_signin()) { 141 size_t max_users = kMaxUsers; 142 int screen_width = background_bounds.width(); 143 if (screen_width > 0) { 144 size_t users_per_screen = (screen_width - login::kUserImageSize) 145 / (UserController::kUnselectedSize + UserController::kPadding); 146 max_users = std::max(kMinUsers, std::min(kMaxUsers, users_per_screen)); 147 } 148 149 size_t visible_users_count = std::min(users.size(), max_users - 150 static_cast<int>(show_guest) - static_cast<int>(show_new_user)); 151 for (size_t i = 0; i < users.size(); ++i) { 152 // TODO(xiyuan): Clean user profile whose email is not in whitelist. 153 if (UserCrosSettingsProvider::cached_allow_new_user() || 154 UserCrosSettingsProvider::IsEmailInCachedWhitelist( 155 users[i].email())) { 156 UserController* user_controller = new UserController(this, users[i]); 157 if (controllers_.size() < visible_users_count) 158 controllers_.push_back(user_controller); 159 else 160 invisible_controllers_.push_back(user_controller); 161 } 162 } 163 } 164 165 if (!controllers_.empty() && show_guest) 166 controllers_.push_back(new UserController(this, true)); 167 168 if (show_new_user) 169 controllers_.push_back(new UserController(this, false)); 170} 171 172void ExistingUserController::Init() { 173 if (!background_window_) { 174 std::string url_string = 175 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 176 switches::kScreenSaverUrl); 177 178 background_window_ = BackgroundView::CreateWindowContainingView( 179 background_bounds_, 180 GURL(url_string), 181 &background_view_); 182 background_view_->EnableShutdownButton(true); 183 184 if (!WizardController::IsDeviceRegistered()) { 185 background_view_->SetOobeProgressBarVisible(true); 186 background_view_->SetOobeProgress(chromeos::BackgroundView::SIGNIN); 187 } 188 189 background_window_->Show(); 190 } 191 // If there's only new user pod, show the guest session link on it. 192 bool show_guest_link = controllers_.size() == 1; 193 for (size_t i = 0; i < controllers_.size(); ++i) { 194 (controllers_[i])->Init(static_cast<int>(i), 195 static_cast<int>(controllers_.size()), 196 show_guest_link); 197 } 198 199 EnableTooltipsIfNeeded(controllers_); 200 201 WmMessageListener::GetInstance()->AddObserver(this); 202 203 LoginUtils::Get()->PrewarmAuthentication(); 204 if (CrosLibrary::Get()->EnsureLoaded()) 205 CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady(); 206} 207 208void ExistingUserController::OwnBackground( 209 views::Widget* background_widget, 210 chromeos::BackgroundView* background_view) { 211 DCHECK(!background_window_); 212 background_window_ = background_widget; 213 background_view_ = background_view; 214} 215 216void ExistingUserController::LoginNewUser(const std::string& username, 217 const std::string& password) { 218 SelectNewUser(); 219 UserController* new_user = controllers_.back(); 220 DCHECK(new_user->is_new_user()); 221 if (!new_user->is_new_user()) 222 return; 223 224 if (password.empty()) 225 return; 226 227 new_user->OnLogin(username, password); 228} 229 230void ExistingUserController::SelectNewUser() { 231 SelectUser(controllers_.size() - 1); 232} 233 234void ExistingUserController::SetStatusAreaEnabled(bool enable) { 235 if (background_view_) { 236 background_view_->SetStatusAreaEnabled(enable); 237 } 238} 239 240ExistingUserController::~ExistingUserController() { 241 ClearErrors(); 242 243 if (background_window_) 244 background_window_->Close(); 245 246 WmMessageListener::GetInstance()->RemoveObserver(this); 247 248 STLDeleteElements(&controllers_); 249 STLDeleteElements(&invisible_controllers_); 250} 251 252void ExistingUserController::Delete() { 253 delete_scheduled_instance_ = NULL; 254 delete this; 255} 256 257void ExistingUserController::ProcessWmMessage(const WmIpc::Message& message, 258 GdkWindow* window) { 259 if (message.type() != WM_IPC_MESSAGE_CHROME_CREATE_GUEST_WINDOW) 260 return; 261 262 ActivateWizard(std::string()); 263} 264 265void ExistingUserController::SendSetLoginState(bool is_enabled) { 266 WmIpc::Message message(WM_IPC_MESSAGE_WM_SET_LOGIN_STATE); 267 message.set_param(0, is_enabled); 268 WmIpc::instance()->SendMessage(message); 269} 270 271void ExistingUserController::Login(UserController* source, 272 const string16& password) { 273 BootTimesLoader::Get()->RecordLoginAttempted(); 274 std::vector<UserController*>::const_iterator i = 275 std::find(controllers_.begin(), controllers_.end(), source); 276 DCHECK(i != controllers_.end()); 277 278 if (i == controllers_.begin() + selected_view_index_) { 279 num_login_attempts_++; 280 } else { 281 selected_view_index_ = i - controllers_.begin(); 282 num_login_attempts_ = 0; 283 } 284 285 // Disable clicking on other windows. 286 SendSetLoginState(false); 287 288 // Use the same LoginPerformer for subsequent login as it has state 289 // such as CAPTCHA challenge token & corresponding user input. 290 if (!login_performer_.get() || num_login_attempts_ <= 1) { 291 login_performer_.reset(new LoginPerformer(this)); 292 } 293 login_performer_->Login(controllers_[selected_view_index_]->user().email(), 294 UTF16ToUTF8(password)); 295} 296 297void ExistingUserController::WhiteListCheckFailed(const std::string& email) { 298 ShowError(IDS_LOGIN_ERROR_WHITELIST, email); 299 300 // Reenable userview and use ClearAndEnablePassword to keep username on 301 // screen with the error bubble. 302 controllers_[selected_view_index_]->ClearAndEnablePassword(); 303 304 // Reenable clicking on other windows. 305 SendSetLoginState(true); 306} 307 308void ExistingUserController::LoginOffTheRecord() { 309 // Check allow_guest in case this call is fired from key accelerator. 310 // Must not proceed without signature verification. 311 bool trusted_setting_available = user_settings_->RequestTrustedAllowGuest( 312 method_factory_.NewRunnableMethod( 313 &ExistingUserController::LoginOffTheRecord)); 314 if (!trusted_setting_available) { 315 // Value of AllowGuest setting is still not verified. 316 // Another attempt will be invoked again after verification completion. 317 return; 318 } 319 if (!UserCrosSettingsProvider::cached_allow_guest()) { 320 // Disallowed. 321 return; 322 } 323 324 // Disable clicking on other windows. 325 SendSetLoginState(false); 326 327 login_performer_.reset(new LoginPerformer(this)); 328 login_performer_->LoginOffTheRecord(); 329} 330 331void ExistingUserController::ClearErrors() { 332 // bubble_ will be set to NULL in callback. 333 if (bubble_) 334 bubble_->Close(); 335} 336 337void ExistingUserController::OnUserSelected(UserController* source) { 338 std::vector<UserController*>::const_iterator i = 339 std::find(controllers_.begin(), controllers_.end(), source); 340 DCHECK(i != controllers_.end()); 341 size_t new_selected_index = i - controllers_.begin(); 342 if (new_selected_index != selected_view_index_ && 343 selected_view_index_ != kNotSelected) { 344 controllers_[selected_view_index_]->ClearAndEnableFields(); 345 controllers_[new_selected_index]->ClearAndEnableFields(); 346 login_performer_.reset(NULL); 347 num_login_attempts_ = 0; 348 } 349 selected_view_index_ = new_selected_index; 350} 351 352void ExistingUserController::ActivateWizard(const std::string& screen_name) { 353 // WizardController takes care of deleting itself when done. 354 WizardController* controller = new WizardController(); 355 356 // Give the background window to the controller. 357 controller->OwnBackground(background_window_, background_view_); 358 background_window_ = NULL; 359 360 controller->Init(screen_name, background_bounds_); 361 controller->set_start_url(start_url_); 362 controller->Show(); 363 364 // And schedule us for deletion. We delay for a second as the window manager 365 // is doing an animation with our windows. 366 DCHECK(!delete_scheduled_instance_); 367 delete_scheduled_instance_ = this; 368 369 delete_timer_.Start(base::TimeDelta::FromSeconds(1), this, 370 &ExistingUserController::Delete); 371} 372 373void ExistingUserController::RemoveUser(UserController* source) { 374 ClearErrors(); 375 376 // Owner is not allowed to be removed from the device. 377 // It must be enforced at upper levels. 378 DCHECK(user_settings_->RequestTrustedOwner(NULL)); 379 DCHECK(source->user().email() != UserCrosSettingsProvider::cached_owner()); 380 381 UserManager::Get()->RemoveUser(source->user().email()); 382 383 controllers_.erase(controllers_.begin() + source->user_index()); 384 385 EnableTooltipsIfNeeded(controllers_); 386 387 // Update user count before unmapping windows, otherwise window manager won't 388 // be in the right state. 389 int new_size = static_cast<int>(controllers_.size()); 390 for (int i = 0; i < new_size; ++i) 391 controllers_[i]->UpdateUserCount(i, new_size); 392 393 // Delete the encrypted user directory. 394 new RemoveAttempt(source->user().email()); 395 // We need to unmap entry windows, the windows will be unmapped in destructor. 396 delete source; 397 398 // Nothing to insert. 399 if (invisible_controllers_.empty()) 400 return; 401 402 // Insert just before guest or add new user pods if any. 403 int insert_position = new_size; 404 while (insert_position > 0 && 405 (controllers_[insert_position - 1]->is_new_user() || 406 controllers_[insert_position - 1]->is_guest())) 407 --insert_position; 408 409 controllers_.insert(controllers_.begin() + insert_position, 410 invisible_controllers_[0]); 411 invisible_controllers_.erase(invisible_controllers_.begin()); 412 413 // Update counts for exiting pods. 414 new_size = static_cast<int>(controllers_.size()); 415 for (int i = 0; i < new_size; ++i) { 416 if (i != insert_position) 417 controllers_[i]->UpdateUserCount(i, new_size); 418 } 419 420 // And initialize new one that was invisible. 421 controllers_[insert_position]->Init(insert_position, new_size, false); 422 423 EnableTooltipsIfNeeded(controllers_); 424} 425 426void ExistingUserController::SelectUser(int index) { 427 if (index >= 0 && index < static_cast<int>(controllers_.size()) && 428 index != static_cast<int>(selected_view_index_)) { 429 WmIpc::Message message(WM_IPC_MESSAGE_WM_SELECT_LOGIN_USER); 430 message.set_param(0, index); 431 WmIpc::instance()->SendMessage(message); 432 } 433} 434 435void ExistingUserController::OnLoginFailure(const LoginFailure& failure) { 436 std::string error = failure.GetErrorString(); 437 438 // Check networking after trying to login in case user is 439 // cached locally or the local admin account. 440 NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary(); 441 if (!network || !CrosLibrary::Get()->EnsureLoaded()) { 442 ShowError(IDS_LOGIN_ERROR_NO_NETWORK_LIBRARY, error); 443 } else if (!network->Connected()) { 444 ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error); 445 } else { 446 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && 447 failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) { 448 if (!failure.error().captcha().image_url.is_empty()) { 449 CaptchaView* view = 450 new CaptchaView(failure.error().captcha().image_url, false); 451 view->Init(); 452 view->set_delegate(this); 453 views::Window* window = browser::CreateViewsWindow( 454 GetNativeWindow(), gfx::Rect(), view); 455 window->SetIsAlwaysOnTop(true); 456 window->Show(); 457 } else { 458 LOG(WARNING) << "No captcha image url was found?"; 459 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error); 460 } 461 } else if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && 462 failure.error().state() == 463 GoogleServiceAuthError::HOSTED_NOT_ALLOWED) { 464 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED, error); 465 } else { 466 if (controllers_[selected_view_index_]->is_new_user()) 467 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error); 468 else 469 ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error); 470 } 471 } 472 473 controllers_[selected_view_index_]->ClearAndEnablePassword(); 474 475 // Reenable clicking on other windows. 476 SendSetLoginState(true); 477} 478 479void ExistingUserController::AppendStartUrlToCmdline() { 480 if (start_url_.is_valid()) 481 CommandLine::ForCurrentProcess()->AppendArg(start_url_.spec()); 482} 483 484gfx::NativeWindow ExistingUserController::GetNativeWindow() const { 485 return GTK_WINDOW( 486 static_cast<views::WidgetGtk*>(background_window_)->GetNativeView()); 487} 488 489void ExistingUserController::ShowError(int error_id, 490 const std::string& details) { 491 ClearErrors(); 492 string16 error_text; 493 // GetStringF fails on debug build if there's no replacement in the string. 494 if (error_id == IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED) { 495 error_text = l10n_util::GetStringFUTF16( 496 error_id, l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)); 497 } else { 498 error_text = l10n_util::GetStringUTF16(error_id); 499 } 500 // TODO(dpolukhin): show detailed error info. |details| string contains 501 // low level error info that is not localized and even is not user friendly. 502 // For now just ignore it because error_text contains all required information 503 // for end users, developers can see details string in Chrome logs. 504 505 gfx::Rect bounds = 506 controllers_[selected_view_index_]->GetMainInputScreenBounds(); 507 BubbleBorder::ArrowLocation arrow; 508 if (controllers_[selected_view_index_]->is_new_user()) { 509 arrow = BubbleBorder::LEFT_TOP; 510 } else { 511 // Point info bubble arrow to cursor position (approximately). 512 bounds.set_width(kCursorOffset * 2); 513 arrow = BubbleBorder::BOTTOM_LEFT; 514 } 515 string16 help_link; 516 if (error_id == IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED) { 517 help_link = l10n_util::GetStringUTF16(IDS_LEARN_MORE); 518 } else if (num_login_attempts_ > static_cast<size_t>(1)) { 519 help_link = l10n_util::GetStringUTF16(IDS_CANT_ACCESS_ACCOUNT_BUTTON); 520 } 521 522 bubble_ = MessageBubble::Show( 523 controllers_[selected_view_index_]->controls_window(), 524 bounds, 525 arrow, 526 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING), 527 UTF16ToWide(error_text), 528 UTF16ToWide(help_link), 529 this); 530} 531 532void ExistingUserController::OnLoginSuccess( 533 const std::string& username, 534 const std::string& password, 535 const GaiaAuthConsumer::ClientLoginResult& credentials, 536 bool pending_requests) { 537 // LoginPerformer instance will delete itself once online auth result is OK. 538 // In case of failure it'll bring up ScreenLock and ask for 539 // correct password/display error message. 540 // Even in case when following online,offline protocol and returning 541 // requests_pending = false, let LoginPerformer delete itself. 542 login_performer_->set_delegate(NULL); 543 LoginPerformer* performer = login_performer_.release(); 544 performer = NULL; 545 bool known_user = UserManager::Get()->IsKnownUser(username); 546 AppendStartUrlToCmdline(); 547 controllers_[selected_view_index_]->StopThrobber(); 548 if (selected_view_index_ + 1 == controllers_.size() && !known_user) { 549#if defined(OFFICIAL_BUILD) 550 CommandLine::ForCurrentProcess()->AppendSwitchPath( 551 switches::kLoadExtension, 552 FilePath(kGetStartedPath)); 553 CommandLine::ForCurrentProcess()->AppendArg(kGetStartedURL); 554#endif // OFFICIAL_BUILD 555 if (credentials.two_factor) { 556 // If we have a two factor error and and this is a new user, 557 // load the personal settings page. 558 // TODO(stevenjb): direct the user to a lightweight sync login page. 559 CommandLine::ForCurrentProcess()->AppendArg(kSettingsSyncLoginUrl); 560 } 561 // For new user login don't launch browser until we pass image screen. 562 LoginUtils::Get()->EnableBrowserLaunch(false); 563 LoginUtils::Get()->CompleteLogin(username, 564 password, 565 credentials, 566 pending_requests); 567 ActivateWizard(WizardController::IsDeviceRegistered() ? 568 WizardController::kUserImageScreenName : 569 WizardController::kRegistrationScreenName); 570 } else { 571 // Hide the login windows now. 572 WmIpc::Message message(WM_IPC_MESSAGE_WM_HIDE_LOGIN); 573 WmIpc::instance()->SendMessage(message); 574 575 LoginUtils::Get()->CompleteLogin(username, 576 password, 577 credentials, 578 pending_requests); 579 580 // Delay deletion as we're on the stack. 581 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 582 } 583} 584 585void ExistingUserController::OnOffTheRecordLoginSuccess() { 586 if (WizardController::IsDeviceRegistered()) { 587 LoginUtils::Get()->CompleteOffTheRecordLogin(start_url_); 588 } else { 589 // Postpone CompleteOffTheRecordLogin until registration completion. 590 ActivateWizard(WizardController::kRegistrationScreenName); 591 } 592} 593 594void ExistingUserController::OnPasswordChangeDetected( 595 const GaiaAuthConsumer::ClientLoginResult& credentials) { 596 // When signing in as a "New user" always remove old cryptohome. 597 if (selected_view_index_ == controllers_.size() - 1) { 598 ResyncEncryptedData(); 599 return; 600 } 601 602 // Must not proceed without signature verification. 603 bool trusted_setting_available = user_settings_->RequestTrustedOwner( 604 method_factory_.NewRunnableMethod( 605 &ExistingUserController::OnPasswordChangeDetected, 606 credentials)); 607 if (!trusted_setting_available) { 608 // Value of owner email is still not verified. 609 // Another attempt will be invoked after verification completion. 610 return; 611 } 612 // TODO(altimofeev): remove this constrain when full sync for the owner will 613 // be correctly handled. 614 bool full_sync_disabled = (UserCrosSettingsProvider::cached_owner() == 615 controllers_[selected_view_index_]->user().email()); 616 617 PasswordChangedView* view = new PasswordChangedView(this, full_sync_disabled); 618 views::Window* window = browser::CreateViewsWindow(GetNativeWindow(), 619 gfx::Rect(), 620 view); 621 window->SetIsAlwaysOnTop(true); 622 window->Show(); 623} 624 625void ExistingUserController::OnHelpLinkActivated() { 626 DCHECK(login_performer_->error().state() != GoogleServiceAuthError::NONE); 627 if (!help_app_.get()) 628 help_app_.reset(new HelpAppLauncher(GetNativeWindow())); 629 switch (login_performer_->error().state()) { 630 case GoogleServiceAuthError::CONNECTION_FAILED: 631 help_app_->ShowHelpTopic( 632 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE); 633 break; 634 case GoogleServiceAuthError::ACCOUNT_DISABLED: 635 help_app_->ShowHelpTopic( 636 HelpAppLauncher::HELP_ACCOUNT_DISABLED); 637 break; 638 case GoogleServiceAuthError::HOSTED_NOT_ALLOWED: 639 help_app_->ShowHelpTopic( 640 HelpAppLauncher::HELP_HOSTED_ACCOUNT); 641 break; 642 default: 643 help_app_->ShowHelpTopic(login_performer_->login_timed_out() ? 644 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE : 645 HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT); 646 break; 647 } 648} 649 650void ExistingUserController::OnCaptchaEntered(const std::string& captcha) { 651 login_performer_->set_captcha(captcha); 652} 653 654void ExistingUserController::RecoverEncryptedData( 655 const std::string& old_password) { 656 // LoginPerformer instance has state of the user so it should exist. 657 if (login_performer_.get()) 658 login_performer_->RecoverEncryptedData(old_password); 659} 660 661void ExistingUserController::ResyncEncryptedData() { 662 // LoginPerformer instance has state of the user so it should exist. 663 if (login_performer_.get()) 664 login_performer_->ResyncEncryptedData(); 665} 666 667} // namespace chromeos 668