1 // Copyright 2014 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/ui/login_display_host_impl.h" 6 7 #include <vector> 8 9 #include "ash/audio/sounds.h" 10 #include "ash/desktop_background/desktop_background_controller.h" 11 #include "ash/desktop_background/user_wallpaper_delegate.h" 12 #include "ash/shell.h" 13 #include "ash/shell_window_ids.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/string_split.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/threading/thread_restrictions.h" 22 #include "base/time/time.h" 23 #include "base/values.h" 24 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/browser_shutdown.h" 26 #include "chrome/browser/chrome_notification_types.h" 27 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" 28 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" 29 #include "chrome/browser/chromeos/base/locale_util.h" 30 #include "chrome/browser/chromeos/boot_times_loader.h" 31 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h" 32 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h" 33 #include "chrome/browser/chromeos/first_run/first_run.h" 34 #include "chrome/browser/chromeos/input_method/input_method_util.h" 35 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" 36 #include "chrome/browser/chromeos/language_preferences.h" 37 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h" 38 #include "chrome/browser/chromeos/login/existing_user_controller.h" 39 #include "chrome/browser/chromeos/login/helper.h" 40 #include "chrome/browser/chromeos/login/login_utils.h" 41 #include "chrome/browser/chromeos/login/login_wizard.h" 42 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h" 43 #include "chrome/browser/chromeos/login/startup_utils.h" 44 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" 45 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h" 46 #include "chrome/browser/chromeos/login/ui/oobe_display.h" 47 #include "chrome/browser/chromeos/login/ui/webui_login_display.h" 48 #include "chrome/browser/chromeos/login/ui/webui_login_view.h" 49 #include "chrome/browser/chromeos/login/wizard_controller.h" 50 #include "chrome/browser/chromeos/mobile_config.h" 51 #include "chrome/browser/chromeos/net/delay_network_call.h" 52 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" 53 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" 54 #include "chrome/browser/chromeos/system/input_device_settings.h" 55 #include "chrome/browser/chromeos/ui/focus_ring_controller.h" 56 #include "chrome/browser/lifetime/application_lifetime.h" 57 #include "chrome/browser/profiles/profile_manager.h" 58 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 59 #include "chrome/common/chrome_constants.h" 60 #include "chrome/common/chrome_switches.h" 61 #include "chrome/common/pref_names.h" 62 #include "chrome/grit/browser_resources.h" 63 #include "chromeos/audio/chromeos_sounds.h" 64 #include "chromeos/chromeos_constants.h" 65 #include "chromeos/chromeos_switches.h" 66 #include "chromeos/dbus/dbus_thread_manager.h" 67 #include "chromeos/dbus/session_manager_client.h" 68 #include "chromeos/ime/extension_ime_util.h" 69 #include "chromeos/ime/input_method_manager.h" 70 #include "chromeos/login/login_state.h" 71 #include "chromeos/settings/timezone_settings.h" 72 #include "components/session_manager/core/session_manager.h" 73 #include "components/user_manager/user_manager.h" 74 #include "content/public/browser/notification_service.h" 75 #include "content/public/browser/notification_types.h" 76 #include "content/public/browser/web_contents.h" 77 #include "content/public/browser/web_ui.h" 78 #include "media/audio/sounds/sounds_manager.h" 79 #include "ui/aura/window.h" 80 #include "ui/base/resource/resource_bundle.h" 81 #include "ui/base/ui_base_switches_util.h" 82 #include "ui/compositor/layer.h" 83 #include "ui/compositor/layer_animation_observer.h" 84 #include "ui/compositor/scoped_layer_animation_settings.h" 85 #include "ui/events/event_utils.h" 86 #include "ui/gfx/display.h" 87 #include "ui/gfx/rect.h" 88 #include "ui/gfx/screen.h" 89 #include "ui/gfx/size.h" 90 #include "ui/gfx/transform.h" 91 #include "ui/keyboard/keyboard_controller.h" 92 #include "ui/keyboard/keyboard_util.h" 93 #include "ui/views/focus/focus_manager.h" 94 #include "ui/views/widget/widget.h" 95 #include "ui/views/widget/widget_delegate.h" 96 #include "ui/wm/core/window_animations.h" 97 #include "url/gurl.h" 98 99 #if defined(USE_ATHENA) 100 #include "athena/screen/public/screen_manager.h" 101 #include "athena/util/container_priorities.h" 102 #endif 103 104 namespace { 105 106 // Maximum delay for startup sound after 'loginPromptVisible' signal. 107 const int kStartupSoundMaxDelayMs = 2000; 108 109 // URL which corresponds to the login WebUI. 110 const char kLoginURL[] = "chrome://oobe/login"; 111 112 // URL which corresponds to the OOBE WebUI. 113 const char kOobeURL[] = "chrome://oobe/oobe"; 114 115 // URL which corresponds to the user adding WebUI. 116 const char kUserAddingURL[] = "chrome://oobe/user-adding"; 117 118 // URL which corresponds to the app launch splash WebUI. 119 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash"; 120 121 // Duration of sign-in transition animation. 122 const int kLoginFadeoutTransitionDurationMs = 700; 123 124 // Number of times we try to reload OOBE/login WebUI if it crashes. 125 const int kCrashCountLimit = 5; 126 127 // Whether to enable tnitializing WebUI in hidden state (see 128 // |initialize_webui_hidden_|) by default. 129 const bool kHiddenWebUIInitializationDefault = true; 130 131 // Switch values that might be used to override WebUI init type. 132 const char kWebUIInitParallel[] = "parallel"; 133 const char kWebUIInitPostpone[] = "postpone"; 134 135 // The delay of triggering initialization of the device policy subsystem 136 // after the login screen is initialized. This makes sure that device policy 137 // network requests are made while the system is idle waiting for user input. 138 const int64 kPolicyServiceInitializationDelayMilliseconds = 100; 139 140 // A class to observe an implicit animation and invokes the callback after the 141 // animation is completed. 142 class AnimationObserver : public ui::ImplicitAnimationObserver { 143 public: 144 explicit AnimationObserver(const base::Closure& callback) 145 : callback_(callback) {} 146 virtual ~AnimationObserver() {} 147 148 private: 149 // ui::ImplicitAnimationObserver implementation: 150 virtual void OnImplicitAnimationsCompleted() OVERRIDE { 151 callback_.Run(); 152 delete this; 153 } 154 155 base::Closure callback_; 156 157 DISALLOW_COPY_AND_ASSIGN(AnimationObserver); 158 }; 159 160 // ShowLoginWizard is split into two parts. This function is sometimes called 161 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback() 162 // (if locale was updated). 163 void ShowLoginWizardFinish( 164 const std::string& first_screen_name, 165 const chromeos::StartupCustomizationDocument* startup_manifest, 166 chromeos::LoginDisplayHost* display_host) { 167 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); 168 169 scoped_ptr<base::DictionaryValue> params; 170 display_host->StartWizard(first_screen_name, params.Pass()); 171 172 // Set initial timezone if specified by customization. 173 const std::string timezone_name = startup_manifest->initial_timezone(); 174 VLOG(1) << "Initial time zone: " << timezone_name; 175 // Apply locale customizations only once to preserve whatever locale 176 // user has changed to during OOBE. 177 if (!timezone_name.empty()) { 178 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( 179 base::UTF8ToUTF16(timezone_name)); 180 } 181 } 182 183 struct ShowLoginWizardSwitchLanguageCallbackData { 184 explicit ShowLoginWizardSwitchLanguageCallbackData( 185 const std::string& first_screen_name, 186 const chromeos::StartupCustomizationDocument* startup_manifest, 187 chromeos::LoginDisplayHost* display_host) 188 : first_screen_name(first_screen_name), 189 startup_manifest(startup_manifest), 190 display_host(display_host) {} 191 192 const std::string first_screen_name; 193 const chromeos::StartupCustomizationDocument* const startup_manifest; 194 chromeos::LoginDisplayHost* const display_host; 195 196 // lock UI while resource bundle is being reloaded. 197 chromeos::InputEventsBlocker events_blocker; 198 }; 199 200 void OnLanguageSwitchedCallback( 201 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self, 202 const std::string& locale, 203 const std::string& loaded_locale, 204 const bool success) { 205 if (!success) 206 LOG(WARNING) << "Locale could not be found for '" << locale << "'"; 207 208 ShowLoginWizardFinish( 209 self->first_screen_name, self->startup_manifest, self->display_host); 210 } 211 212 void EnableSystemSoundsForAccessibility() { 213 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true); 214 } 215 216 // A login implementation of WidgetDelegate. 217 class LoginWidgetDelegate : public views::WidgetDelegate { 218 public: 219 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) { 220 } 221 virtual ~LoginWidgetDelegate() {} 222 223 // Overridden from WidgetDelegate: 224 virtual void DeleteDelegate() OVERRIDE { 225 delete this; 226 } 227 virtual views::Widget* GetWidget() OVERRIDE { 228 return widget_; 229 } 230 virtual const views::Widget* GetWidget() const OVERRIDE { 231 return widget_; 232 } 233 virtual bool CanActivate() const OVERRIDE { 234 return true; 235 } 236 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { 237 return true; 238 } 239 240 private: 241 views::Widget* widget_; 242 243 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate); 244 }; 245 246 // Disables virtual keyboard overscroll. Login UI will scroll user pods 247 // into view on JS side when virtual keyboard is shown. 248 void DisableKeyboardOverscroll() { 249 keyboard::SetKeyboardOverscrollOverride( 250 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 251 } 252 253 void ResetKeyboardOverscrollOverride() { 254 keyboard::SetKeyboardOverscrollOverride( 255 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); 256 } 257 258 } // namespace 259 260 namespace chromeos { 261 262 // static 263 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL; 264 265 // static 266 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111; 267 268 //////////////////////////////////////////////////////////////////////////////// 269 // LoginDisplayHostImpl, public 270 271 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds) 272 : background_bounds_(background_bounds), 273 pointer_factory_(this), 274 shutting_down_(false), 275 oobe_progress_bar_visible_(false), 276 session_starting_(false), 277 login_window_(NULL), 278 login_view_(NULL), 279 webui_login_display_(NULL), 280 is_showing_login_(false), 281 is_wallpaper_loaded_(false), 282 status_area_saved_visibility_(false), 283 crash_count_(0), 284 restore_path_(RESTORE_UNKNOWN), 285 finalize_animation_type_(ANIMATION_WORKSPACE), 286 startup_sound_played_(false), 287 startup_sound_honors_spoken_feedback_(false), 288 is_observing_keyboard_(false), 289 animation_weak_ptr_factory_(this) { 290 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); 291 CrasAudioHandler::Get()->AddAudioObserver(this); 292 if (keyboard::KeyboardController::GetInstance()) { 293 keyboard::KeyboardController::GetInstance()->AddObserver(this); 294 is_observing_keyboard_ = true; 295 } 296 297 #if !defined(USE_ATHENA) 298 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this); 299 ash::Shell::GetScreen()->AddObserver(this); 300 #endif 301 302 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING 303 // because/ APP_TERMINATING will never be fired as long as this keeps 304 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no 305 // browser instance that will block the shutdown. 306 registrar_.Add(this, 307 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 308 content::NotificationService::AllSources()); 309 310 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but 311 // not shown yet. Lock window has to be closed at this point so that 312 // a browser window exists and the window can acquire input focus. 313 registrar_.Add(this, 314 chrome::NOTIFICATION_BROWSER_OPENED, 315 content::NotificationService::AllSources()); 316 317 // Login screen is moved to lock screen container when user logs in. 318 registrar_.Add(this, 319 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 320 content::NotificationService::AllSources()); 321 322 DCHECK(default_host_ == NULL); 323 default_host_ = this; 324 325 // Make sure chrome won't exit while we are at login/oobe screen. 326 chrome::IncrementKeepAliveCount(); 327 328 bool is_registered = StartupUtils::IsDeviceRegistered(); 329 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); 330 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch( 331 switches::kDisableBootAnimation); 332 333 waiting_for_wallpaper_load_ = !zero_delay_enabled && 334 (!is_registered || !disable_boot_animation); 335 336 #if defined(USE_ATHENA) 337 // TODO(dpolukhin): remove #ifdef when Athena supports wallpaper manager. 338 // crbug.com/408734 339 waiting_for_wallpaper_load_ = false; 340 #endif 341 342 // For slower hardware we have boot animation disabled so 343 // we'll be initializing WebUI hidden, waiting for user pods to load and then 344 // show WebUI at once. 345 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_; 346 347 initialize_webui_hidden_ = 348 kHiddenWebUIInitializationDefault && !zero_delay_enabled; 349 350 // Check if WebUI init type is overriden. 351 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) { 352 const std::string override_type = 353 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 354 switches::kAshWebUIInit); 355 if (override_type == kWebUIInitParallel) 356 initialize_webui_hidden_ = true; 357 else if (override_type == kWebUIInitPostpone) 358 initialize_webui_hidden_ = false; 359 } 360 361 // Always postpone WebUI initialization on first boot, otherwise we miss 362 // initial animation. 363 if (!StartupUtils::IsOobeCompleted()) 364 initialize_webui_hidden_ = false; 365 366 // There is no wallpaper for KioskMode, don't initialize the webui hidden. 367 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 368 initialize_webui_hidden_ = false; 369 370 if (waiting_for_wallpaper_load_) { 371 registrar_.Add(this, 372 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 373 content::NotificationService::AllSources()); 374 } 375 376 // When we wait for WebUI to be initialized we wait for one of 377 // these notifications. 378 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) && 379 initialize_webui_hidden_) { 380 registrar_.Add(this, 381 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 382 content::NotificationService::AllSources()); 383 registrar_.Add(this, 384 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 385 content::NotificationService::AllSources()); 386 } 387 VLOG(1) << "Login WebUI >> " 388 << "zero_delay: " << zero_delay_enabled 389 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_ 390 << " wait_for_pods_: " << waiting_for_user_pods_ 391 << " init_webui_hidden_: " << initialize_webui_hidden_; 392 393 media::SoundsManager* manager = media::SoundsManager::Get(); 394 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 395 manager->Initialize(chromeos::SOUND_STARTUP, 396 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV)); 397 } 398 399 LoginDisplayHostImpl::~LoginDisplayHostImpl() { 400 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); 401 CrasAudioHandler::Get()->RemoveAudioObserver(this); 402 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { 403 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 404 is_observing_keyboard_ = false; 405 } 406 407 #if !defined(USE_ATHENA) 408 ash::Shell::GetInstance()->delegate()-> 409 RemoveVirtualKeyboardStateObserver(this); 410 ash::Shell::GetScreen()->RemoveObserver(this); 411 #endif 412 413 if (login_view_ && login_window_) 414 login_window_->RemoveRemovalsObserver(this); 415 416 if (login::LoginScrollIntoViewEnabled()) 417 ResetKeyboardOverscrollOverride(); 418 419 views::FocusManager::set_arrow_key_traversal_enabled(false); 420 ResetLoginWindowAndView(); 421 422 // Let chrome process exit after login/oobe screen if needed. 423 chrome::DecrementKeepAliveCount(); 424 425 default_host_ = NULL; 426 // TODO(tengs): This should be refactored. See crbug.com/314934. 427 if (user_manager::UserManager::Get()->IsCurrentUserNew()) { 428 // DriveOptInController will delete itself when finished. 429 (new DriveFirstRunController( 430 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode(); 431 } 432 } 433 434 //////////////////////////////////////////////////////////////////////////////// 435 // LoginDisplayHostImpl, LoginDisplayHost implementation: 436 437 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay( 438 LoginDisplay::Delegate* delegate) { 439 webui_login_display_ = new WebUILoginDisplay(delegate); 440 webui_login_display_->set_background_bounds(background_bounds()); 441 return webui_login_display_; 442 } 443 444 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const { 445 return login_window_ ? login_window_->GetNativeWindow() : NULL; 446 } 447 448 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const { 449 return login_view_; 450 } 451 452 void LoginDisplayHostImpl::BeforeSessionStart() { 453 session_starting_ = true; 454 } 455 456 void LoginDisplayHostImpl::Finalize() { 457 DVLOG(1) << "Session starting"; 458 if (ash::Shell::HasInstance()) { 459 ash::Shell::GetInstance()-> 460 desktop_background_controller()->MoveDesktopToUnlockedContainer(); 461 } 462 if (wizard_controller_.get()) 463 wizard_controller_->OnSessionStart(); 464 465 switch (finalize_animation_type_) { 466 case ANIMATION_NONE: 467 ShutdownDisplayHost(false); 468 break; 469 case ANIMATION_WORKSPACE: 470 if (ash::Shell::HasInstance()) 471 ScheduleWorkspaceAnimation(); 472 473 ShutdownDisplayHost(false); 474 break; 475 case ANIMATION_FADE_OUT: 476 // Display host is deleted once animation is completed 477 // since sign in screen widget has to stay alive. 478 ScheduleFadeOutAnimation(); 479 break; 480 } 481 } 482 483 void LoginDisplayHostImpl::OnCompleteLogin() { 484 if (auto_enrollment_controller_) 485 auto_enrollment_controller_->Cancel(); 486 } 487 488 void LoginDisplayHostImpl::OpenProxySettings() { 489 if (login_view_) 490 login_view_->OpenProxySettings(); 491 } 492 493 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) { 494 if (initialize_webui_hidden_) 495 status_area_saved_visibility_ = visible; 496 else if (login_view_) 497 login_view_->SetStatusAreaVisible(visible); 498 } 499 500 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() { 501 if (!auto_enrollment_controller_) { 502 auto_enrollment_controller_.reset(new AutoEnrollmentController()); 503 auto_enrollment_progress_subscription_ = 504 auto_enrollment_controller_->RegisterProgressCallback( 505 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress, 506 base::Unretained(this))); 507 } 508 return auto_enrollment_controller_.get(); 509 } 510 511 void LoginDisplayHostImpl::StartWizard( 512 const std::string& first_screen_name, 513 scoped_ptr<base::DictionaryValue> screen_parameters) { 514 if (login::LoginScrollIntoViewEnabled()) 515 DisableKeyboardOverscroll(); 516 517 startup_sound_honors_spoken_feedback_ = false; 518 TryToPlayStartupSound(); 519 520 // Keep parameters to restore if renderer crashes. 521 restore_path_ = RESTORE_WIZARD; 522 wizard_first_screen_name_ = first_screen_name; 523 if (screen_parameters.get()) 524 wizard_screen_parameters_.reset(screen_parameters->DeepCopy()); 525 else 526 wizard_screen_parameters_.reset(); 527 is_showing_login_ = false; 528 529 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 530 VLOG(1) << "Login WebUI >> wizard postponed"; 531 return; 532 } 533 VLOG(1) << "Login WebUI >> wizard"; 534 535 if (!login_window_) 536 LoadURL(GURL(kOobeURL)); 537 538 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; 539 // Create and show the wizard. 540 // Note, dtor of the old WizardController should be called before ctor of the 541 // new one, because "default_controller()" is updated there. So pure "reset()" 542 // is done before new controller creation. 543 wizard_controller_.reset(); 544 wizard_controller_.reset(CreateWizardController()); 545 546 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 547 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 548 wizard_controller_->Init(first_screen_name, screen_parameters.Pass()); 549 } 550 551 WizardController* LoginDisplayHostImpl::GetWizardController() { 552 return wizard_controller_.get(); 553 } 554 555 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() { 556 return app_launch_controller_.get(); 557 } 558 559 void LoginDisplayHostImpl::StartUserAdding( 560 const base::Closure& completion_callback) { 561 if (login::LoginScrollIntoViewEnabled()) 562 DisableKeyboardOverscroll(); 563 564 restore_path_ = RESTORE_ADD_USER_INTO_SESSION; 565 completion_callback_ = completion_callback; 566 finalize_animation_type_ = ANIMATION_NONE; 567 VLOG(1) << "Login WebUI >> user adding"; 568 if (!login_window_) 569 LoadURL(GURL(kUserAddingURL)); 570 // We should emit this signal only at login screen (after reboot or sign out). 571 login_view_->set_should_emit_login_prompt_visible(false); 572 573 // Lock container can be transparent after lock screen animation. 574 aura::Window* lock_container = ash::Shell::GetContainer( 575 ash::Shell::GetPrimaryRootWindow(), 576 ash::kShellWindowId_LockScreenContainersContainer); 577 lock_container->layer()->SetOpacity(1.0); 578 579 ash::Shell::GetInstance()-> 580 desktop_background_controller()->MoveDesktopToLockedContainer(); 581 582 sign_in_controller_.reset(); // Only one controller in a time. 583 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 584 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false); 585 SetStatusAreaVisible(true); 586 sign_in_controller_->Init( 587 user_manager::UserManager::Get()->GetUsersAdmittedForMultiProfile()); 588 CHECK(webui_login_display_); 589 GetOobeUI()->ShowSigninScreen(LoginScreenContext(), 590 webui_login_display_, 591 webui_login_display_); 592 } 593 594 void LoginDisplayHostImpl::StartSignInScreen( 595 const LoginScreenContext& context) { 596 if (login::LoginScrollIntoViewEnabled()) 597 DisableKeyboardOverscroll(); 598 599 startup_sound_honors_spoken_feedback_ = true; 600 TryToPlayStartupSound(); 601 602 restore_path_ = RESTORE_SIGN_IN; 603 is_showing_login_ = true; 604 finalize_animation_type_ = ANIMATION_WORKSPACE; 605 606 PrewarmAuthentication(); 607 608 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 609 VLOG(1) << "Login WebUI >> sign in postponed"; 610 return; 611 } 612 VLOG(1) << "Login WebUI >> sign in"; 613 614 if (!login_window_) { 615 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid); 616 TRACE_EVENT_ASYNC_STEP_INTO0( 617 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen"); 618 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen"); 619 LoadURL(GURL(kLoginURL)); 620 } 621 622 DVLOG(1) << "Starting sign in screen"; 623 const user_manager::UserList& users = 624 user_manager::UserManager::Get()->GetUsers(); 625 626 // Fix for users who updated device and thus never passed register screen. 627 // If we already have users, we assume that it is not a second part of 628 // OOBE. See http://crosbug.com/6289 629 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) { 630 VLOG(1) << "Mark device registered because there are remembered users: " 631 << users.size(); 632 StartupUtils::MarkDeviceRegistered(base::Closure()); 633 } 634 635 sign_in_controller_.reset(); // Only one controller in a time. 636 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 637 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 638 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 639 SetStatusAreaVisible(true); 640 sign_in_controller_->Init(users); 641 642 // We might be here after a reboot that was triggered after OOBE was complete, 643 // so check for auto-enrollment again. This might catch a cached decision from 644 // a previous oobe flow, or might start a new check with the server. 645 if (GetAutoEnrollmentController()->ShouldEnrollSilently()) 646 sign_in_controller_->DoAutoEnrollment(); 647 else 648 GetAutoEnrollmentController()->Start(); 649 650 // Initiate mobile config load. 651 MobileConfig::GetInstance(); 652 653 // Initiate device policy fetching. 654 policy::BrowserPolicyConnectorChromeOS* connector = 655 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 656 connector->ScheduleServiceInitialization( 657 kPolicyServiceInitializationDelayMilliseconds); 658 659 CHECK(webui_login_display_); 660 GetOobeUI()->ShowSigninScreen(context, 661 webui_login_display_, 662 webui_login_display_); 663 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 664 SetStatusAreaVisible(false); 665 TRACE_EVENT_ASYNC_STEP_INTO0("ui", 666 "ShowLoginWebUI", 667 kShowLoginWebUIid, 668 "WaitForScreenStateInitialize"); 669 BootTimesLoader::Get()->RecordCurrentStats( 670 "login-wait-for-signin-state-initialize"); 671 } 672 673 void LoginDisplayHostImpl::ResumeSignInScreen() { 674 // We only get here after a previous call the StartSignInScreen. That sign-in 675 // was successful but was interrupted by an auto-enrollment execution; once 676 // auto-enrollment is complete we resume the normal login flow from here. 677 DVLOG(1) << "Resuming sign in screen"; 678 CHECK(sign_in_controller_.get()); 679 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 680 SetStatusAreaVisible(true); 681 sign_in_controller_->ResumeLogin(); 682 } 683 684 685 void LoginDisplayHostImpl::OnPreferencesChanged() { 686 if (is_showing_login_) 687 webui_login_display_->OnPreferencesChanged(); 688 } 689 690 void LoginDisplayHostImpl::PrewarmAuthentication() { 691 auth_prewarmer_.reset(new AuthPrewarmer()); 692 auth_prewarmer_->PrewarmAuthentication( 693 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone, 694 pointer_factory_.GetWeakPtr())); 695 } 696 697 void LoginDisplayHostImpl::StartDemoAppLaunch() { 698 VLOG(1) << "Login WebUI >> starting demo app."; 699 SetStatusAreaVisible(false); 700 701 demo_app_launcher_.reset(new DemoAppLauncher()); 702 demo_app_launcher_->StartDemoAppLaunch(); 703 } 704 705 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id, 706 bool diagnostic_mode) { 707 VLOG(1) << "Login WebUI >> start app launch."; 708 SetStatusAreaVisible(false); 709 finalize_animation_type_ = ANIMATION_FADE_OUT; 710 if (!login_window_) 711 LoadURL(GURL(kAppLaunchSplashURL)); 712 713 login_view_->set_should_emit_login_prompt_visible(false); 714 715 app_launch_controller_.reset(new AppLaunchController( 716 app_id, diagnostic_mode, this, GetOobeUI())); 717 718 app_launch_controller_->StartAppLaunch(); 719 } 720 721 //////////////////////////////////////////////////////////////////////////////// 722 // LoginDisplayHostImpl, public 723 724 WizardController* LoginDisplayHostImpl::CreateWizardController() { 725 // TODO(altimofeev): ensure that WebUI is ready. 726 OobeDisplay* oobe_display = GetOobeUI(); 727 return new WizardController(this, oobe_display); 728 } 729 730 void LoginDisplayHostImpl::OnBrowserCreated() { 731 // Close lock window now so that the launched browser can receive focus. 732 ResetLoginWindowAndView(); 733 } 734 735 OobeUI* LoginDisplayHostImpl::GetOobeUI() const { 736 if (!login_view_) 737 return NULL; 738 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController()); 739 } 740 741 //////////////////////////////////////////////////////////////////////////////// 742 // LoginDisplayHostImpl, content:NotificationObserver implementation: 743 744 void LoginDisplayHostImpl::Observe( 745 int type, 746 const content::NotificationSource& source, 747 const content::NotificationDetails& details) { 748 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) { 749 VLOG(1) << "Login WebUI >> wp animation done"; 750 is_wallpaper_loaded_ = true; 751 ash::Shell::GetInstance()->user_wallpaper_delegate() 752 ->OnWallpaperBootAnimationFinished(); 753 if (waiting_for_wallpaper_load_) { 754 // StartWizard / StartSignInScreen could be called multiple times through 755 // the lifetime of host. 756 // Make sure that subsequent calls are not postponed. 757 waiting_for_wallpaper_load_ = false; 758 if (initialize_webui_hidden_) 759 ShowWebUI(); 760 else 761 StartPostponedWebUI(); 762 } 763 registrar_.Remove(this, 764 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 765 content::NotificationService::AllSources()); 766 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type || 767 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) { 768 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE"; 769 if (waiting_for_user_pods_ && initialize_webui_hidden_) { 770 waiting_for_user_pods_ = false; 771 ShowWebUI(); 772 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { 773 // Reduce time till login UI is shown - show it as soon as possible. 774 waiting_for_wallpaper_load_ = false; 775 ShowWebUI(); 776 } 777 registrar_.Remove(this, 778 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 779 content::NotificationService::AllSources()); 780 registrar_.Remove(this, 781 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 782 content::NotificationService::AllSources()); 783 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { 784 ShutdownDisplayHost(true); 785 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { 786 // Browsers created before session start (windows opened by extensions, for 787 // example) are ignored. 788 OnBrowserCreated(); 789 registrar_.Remove(this, 790 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 791 content::NotificationService::AllSources()); 792 registrar_.Remove(this, 793 chrome::NOTIFICATION_BROWSER_OPENED, 794 content::NotificationService::AllSources()); 795 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && 796 user_manager::UserManager::Get()->IsCurrentUserNew()) { 797 #if !defined(USE_ATHENA) 798 // For new user, move desktop to locker container so that windows created 799 // during the user image picker step are below it. 800 ash::Shell::GetInstance()-> 801 desktop_background_controller()->MoveDesktopToLockedContainer(); 802 #endif 803 registrar_.Remove(this, 804 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 805 content::NotificationService::AllSources()); 806 } 807 } 808 809 //////////////////////////////////////////////////////////////////////////////// 810 // LoginDisplayHostImpl, WebContentsObserver implementation: 811 812 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) { 813 // Do not try to restore on shutdown 814 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) 815 return; 816 817 crash_count_++; 818 if (crash_count_ > kCrashCountLimit) 819 return; 820 821 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { 822 // Render with login screen crashed. Let's crash browser process to let 823 // session manager restart it properly. It is hard to reload the page 824 // and get to controlled state that is fully functional. 825 // If you see check, search for renderer crash for the same client. 826 LOG(FATAL) << "Renderer crash on login window"; 827 } 828 } 829 830 //////////////////////////////////////////////////////////////////////////////// 831 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer 832 // implementation: 833 834 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() { 835 OnLoginPromptVisible(); 836 } 837 838 //////////////////////////////////////////////////////////////////////////////// 839 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver 840 // implementation: 841 842 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() { 843 TryToPlayStartupSound(); 844 } 845 846 //////////////////////////////////////////////////////////////////////////////// 847 // LoginDisplayHostImpl, ash::KeyboardStateObserver: 848 // implementation: 849 850 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) { 851 if (keyboard::KeyboardController::GetInstance()) { 852 if (activated) { 853 if (!is_observing_keyboard_) { 854 keyboard::KeyboardController::GetInstance()->AddObserver(this); 855 is_observing_keyboard_ = true; 856 } 857 } else { 858 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 859 is_observing_keyboard_ = false; 860 } 861 } 862 } 863 864 //////////////////////////////////////////////////////////////////////////////// 865 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver: 866 // implementation: 867 868 void LoginDisplayHostImpl::OnKeyboardBoundsChanging( 869 const gfx::Rect& new_bounds) { 870 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) { 871 // Keyboard has been hidden. 872 if (GetOobeUI()) { 873 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true); 874 if (login::LoginScrollIntoViewEnabled()) 875 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds); 876 } 877 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) { 878 // Keyboard has been shown. 879 if (GetOobeUI()) { 880 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false); 881 if (login::LoginScrollIntoViewEnabled()) 882 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds); 883 } 884 } 885 886 keyboard_bounds_ = new_bounds; 887 } 888 889 //////////////////////////////////////////////////////////////////////////////// 890 // LoginDisplayHostImpl, gfx::DisplayObserver implementation: 891 892 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) { 893 } 894 895 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) { 896 } 897 898 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display, 899 uint32_t changed_metrics) { 900 if (display.id() != ash::Shell::GetScreen()->GetPrimaryDisplay().id() || 901 !(changed_metrics & DISPLAY_METRIC_BOUNDS)) { 902 return; 903 } 904 905 if (GetOobeUI()) { 906 const gfx::Size& size = ash::Shell::GetScreen()->GetPrimaryDisplay().size(); 907 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(), 908 size.height()); 909 } 910 } 911 912 //////////////////////////////////////////////////////////////////////////////// 913 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation: 914 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget, 915 views::View* view) { 916 if (view != static_cast<views::View*>(login_view_)) 917 return; 918 login_view_ = NULL; 919 widget->RemoveRemovalsObserver(this); 920 } 921 922 //////////////////////////////////////////////////////////////////////////////// 923 // LoginDisplayHostImpl, private 924 925 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) { 926 if (shutting_down_) 927 return; 928 929 shutting_down_ = true; 930 registrar_.RemoveAll(); 931 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 932 if (post_quit_task) 933 base::MessageLoop::current()->Quit(); 934 935 if (!completion_callback_.is_null()) 936 completion_callback_.Run(); 937 } 938 939 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() { 940 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), 941 ash::kShellWindowId_DesktopBackgroundContainer) 942 ->children() 943 .empty()) { 944 // If there is no background window, don't perform any animation on the 945 // default and background layer because there is nothing behind it. 946 return; 947 } 948 949 if (!CommandLine::ForCurrentProcess()->HasSwitch( 950 switches::kDisableLoginAnimations)) 951 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation(); 952 } 953 954 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() { 955 ui::Layer* layer = login_window_->GetLayer(); 956 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); 957 animation.AddObserver(new AnimationObserver( 958 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost, 959 animation_weak_ptr_factory_.GetWeakPtr(), 960 false))); 961 layer->SetOpacity(0); 962 } 963 964 void LoginDisplayHostImpl::OnAutoEnrollmentProgress( 965 policy::AutoEnrollmentState state) { 966 VLOG(1) << "OnAutoEnrollmentProgress, state " << state; 967 968 if (sign_in_controller_ && 969 auto_enrollment_controller_->ShouldEnrollSilently()) { 970 sign_in_controller_->DoAutoEnrollment(); 971 } 972 } 973 974 void LoginDisplayHostImpl::LoadURL(const GURL& url) { 975 InitLoginWindowAndView(); 976 // Subscribe to crash events. 977 content::WebContentsObserver::Observe(login_view_->GetWebContents()); 978 login_view_->LoadURL(url); 979 980 // LoadURL could be called after the spring charger dialog shows, and 981 // take away the focus from it. Set the focus back to the charger dialog 982 // if it is visible. 983 // See crbug.com/328538. 984 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible(); 985 } 986 987 void LoginDisplayHostImpl::ShowWebUI() { 988 if (!login_window_ || !login_view_) { 989 NOTREACHED(); 990 return; 991 } 992 VLOG(1) << "Login WebUI >> Show already initialized UI"; 993 login_window_->Show(); 994 login_view_->GetWebContents()->Focus(); 995 if (::switches::IsTextInputFocusManagerEnabled()) 996 login_view_->RequestFocus(); 997 login_view_->SetStatusAreaVisible(status_area_saved_visibility_); 998 login_view_->OnPostponedShow(); 999 1000 // Login window could be shown after the spring charger dialog shows, and 1001 // take away the focus from it. Set the focus back to the charger dialog 1002 // if it is visible. 1003 // See crbug.com/328538. 1004 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible(); 1005 1006 // We should reset this flag to allow changing of status area visibility. 1007 initialize_webui_hidden_ = false; 1008 } 1009 1010 void LoginDisplayHostImpl::StartPostponedWebUI() { 1011 if (!is_wallpaper_loaded_) { 1012 NOTREACHED(); 1013 return; 1014 } 1015 VLOG(1) << "Login WebUI >> Init postponed WebUI"; 1016 1017 // Wallpaper has finished loading before StartWizard/StartSignInScreen has 1018 // been called. In general this should not happen. 1019 // Let go through normal code path when one of those will be called. 1020 if (restore_path_ == RESTORE_UNKNOWN) { 1021 NOTREACHED(); 1022 return; 1023 } 1024 1025 switch (restore_path_) { 1026 case RESTORE_WIZARD: 1027 StartWizard(wizard_first_screen_name_, 1028 wizard_screen_parameters_.Pass()); 1029 break; 1030 case RESTORE_SIGN_IN: 1031 StartSignInScreen(LoginScreenContext()); 1032 break; 1033 case RESTORE_ADD_USER_INTO_SESSION: 1034 StartUserAdding(completion_callback_); 1035 break; 1036 default: 1037 NOTREACHED(); 1038 break; 1039 } 1040 } 1041 1042 void LoginDisplayHostImpl::InitLoginWindowAndView() { 1043 if (login_window_) 1044 return; 1045 1046 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) { 1047 views::FocusManager::set_arrow_key_traversal_enabled(true); 1048 #if !defined(USE_ATHENA) 1049 // crbug.com/405859 1050 focus_ring_controller_.reset(new FocusRingController); 1051 focus_ring_controller_->SetVisible(true); 1052 #endif 1053 1054 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler); 1055 } 1056 1057 views::Widget::InitParams params( 1058 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 1059 params.bounds = background_bounds(); 1060 params.show_state = ui::SHOW_STATE_FULLSCREEN; 1061 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 1062 #if defined(USE_ATHENA) 1063 athena::ScreenManager::ContainerParams container_params( 1064 "LoginScreen", athena::CP_LOGIN_SCREEN); 1065 container_params.can_activate_children = true; 1066 login_screen_container_.reset( 1067 athena::ScreenManager::Get()->CreateContainer(container_params)); 1068 params.parent = login_screen_container_.get(); 1069 #else 1070 params.parent = 1071 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), 1072 ash::kShellWindowId_LockScreenContainer); 1073 #endif 1074 login_window_ = new views::Widget; 1075 params.delegate = new LoginWidgetDelegate(login_window_); 1076 login_window_->Init(params); 1077 1078 login_view_ = new WebUILoginView(); 1079 login_view_->Init(); 1080 if (login_view_->webui_visible()) 1081 OnLoginPromptVisible(); 1082 1083 wm::SetWindowVisibilityAnimationDuration( 1084 login_window_->GetNativeView(), 1085 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs)); 1086 wm::SetWindowVisibilityAnimationTransition( 1087 login_window_->GetNativeView(), 1088 wm::ANIMATE_HIDE); 1089 1090 login_window_->AddRemovalsObserver(this); 1091 login_window_->SetContentsView(login_view_); 1092 1093 // If WebUI is initialized in hidden state, show it only if we're no 1094 // longer waiting for wallpaper animation/user images loading. Otherwise, 1095 // always show it. 1096 if (!initialize_webui_hidden_ || 1097 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) { 1098 VLOG(1) << "Login WebUI >> show login wnd on create"; 1099 login_window_->Show(); 1100 } else { 1101 VLOG(1) << "Login WebUI >> login wnd is hidden on create"; 1102 login_view_->set_is_hidden(true); 1103 } 1104 login_window_->GetNativeView()->SetName("WebUILoginView"); 1105 } 1106 1107 void LoginDisplayHostImpl::ResetLoginWindowAndView() { 1108 if (!login_window_) 1109 return; 1110 login_window_->Close(); 1111 login_window_ = NULL; 1112 login_view_ = NULL; 1113 } 1114 1115 void LoginDisplayHostImpl::OnAuthPrewarmDone() { 1116 auth_prewarmer_.reset(); 1117 } 1118 1119 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) { 1120 GetOobeUI()->ShowOobeUI(visible); 1121 } 1122 1123 void LoginDisplayHostImpl::TryToPlayStartupSound() { 1124 if (startup_sound_played_ || login_prompt_visible_time_.is_null() || 1125 !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) { 1126 return; 1127 } 1128 1129 startup_sound_played_ = true; 1130 1131 // Don't try play startup sound if login prompt is already visible 1132 // for a long time or can't be played. 1133 if (base::TimeTicks::Now() - login_prompt_visible_time_ > 1134 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) { 1135 EnableSystemSoundsForAccessibility(); 1136 return; 1137 } 1138 1139 if (!startup_sound_honors_spoken_feedback_ && 1140 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) { 1141 EnableSystemSoundsForAccessibility(); 1142 return; 1143 } 1144 1145 #if !defined(USE_ATHENA) 1146 // crbug.com/408733 1147 if (startup_sound_honors_spoken_feedback_ && 1148 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) { 1149 EnableSystemSoundsForAccessibility(); 1150 return; 1151 } 1152 #endif 1153 1154 base::MessageLoop::current()->PostDelayedTask( 1155 FROM_HERE, 1156 base::Bind(&EnableSystemSoundsForAccessibility), 1157 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP)); 1158 } 1159 1160 void LoginDisplayHostImpl::OnLoginPromptVisible() { 1161 if (!login_prompt_visible_time_.is_null()) 1162 return; 1163 login_prompt_visible_time_ = base::TimeTicks::Now(); 1164 TryToPlayStartupSound(); 1165 } 1166 1167 //////////////////////////////////////////////////////////////////////////////// 1168 // external 1169 1170 // Declared in login_wizard.h so that others don't need to depend on our .h. 1171 // TODO(nkostylev): Split this into a smaller functions. 1172 void ShowLoginWizard(const std::string& first_screen_name) { 1173 if (browser_shutdown::IsTryingToQuit()) 1174 return; 1175 1176 VLOG(1) << "Showing OOBE screen: " << first_screen_name; 1177 1178 #if !defined(USE_ATHENA) 1179 // TODO(dpolukhin): crbug.com/407579 1180 chromeos::input_method::InputMethodManager* manager = 1181 chromeos::input_method::InputMethodManager::Get(); 1182 1183 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty 1184 // and US dvorak keyboard layouts. 1185 if (g_browser_process && g_browser_process->local_state()) { 1186 manager->GetActiveIMEState()->SetInputMethodLoginDefault(); 1187 1188 PrefService* prefs = g_browser_process->local_state(); 1189 // Apply owner preferences for tap-to-click and mouse buttons swap for 1190 // login screen. 1191 system::InputDeviceSettings::Get()->SetPrimaryButtonRight( 1192 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); 1193 system::InputDeviceSettings::Get()->SetTapToClick( 1194 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled)); 1195 } 1196 system::InputDeviceSettings::Get()->SetNaturalScroll( 1197 CommandLine::ForCurrentProcess()->HasSwitch( 1198 switches::kNaturalScrollDefault)); 1199 #endif 1200 1201 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size())); 1202 1203 g_browser_process->platform_part()->SessionManager()->SetSessionState( 1204 StartupUtils::IsOobeCompleted() 1205 ? session_manager::SESSION_STATE_LOGIN_PRIMARY 1206 : session_manager::SESSION_STATE_OOBE); 1207 1208 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds); 1209 1210 bool show_app_launch_splash_screen = 1211 (first_screen_name == WizardController::kAppLaunchSplashScreenName); 1212 if (show_app_launch_splash_screen) { 1213 const std::string& auto_launch_app_id = 1214 KioskAppManager::Get()->GetAutoLaunchApp(); 1215 display_host->StartAppLaunch(auto_launch_app_id, 1216 false /* diagnostic_mode */); 1217 return; 1218 } 1219 1220 // Check whether we need to execute OOBE flow. 1221 bool oobe_complete = StartupUtils::IsOobeCompleted(); 1222 policy::BrowserPolicyConnectorChromeOS* connector = 1223 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 1224 bool enrollment_screen_wanted = 1225 WizardController::ShouldRecoverEnrollment() || 1226 (WizardController::ShouldAutoStartEnrollment() && oobe_complete && 1227 !connector->IsEnterpriseManaged()); 1228 if (enrollment_screen_wanted && first_screen_name.empty()) { 1229 // Shows networks screen instead of enrollment screen to resume the 1230 // interrupted auto start enrollment flow because enrollment screen does 1231 // not handle flaky network. See http://crbug.com/332572 1232 display_host->StartWizard(WizardController::kNetworkScreenName, 1233 scoped_ptr<base::DictionaryValue>()); 1234 return; 1235 } 1236 1237 if (StartupUtils::IsEulaAccepted()) { 1238 DelayNetworkCall( 1239 ServicesCustomizationDocument::GetInstance() 1240 ->EnsureCustomizationAppliedClosure(), 1241 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)); 1242 } 1243 1244 bool show_login_screen = 1245 (first_screen_name.empty() && oobe_complete) || 1246 first_screen_name == WizardController::kLoginScreenName; 1247 1248 if (show_login_screen) { 1249 display_host->StartSignInScreen(LoginScreenContext()); 1250 return; 1251 } 1252 1253 // Load startup manifest. 1254 const StartupCustomizationDocument* startup_manifest = 1255 StartupCustomizationDocument::GetInstance(); 1256 1257 // Switch to initial locale if specified by customization 1258 // and has not been set yet. We cannot call 1259 // LanguageSwitchMenu::SwitchLanguage here before 1260 // EmitLoginPromptReady. 1261 PrefService* prefs = g_browser_process->local_state(); 1262 const std::string& current_locale = 1263 prefs->GetString(prefs::kApplicationLocale); 1264 VLOG(1) << "Current locale: " << current_locale; 1265 const std::string& locale = startup_manifest->initial_locale_default(); 1266 1267 const std::string& layout = startup_manifest->keyboard_layout(); 1268 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout; 1269 1270 #if !defined(USE_ATHENA) 1271 // Determine keyboard layout from OEM customization (if provided) or 1272 // initial locale and save it in preferences. 1273 manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale, 1274 layout); 1275 #endif 1276 1277 if (!current_locale.empty() || locale.empty()) { 1278 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host); 1279 return; 1280 } 1281 1282 // Save initial locale from VPD/customization manifest as current 1283 // Chrome locale. Otherwise it will be lost if Chrome restarts. 1284 // Don't need to schedule pref save because setting initial local 1285 // will enforce preference saving. 1286 prefs->SetString(prefs::kApplicationLocale, locale); 1287 StartupUtils::SetInitialLocale(locale); 1288 1289 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( 1290 new ShowLoginWizardSwitchLanguageCallbackData( 1291 first_screen_name, startup_manifest, display_host)); 1292 1293 scoped_ptr<locale_util::SwitchLanguageCallback> callback( 1294 new locale_util::SwitchLanguageCallback( 1295 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass())))); 1296 1297 // Load locale keyboards here. Hardware layout would be automatically enabled. 1298 locale_util::SwitchLanguage( 1299 locale, true, true /* login_layouts_only */, callback.Pass()); 1300 } 1301 1302 } // namespace chromeos 1303