1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/login/login_display_host_impl.h" 6 7 #include <vector> 8 9 #include "ash/desktop_background/desktop_background_controller.h" 10 #include "ash/desktop_background/user_wallpaper_delegate.h" 11 #include "ash/shell.h" 12 #include "ash/shell_window_ids.h" 13 #include "ash/wm/window_properties.h" 14 #include "base/bind.h" 15 #include "base/command_line.h" 16 #include "base/debug/trace_event.h" 17 #include "base/logging.h" 18 #include "base/prefs/pref_service.h" 19 #include "base/strings/utf_string_conversions.h" 20 #include "base/threading/thread_restrictions.h" 21 #include "base/time/time.h" 22 #include "base/values.h" 23 #include "chrome/browser/browser_process.h" 24 #include "chrome/browser/browser_shutdown.h" 25 #include "chrome/browser/chrome_notification_types.h" 26 #include "chrome/browser/chromeos/customization_document.h" 27 #include "chrome/browser/chromeos/input_method/input_method_util.h" 28 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" 29 #include "chrome/browser/chromeos/language_preferences.h" 30 #include "chrome/browser/chromeos/login/existing_user_controller.h" 31 #include "chrome/browser/chromeos/login/helper.h" 32 #include "chrome/browser/chromeos/login/language_switch_menu.h" 33 #include "chrome/browser/chromeos/login/login_utils.h" 34 #include "chrome/browser/chromeos/login/login_wizard.h" 35 #include "chrome/browser/chromeos/login/oobe_display.h" 36 #include "chrome/browser/chromeos/login/startup_utils.h" 37 #include "chrome/browser/chromeos/login/user_manager.h" 38 #include "chrome/browser/chromeos/login/webui_login_display.h" 39 #include "chrome/browser/chromeos/login/webui_login_view.h" 40 #include "chrome/browser/chromeos/login/wizard_controller.h" 41 #include "chrome/browser/chromeos/mobile_config.h" 42 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" 43 #include "chrome/browser/chromeos/system/input_device_settings.h" 44 #include "chrome/browser/chromeos/system/timezone_settings.h" 45 #include "chrome/browser/chromeos/ui/focus_ring_controller.h" 46 #include "chrome/browser/lifetime/application_lifetime.h" 47 #include "chrome/browser/policy/browser_policy_connector.h" 48 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 49 #include "chrome/common/chrome_constants.h" 50 #include "chrome/common/pref_names.h" 51 #include "chromeos/chromeos_constants.h" 52 #include "chromeos/chromeos_switches.h" 53 #include "chromeos/dbus/dbus_thread_manager.h" 54 #include "chromeos/dbus/session_manager_client.h" 55 #include "chromeos/ime/input_method_manager.h" 56 #include "chromeos/login/login_state.h" 57 #include "content/public/browser/notification_service.h" 58 #include "content/public/browser/notification_types.h" 59 #include "content/public/browser/web_contents.h" 60 #include "content/public/browser/web_contents_view.h" 61 #include "content/public/browser/web_ui.h" 62 #include "ui/aura/root_window.h" 63 #include "ui/aura/window.h" 64 #include "ui/base/events/event_utils.h" 65 #include "ui/base/resource/resource_bundle.h" 66 #include "ui/compositor/layer.h" 67 #include "ui/compositor/layer_animation_element.h" 68 #include "ui/compositor/layer_animation_sequence.h" 69 #include "ui/compositor/layer_animator.h" 70 #include "ui/compositor/scoped_layer_animation_settings.h" 71 #include "ui/gfx/rect.h" 72 #include "ui/gfx/transform.h" 73 #include "ui/views/focus/focus_manager.h" 74 #include "ui/views/widget/widget.h" 75 #include "url/gurl.h" 76 77 namespace { 78 79 // URL which corresponds to the login WebUI. 80 const char kLoginURL[] = "chrome://oobe/login#login"; 81 82 // URL which corresponds to the OOBE WebUI. 83 const char kOobeURL[] = "chrome://oobe#login"; 84 85 // URL which corresponds to the user adding WebUI. 86 const char kUserAddingURL[] = "chrome://oobe/login#user-adding"; 87 88 // Duration of sign-in transition animation. 89 const int kLoginFadeoutTransitionDurationMs = 700; 90 91 // Number of times we try to reload OOBE/login WebUI if it crashes. 92 const int kCrashCountLimit = 5; 93 94 // Whether to enable tnitializing WebUI in hidden state (see 95 // |initialize_webui_hidden_|) by default. 96 const bool kHiddenWebUIInitializationDefault = true; 97 98 // Switch values that might be used to override WebUI init type. 99 const char kWebUIInitParallel[] = "parallel"; 100 const char kWebUIInitPostpone[] = "postpone"; 101 102 // The delay of triggering initialization of the device policy subsystem 103 // after the login screen is initialized. This makes sure that device policy 104 // network requests are made while the system is idle waiting for user input. 105 const int64 kPolicyServiceInitializationDelayMilliseconds = 100; 106 107 // Determines the hardware keyboard from the given locale code 108 // and the OEM layout information, and saves it to "Locale State". 109 // The information will be used in InputMethodUtil::GetHardwareInputMethodId(). 110 void DetermineAndSaveHardwareKeyboard(const std::string& locale, 111 const std::string& oem_layout) { 112 std::string layout; 113 if (!oem_layout.empty()) { 114 // If the OEM layout information is provided, use it. 115 layout = oem_layout; 116 } else { 117 chromeos::input_method::InputMethodManager* manager = 118 chromeos::input_method::InputMethodManager::Get(); 119 // Otherwise, determine the hardware keyboard from the locale. 120 std::vector<std::string> input_method_ids; 121 if (manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode( 122 locale, 123 chromeos::input_method::kKeyboardLayoutsOnly, 124 &input_method_ids)) { 125 // The output list |input_method_ids| is sorted by popularity, hence 126 // input_method_ids[0] now contains the most popular keyboard layout 127 // for the given locale. 128 layout = input_method_ids[0]; 129 } 130 } 131 132 if (!layout.empty()) { 133 PrefService* prefs = g_browser_process->local_state(); 134 prefs->SetString(prefs::kHardwareKeyboardLayout, layout); 135 // This asks the file thread to save the prefs (i.e. doesn't block). 136 // The latest values of Local State reside in memory so we can safely 137 // get the value of kHardwareKeyboardLayout even if the data is not 138 // yet saved to disk. 139 prefs->CommitPendingWrite(); 140 } 141 } 142 143 ui::Layer* GetLayer(views::Widget* widget) { 144 return widget->GetNativeView()->layer(); 145 } 146 147 } // namespace 148 149 namespace chromeos { 150 151 // static 152 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL; 153 154 // static 155 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111; 156 157 //////////////////////////////////////////////////////////////////////////////// 158 // LoginDisplayHostImpl, public 159 160 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds) 161 : background_bounds_(background_bounds), 162 pointer_factory_(this), 163 shutting_down_(false), 164 oobe_progress_bar_visible_(false), 165 session_starting_(false), 166 login_window_(NULL), 167 login_view_(NULL), 168 webui_login_display_(NULL), 169 is_showing_login_(false), 170 is_wallpaper_loaded_(false), 171 status_area_saved_visibility_(false), 172 crash_count_(0), 173 restore_path_(RESTORE_UNKNOWN), 174 old_ignore_solo_window_frame_painter_policy_value_(false) { 175 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING 176 // because/ APP_TERMINATING will never be fired as long as this keeps 177 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no 178 // browser instance that will block the shutdown. 179 registrar_.Add(this, 180 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 181 content::NotificationService::AllSources()); 182 183 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but 184 // not shown yet. Lock window has to be closed at this point so that 185 // a browser window exists and the window can acquire input focus. 186 registrar_.Add(this, 187 chrome::NOTIFICATION_BROWSER_OPENED, 188 content::NotificationService::AllSources()); 189 190 // Login screen is moved to lock screen container when user logs in. 191 registrar_.Add(this, 192 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 193 content::NotificationService::AllSources()); 194 195 DCHECK(default_host_ == NULL); 196 default_host_ = this; 197 198 // Make sure chrome won't exit while we are at login/oobe screen. 199 chrome::StartKeepAlive(); 200 201 bool is_registered = StartupUtils::IsDeviceRegistered(); 202 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); 203 bool disable_boot_animation = CommandLine::ForCurrentProcess()-> 204 HasSwitch(switches::kDisableBootAnimation); 205 bool disable_oobe_animation = CommandLine::ForCurrentProcess()-> 206 HasSwitch(switches::kDisableOobeAnimation); 207 208 waiting_for_wallpaper_load_ = 209 !zero_delay_enabled && 210 (is_registered || !disable_oobe_animation) && 211 (!is_registered || !disable_boot_animation); 212 213 // For slower hardware we have boot animation disabled so 214 // we'll be initializing WebUI hidden, waiting for user pods to load and then 215 // show WebUI at once. 216 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_; 217 218 initialize_webui_hidden_ = 219 kHiddenWebUIInitializationDefault && !zero_delay_enabled; 220 221 // Check if WebUI init type is overriden. 222 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) { 223 const std::string override_type = CommandLine::ForCurrentProcess()-> 224 GetSwitchValueASCII(switches::kAshWebUIInit); 225 if (override_type == kWebUIInitParallel) 226 initialize_webui_hidden_ = true; 227 else if (override_type == kWebUIInitPostpone) 228 initialize_webui_hidden_ = false; 229 } 230 231 // Always postpone WebUI initialization on first boot, otherwise we miss 232 // initial animation. 233 if (!StartupUtils::IsOobeCompleted()) 234 initialize_webui_hidden_ = false; 235 236 // There is no wallpaper for KioskMode, don't initialize the webui hidden. 237 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 238 initialize_webui_hidden_ = false; 239 240 if (waiting_for_wallpaper_load_) { 241 registrar_.Add(this, chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 242 content::NotificationService::AllSources()); 243 } 244 245 // When we wait for WebUI to be initialized we wait for one of 246 // these notifications. 247 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) 248 && initialize_webui_hidden_) { 249 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 250 content::NotificationService::AllSources()); 251 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 252 content::NotificationService::AllSources()); 253 } 254 LOG(WARNING) << "Login WebUI >> " 255 << "zero_delay: " << zero_delay_enabled 256 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_ 257 << " wait_for_pods_: " << waiting_for_user_pods_ 258 << " init_webui_hidden_: " << initialize_webui_hidden_; 259 260 if (system::keyboard_settings::ForceKeyboardDrivenUINavigation()) { 261 views::FocusManager::set_arrow_key_traversal_enabled(true); 262 263 focus_ring_controller_.reset(new FocusRingController); 264 focus_ring_controller_->SetVisible(true); 265 } 266 } 267 268 LoginDisplayHostImpl::~LoginDisplayHostImpl() { 269 views::FocusManager::set_arrow_key_traversal_enabled(false); 270 ResetLoginWindowAndView(); 271 272 // Let chrome process exit after login/oobe screen if needed. 273 chrome::EndKeepAlive(); 274 275 default_host_ = NULL; 276 } 277 278 //////////////////////////////////////////////////////////////////////////////// 279 // LoginDisplayHostImpl, LoginDisplayHost implementation: 280 281 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay( 282 LoginDisplay::Delegate* delegate) { 283 webui_login_display_ = new WebUILoginDisplay(delegate); 284 webui_login_display_->set_background_bounds(background_bounds()); 285 return webui_login_display_; 286 } 287 288 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const { 289 return login_window_ ? login_window_->GetNativeWindow() : NULL; 290 } 291 292 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const { 293 return login_view_; 294 } 295 296 views::Widget* LoginDisplayHostImpl::GetWidget() const { 297 return login_window_; 298 } 299 300 void LoginDisplayHostImpl::BeforeSessionStart() { 301 session_starting_ = true; 302 } 303 304 void LoginDisplayHostImpl::Finalize() { 305 DVLOG(1) << "Session starting"; 306 ash::Shell::GetInstance()-> 307 desktop_background_controller()->MoveDesktopToUnlockedContainer(); 308 if (wizard_controller_.get()) 309 wizard_controller_->OnSessionStart(); 310 if (!IsRunningUserAdding()) { 311 // Display host is deleted once animation is completed 312 // since sign in screen widget has to stay alive. 313 StartAnimation(); 314 } 315 ShutdownDisplayHost(false); 316 } 317 318 void LoginDisplayHostImpl::OnCompleteLogin() { 319 // Cancelling the |auto_enrollment_client_| now allows it to determine whether 320 // its protocol finished before login was complete. 321 if (auto_enrollment_client_.get()) 322 auto_enrollment_client_.release()->CancelAndDeleteSoon(); 323 } 324 325 void LoginDisplayHostImpl::OpenProxySettings() { 326 if (login_view_) 327 login_view_->OpenProxySettings(); 328 } 329 330 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) { 331 GetOobeUI()->ShowOobeUI(visible); 332 } 333 334 void LoginDisplayHostImpl::SetShutdownButtonEnabled(bool enable) { 335 } 336 337 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) { 338 if (initialize_webui_hidden_) 339 status_area_saved_visibility_ = visible; 340 else if (login_view_) 341 login_view_->SetStatusAreaVisible(visible); 342 } 343 344 void LoginDisplayHostImpl::CheckForAutoEnrollment() { 345 // This method is called when the controller determines that the 346 // auto-enrollment check can start. This happens either after the EULA is 347 // accepted, or right after a reboot if the EULA has already been accepted. 348 349 if (policy::AutoEnrollmentClient::IsDisabled()) { 350 VLOG(1) << "CheckForAutoEnrollment: auto-enrollment disabled"; 351 return; 352 } 353 354 // Start by checking if the device has already been owned. 355 pointer_factory_.InvalidateWeakPtrs(); 356 DeviceSettingsService::Get()->GetOwnershipStatusAsync( 357 base::Bind(&LoginDisplayHostImpl::OnOwnershipStatusCheckDone, 358 pointer_factory_.GetWeakPtr())); 359 } 360 361 void LoginDisplayHostImpl::StartWizard( 362 const std::string& first_screen_name, 363 scoped_ptr<DictionaryValue> screen_parameters) { 364 // Keep parameters to restore if renderer crashes. 365 restore_path_ = RESTORE_WIZARD; 366 wizard_first_screen_name_ = first_screen_name; 367 if (screen_parameters.get()) 368 wizard_screen_parameters_.reset(screen_parameters->DeepCopy()); 369 else 370 wizard_screen_parameters_.reset(); 371 is_showing_login_ = false; 372 373 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 374 LOG(WARNING) << "Login WebUI >> wizard postponed"; 375 return; 376 } 377 LOG(WARNING) << "Login WebUI >> wizard"; 378 379 if (!login_window_) 380 LoadURL(GURL(kOobeURL)); 381 382 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; 383 // Create and show the wizard. 384 // Note, dtor of the old WizardController should be called before ctor of the 385 // new one, because "default_controller()" is updated there. So pure "reset()" 386 // is done before new controller creation. 387 wizard_controller_.reset(); 388 wizard_controller_.reset(CreateWizardController()); 389 390 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 391 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 392 wizard_controller_->Init(first_screen_name, screen_parameters.Pass()); 393 } 394 395 WizardController* LoginDisplayHostImpl::GetWizardController() { 396 return wizard_controller_.get(); 397 } 398 399 void LoginDisplayHostImpl::StartUserAdding( 400 const base::Closure& completion_callback) { 401 restore_path_ = RESTORE_ADD_USER_INTO_SESSION; 402 completion_callback_ = completion_callback; 403 LOG(WARNING) << "Login WebUI >> user adding"; 404 if (!login_window_) 405 LoadURL(GURL(kUserAddingURL)); 406 // We should emit this signal only at login screen (after reboot or sign out). 407 login_view_->set_should_emit_login_prompt_visible(false); 408 409 // Lock container can be transparent after lock screen animation. 410 aura::Window* lock_container = ash::Shell::GetContainer( 411 ash::Shell::GetPrimaryRootWindow(), 412 ash::internal::kShellWindowId_LockScreenContainersContainer); 413 lock_container->layer()->SetOpacity(1.0); 414 415 ash::Shell::GetInstance()-> 416 desktop_background_controller()->MoveDesktopToLockedContainer(); 417 418 sign_in_controller_.reset(); // Only one controller in a time. 419 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 420 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false); 421 SetStatusAreaVisible(true); 422 SetShutdownButtonEnabled(true); 423 sign_in_controller_->Init( 424 chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile()); 425 CHECK(webui_login_display_); 426 GetOobeUI()->ShowSigninScreen(webui_login_display_, webui_login_display_); 427 } 428 429 void LoginDisplayHostImpl::StartSignInScreen() { 430 restore_path_ = RESTORE_SIGN_IN; 431 is_showing_login_ = true; 432 433 PrewarmAuthentication(); 434 435 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 436 LOG(WARNING) << "Login WebUI >> sign in postponed"; 437 return; 438 } 439 LOG(WARNING) << "Login WebUI >> sign in"; 440 441 if (!login_window_) { 442 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid); 443 LoadURL(GURL(kLoginURL)); 444 } 445 446 DVLOG(1) << "Starting sign in screen"; 447 const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers(); 448 449 // Fix for users who updated device and thus never passed register screen. 450 // If we already have users, we assume that it is not a second part of 451 // OOBE. See http://crosbug.com/6289 452 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) { 453 VLOG(1) << "Mark device registered because there are remembered users: " 454 << users.size(); 455 StartupUtils::MarkDeviceRegistered(); 456 } 457 458 sign_in_controller_.reset(); // Only one controller in a time. 459 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 460 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 461 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 462 SetStatusAreaVisible(true); 463 SetShutdownButtonEnabled(true); 464 sign_in_controller_->Init(users); 465 466 // We might be here after a reboot that was triggered after OOBE was complete, 467 // so check for auto-enrollment again. This might catch a cached decision from 468 // a previous oobe flow, or might start a new check with the server. 469 CheckForAutoEnrollment(); 470 471 // Initiate services customization manifest fetching. 472 ServicesCustomizationDocument::GetInstance()->StartFetching(); 473 474 // Initiate mobile config load. 475 MobileConfig::GetInstance(); 476 477 // Initiate device policy fetching. 478 g_browser_process->browser_policy_connector()->ScheduleServiceInitialization( 479 kPolicyServiceInitializationDelayMilliseconds); 480 481 CHECK(webui_login_display_); 482 GetOobeUI()->ShowSigninScreen(webui_login_display_, webui_login_display_); 483 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 484 SetStatusAreaVisible(false); 485 } 486 487 void LoginDisplayHostImpl::ResumeSignInScreen() { 488 // We only get here after a previous call the StartSignInScreen. That sign-in 489 // was successful but was interrupted by an auto-enrollment execution; once 490 // auto-enrollment is complete we resume the normal login flow from here. 491 DVLOG(1) << "Resuming sign in screen"; 492 CHECK(sign_in_controller_.get()); 493 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 494 SetStatusAreaVisible(true); 495 SetShutdownButtonEnabled(true); 496 sign_in_controller_->ResumeLogin(); 497 } 498 499 500 void LoginDisplayHostImpl::OnPreferencesChanged() { 501 if (is_showing_login_) 502 webui_login_display_->OnPreferencesChanged(); 503 } 504 505 void LoginDisplayHostImpl::PrewarmAuthentication() { 506 auth_prewarmer_.reset(new AuthPrewarmer()); 507 auth_prewarmer_->PrewarmAuthentication( 508 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone, 509 pointer_factory_.GetWeakPtr())); 510 } 511 512 //////////////////////////////////////////////////////////////////////////////// 513 // LoginDisplayHostImpl, public 514 515 WizardController* LoginDisplayHostImpl::CreateWizardController() { 516 // TODO(altimofeev): ensure that WebUI is ready. 517 OobeDisplay* oobe_display = GetOobeUI(); 518 return new WizardController(this, oobe_display); 519 } 520 521 void LoginDisplayHostImpl::OnBrowserCreated() { 522 // Close lock window now so that the launched browser can receive focus. 523 ResetLoginWindowAndView(); 524 } 525 526 OobeUI* LoginDisplayHostImpl::GetOobeUI() const { 527 if (!login_view_) 528 return NULL; 529 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController()); 530 } 531 532 //////////////////////////////////////////////////////////////////////////////// 533 // LoginDisplayHostImpl, content:NotificationObserver implementation: 534 535 void LoginDisplayHostImpl::Observe( 536 int type, 537 const content::NotificationSource& source, 538 const content::NotificationDetails& details) { 539 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) { 540 LOG(WARNING) << "Login WebUI >> wp animation done"; 541 is_wallpaper_loaded_ = true; 542 ash::Shell::GetInstance()->user_wallpaper_delegate() 543 ->OnWallpaperBootAnimationFinished(); 544 if (waiting_for_wallpaper_load_) { 545 // StartWizard / StartSignInScreen could be called multiple times through 546 // the lifetime of host. 547 // Make sure that subsequent calls are not postponed. 548 waiting_for_wallpaper_load_ = false; 549 if (initialize_webui_hidden_) 550 ShowWebUI(); 551 else 552 StartPostponedWebUI(); 553 } 554 registrar_.Remove(this, 555 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 556 content::NotificationService::AllSources()); 557 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type || 558 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) { 559 LOG(WARNING) << "Login WebUI >> WEBUI_VISIBLE"; 560 if (waiting_for_user_pods_ && initialize_webui_hidden_) { 561 waiting_for_user_pods_ = false; 562 ShowWebUI(); 563 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { 564 // Reduce time till login UI is shown - show it as soon as possible. 565 waiting_for_wallpaper_load_ = false; 566 ShowWebUI(); 567 } 568 registrar_.Remove(this, 569 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 570 content::NotificationService::AllSources()); 571 registrar_.Remove(this, 572 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 573 content::NotificationService::AllSources()); 574 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { 575 ShutdownDisplayHost(true); 576 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { 577 // Browsers created before session start (windows opened by extensions, for 578 // example) are ignored. 579 OnBrowserCreated(); 580 registrar_.Remove(this, 581 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 582 content::NotificationService::AllSources()); 583 registrar_.Remove(this, 584 chrome::NOTIFICATION_BROWSER_OPENED, 585 content::NotificationService::AllSources()); 586 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && 587 chromeos::UserManager::Get()->IsCurrentUserNew()) { 588 // For new user, move desktop to locker container so that windows created 589 // during the user image picker step are below it. 590 ash::Shell::GetInstance()-> 591 desktop_background_controller()->MoveDesktopToLockedContainer(); 592 registrar_.Remove(this, 593 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 594 content::NotificationService::AllSources()); 595 } 596 } 597 598 //////////////////////////////////////////////////////////////////////////////// 599 // LoginDisplayHostImpl, WebContentsObserver implementation: 600 601 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) { 602 // Do not try to restore on shutdown 603 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) 604 return; 605 606 crash_count_++; 607 if (crash_count_ > kCrashCountLimit) 608 return; 609 610 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { 611 // Render with login screen crashed. Let's crash browser process to let 612 // session manager restart it properly. It is hard to reload the page 613 // and get to controlled state that is fully functional. 614 // If you see check, search for renderer crash for the same client. 615 LOG(FATAL) << "Renderer crash on login window"; 616 } 617 } 618 619 //////////////////////////////////////////////////////////////////////////////// 620 // LoginDisplayHostImpl, private 621 622 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) { 623 if (shutting_down_) 624 return; 625 626 shutting_down_ = true; 627 registrar_.RemoveAll(); 628 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 629 if (post_quit_task) 630 base::MessageLoop::current()->Quit(); 631 632 if (!completion_callback_.is_null()) 633 completion_callback_.Run(); 634 } 635 636 void LoginDisplayHostImpl::StartAnimation() { 637 if (ash::Shell::GetContainer( 638 ash::Shell::GetPrimaryRootWindow(), 639 ash::internal::kShellWindowId_DesktopBackgroundContainer)-> 640 children().empty()) { 641 // If there is no background window, don't perform any animation on the 642 // default and background layer because there is nothing behind it. 643 return; 644 } 645 646 if (!CommandLine::ForCurrentProcess()->HasSwitch( 647 switches::kDisableLoginAnimations)) 648 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation(); 649 } 650 651 void LoginDisplayHostImpl::OnOwnershipStatusCheckDone( 652 DeviceSettingsService::OwnershipStatus status, 653 bool current_user_is_owner) { 654 if (status != DeviceSettingsService::OWNERSHIP_NONE) { 655 // The device is already owned. No need for auto-enrollment checks. 656 VLOG(1) << "CheckForAutoEnrollment: device already owned"; 657 return; 658 } 659 660 // Kick off the auto-enrollment client. 661 if (auto_enrollment_client_.get()) { 662 // They client might have been started after the EULA screen, but we made 663 // it to the login screen before it finished. In that case let the current 664 // client proceed. 665 // 666 // CheckForAutoEnrollment() is also called when we reach the sign-in screen, 667 // because that's what happens after an auto-update. 668 VLOG(1) << "CheckForAutoEnrollment: client already started"; 669 670 // If the client already started and already finished too, pass the decision 671 // to the |sign_in_controller_| now. 672 if (auto_enrollment_client_->should_auto_enroll()) 673 ForceAutoEnrollment(); 674 } else { 675 VLOG(1) << "CheckForAutoEnrollment: starting auto-enrollment client"; 676 auto_enrollment_client_.reset(policy::AutoEnrollmentClient::Create( 677 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentClientDone, 678 base::Unretained(this)))); 679 auto_enrollment_client_->Start(); 680 } 681 } 682 683 void LoginDisplayHostImpl::OnAutoEnrollmentClientDone() { 684 bool auto_enroll = auto_enrollment_client_->should_auto_enroll(); 685 VLOG(1) << "OnAutoEnrollmentClientDone, decision is " << auto_enroll; 686 687 if (auto_enroll) 688 ForceAutoEnrollment(); 689 } 690 691 void LoginDisplayHostImpl::ForceAutoEnrollment() { 692 if (sign_in_controller_.get()) 693 sign_in_controller_->DoAutoEnrollment(); 694 } 695 696 void LoginDisplayHostImpl::LoadURL(const GURL& url) { 697 InitLoginWindowAndView(); 698 // Subscribe to crash events. 699 content::WebContentsObserver::Observe(login_view_->GetWebContents()); 700 login_view_->LoadURL(url); 701 } 702 703 void LoginDisplayHostImpl::ShowWebUI() { 704 if (!login_window_ || !login_view_) { 705 NOTREACHED(); 706 return; 707 } 708 LOG(WARNING) << "Login WebUI >> Show already initialized UI"; 709 login_window_->Show(); 710 login_view_->GetWebContents()->GetView()->Focus(); 711 login_view_->SetStatusAreaVisible(status_area_saved_visibility_); 712 login_view_->OnPostponedShow(); 713 // We should reset this flag to allow changing of status area visibility. 714 initialize_webui_hidden_ = false; 715 } 716 717 void LoginDisplayHostImpl::StartPostponedWebUI() { 718 if (!is_wallpaper_loaded_) { 719 NOTREACHED(); 720 return; 721 } 722 LOG(WARNING) << "Login WebUI >> Init postponed WebUI"; 723 724 // Wallpaper has finished loading before StartWizard/StartSignInScreen has 725 // been called. In general this should not happen. 726 // Let go through normal code path when one of those will be called. 727 if (restore_path_ == RESTORE_UNKNOWN) { 728 NOTREACHED(); 729 return; 730 } 731 732 switch (restore_path_) { 733 case RESTORE_WIZARD: 734 StartWizard(wizard_first_screen_name_, 735 wizard_screen_parameters_.Pass()); 736 break; 737 case RESTORE_SIGN_IN: 738 StartSignInScreen(); 739 break; 740 case RESTORE_ADD_USER_INTO_SESSION: 741 StartUserAdding(completion_callback_); 742 break; 743 default: 744 NOTREACHED(); 745 break; 746 } 747 } 748 749 void LoginDisplayHostImpl::InitLoginWindowAndView() { 750 if (login_window_) 751 return; 752 753 views::Widget::InitParams params( 754 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 755 params.bounds = background_bounds(); 756 params.show_state = ui::SHOW_STATE_FULLSCREEN; 757 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 758 params.parent = 759 ash::Shell::GetContainer( 760 ash::Shell::GetPrimaryRootWindow(), 761 ash::internal::kShellWindowId_LockScreenContainer); 762 763 login_window_ = new views::Widget; 764 login_window_->Init(params); 765 if (login_window_->GetNativeWindow()) { 766 aura::RootWindow* root = login_window_->GetNativeWindow()->GetRootWindow(); 767 if (root) { 768 old_ignore_solo_window_frame_painter_policy_value_ = 769 root->GetProperty(ash::internal::kIgnoreSoloWindowFramePainterPolicy); 770 root->SetProperty(ash::internal::kIgnoreSoloWindowFramePainterPolicy, 771 true); 772 } 773 } 774 login_view_ = new WebUILoginView(); 775 776 login_view_->Init(login_window_); 777 778 views::corewm::SetWindowVisibilityAnimationDuration( 779 login_window_->GetNativeView(), 780 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs)); 781 views::corewm::SetWindowVisibilityAnimationTransition( 782 login_window_->GetNativeView(), 783 views::corewm::ANIMATE_HIDE); 784 785 login_window_->SetContentsView(login_view_); 786 login_view_->UpdateWindowType(); 787 788 // If WebUI is initialized in hidden state, show it only if we're no 789 // longer waiting for wallpaper animation/user images loading. Otherwise, 790 // always show it. 791 if (!initialize_webui_hidden_ || 792 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) { 793 LOG(WARNING) << "Login WebUI >> show login wnd on create"; 794 login_window_->Show(); 795 } else { 796 LOG(WARNING) << "Login WebUI >> login wnd is hidden on create"; 797 login_view_->set_is_hidden(true); 798 } 799 login_window_->GetNativeView()->SetName("WebUILoginView"); 800 login_view_->OnWindowCreated(); 801 } 802 803 void LoginDisplayHostImpl::ResetLoginWindowAndView() { 804 if (!login_window_) 805 return; 806 807 if (login_window_->GetNativeWindow()) { 808 aura::RootWindow* root = login_window_->GetNativeWindow()->GetRootWindow(); 809 if (root) { 810 root->SetProperty(ash::internal::kIgnoreSoloWindowFramePainterPolicy, 811 old_ignore_solo_window_frame_painter_policy_value_); 812 } 813 } 814 login_window_->Close(); 815 login_window_ = NULL; 816 login_view_ = NULL; 817 } 818 819 bool LoginDisplayHostImpl::IsRunningUserAdding() { 820 return restore_path_ == RESTORE_ADD_USER_INTO_SESSION; 821 } 822 823 void LoginDisplayHostImpl::OnAuthPrewarmDone() { 824 auth_prewarmer_.reset(); 825 } 826 827 //////////////////////////////////////////////////////////////////////////////// 828 // external 829 830 // Declared in login_wizard.h so that others don't need to depend on our .h. 831 // TODO(nkostylev): Split this into a smaller functions. 832 void ShowLoginWizard(const std::string& first_screen_name) { 833 if (browser_shutdown::IsTryingToQuit()) 834 return; 835 836 VLOG(1) << "Showing OOBE screen: " << first_screen_name; 837 838 chromeos::input_method::InputMethodManager* manager = 839 chromeos::input_method::InputMethodManager::Get(); 840 841 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty 842 // and US dvorak keyboard layouts. 843 if (g_browser_process && g_browser_process->local_state()) { 844 manager->SetInputMethodDefault(); 845 846 PrefService* prefs = g_browser_process->local_state(); 847 // Apply owner preferences for tap-to-click and mouse buttons swap for 848 // login screen. 849 system::mouse_settings::SetPrimaryButtonRight( 850 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); 851 system::touchpad_settings::SetTapToClick( 852 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled)); 853 } 854 855 ui::SetNaturalScroll(CommandLine::ForCurrentProcess()->HasSwitch( 856 switches::kNaturalScrollDefault)); 857 858 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size())); 859 860 // Check whether we need to execute OOBE process. 861 bool oobe_complete = chromeos::StartupUtils::IsOobeCompleted(); 862 if (!oobe_complete) { 863 LoginState::Get()->SetLoggedInState( 864 LoginState::LOGGED_IN_OOBE, LoginState::LOGGED_IN_USER_NONE); 865 } else { 866 LoginState::Get()->SetLoggedInState( 867 LoginState::LOGGED_IN_NONE, LoginState::LOGGED_IN_USER_NONE); 868 } 869 bool show_login_screen = 870 (first_screen_name.empty() && oobe_complete) || 871 first_screen_name == chromeos::WizardController::kLoginScreenName; 872 873 chromeos::LoginDisplayHost* display_host = 874 new chromeos::LoginDisplayHostImpl(screen_bounds); 875 876 if (show_login_screen) { 877 // R11 > R12 migration fix. See http://crosbug.com/p/4898. 878 // If user has manually changed locale during R11 OOBE, locale will be set. 879 // On R12 > R12|R13 etc. this fix won't get activated since 880 // OOBE process has set kApplicationLocale to non-default value. 881 PrefService* prefs = g_browser_process->local_state(); 882 if (!prefs->HasPrefPath(prefs::kApplicationLocale)) { 883 std::string locale = chromeos::StartupUtils::GetInitialLocale(); 884 prefs->SetString(prefs::kApplicationLocale, locale); 885 manager->EnableLayouts( 886 locale, 887 manager->GetInputMethodUtil()->GetHardwareInputMethodId()); 888 base::ThreadRestrictions::ScopedAllowIO allow_io; 889 const std::string loaded_locale = 890 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); 891 g_browser_process->SetApplicationLocale(loaded_locale); 892 } 893 display_host->StartSignInScreen(); 894 return; 895 } 896 897 // Load startup manifest. 898 const chromeos::StartupCustomizationDocument* startup_manifest = 899 chromeos::StartupCustomizationDocument::GetInstance(); 900 901 // Switch to initial locale if specified by customization 902 // and has not been set yet. We cannot call 903 // chromeos::LanguageSwitchMenu::SwitchLanguage here before 904 // EmitLoginPromptReady. 905 PrefService* prefs = g_browser_process->local_state(); 906 const std::string current_locale = 907 prefs->GetString(prefs::kApplicationLocale); 908 VLOG(1) << "Current locale: " << current_locale; 909 std::string locale; 910 if (current_locale.empty()) { 911 locale = startup_manifest->initial_locale(); 912 std::string layout = startup_manifest->keyboard_layout(); 913 VLOG(1) << "Initial locale: " << locale 914 << "keyboard layout " << layout; 915 if (!locale.empty()) { 916 // Save initial locale from VPD/customization manifest as current 917 // Chrome locale. Otherwise it will be lost if Chrome restarts. 918 // Don't need to schedule pref save because setting initial local 919 // will enforce preference saving. 920 prefs->SetString(prefs::kApplicationLocale, locale); 921 chromeos::StartupUtils::SetInitialLocale(locale); 922 // Determine keyboard layout from OEM customization (if provided) or 923 // initial locale and save it in preferences. 924 DetermineAndSaveHardwareKeyboard(locale, layout); 925 // Then, enable the hardware keyboard. 926 manager->EnableLayouts( 927 locale, 928 manager->GetInputMethodUtil()->GetHardwareInputMethodId()); 929 // Reloading resource bundle causes us to do blocking IO on UI thread. 930 // Temporarily allow it until we fix http://crosbug.com/11102 931 base::ThreadRestrictions::ScopedAllowIO allow_io; 932 const std::string loaded_locale = 933 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); 934 CHECK(!loaded_locale.empty()) << "Locale could not be found for " 935 << locale; 936 // Set the application locale here so that the language switch 937 // menu works properly with the newly loaded locale. 938 g_browser_process->SetApplicationLocale(loaded_locale); 939 940 // Reload font settings here to use correct font for initial_locale. 941 LanguageSwitchMenu::LoadFontsForCurrentLocale(); 942 } 943 } 944 945 scoped_ptr<DictionaryValue> params; 946 display_host->StartWizard(first_screen_name, params.Pass()); 947 948 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() 949 ->EmitLoginPromptReady(); 950 TRACE_EVENT0("chromeos", "ShowLoginWizard::EmitLoginPromptReady"); 951 952 // Set initial timezone if specified by customization. 953 const std::string timezone_name = startup_manifest->initial_timezone(); 954 VLOG(1) << "Initial time zone: " << timezone_name; 955 // Apply locale customizations only once to preserve whatever locale 956 // user has changed to during OOBE. 957 if (!timezone_name.empty()) { 958 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( 959 UTF8ToUTF16(timezone_name)); 960 } 961 } 962 963 } // namespace chromeos 964