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