login_display_host_impl.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 "components/session_manager/core/session_manager.h" 72#include "content/public/browser/notification_service.h" 73#include "content/public/browser/notification_types.h" 74#include "content/public/browser/render_frame_host.h" 75#include "content/public/browser/web_contents.h" 76#include "content/public/browser/web_ui.h" 77#include "grit/browser_resources.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 99namespace { 100 101// Maximum delay for startup sound after 'loginPromptVisible' signal. 102const int kStartupSoundMaxDelayMs = 2000; 103 104// URL which corresponds to the login WebUI. 105const char kLoginURL[] = "chrome://oobe/login"; 106 107// URL which corresponds to the OOBE WebUI. 108const char kOobeURL[] = "chrome://oobe/oobe"; 109 110// URL which corresponds to the user adding WebUI. 111const char kUserAddingURL[] = "chrome://oobe/user-adding"; 112 113// URL which corresponds to the app launch splash WebUI. 114const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash"; 115 116// Duration of sign-in transition animation. 117const int kLoginFadeoutTransitionDurationMs = 700; 118 119// Number of times we try to reload OOBE/login WebUI if it crashes. 120const int kCrashCountLimit = 5; 121 122// Whether to enable tnitializing WebUI in hidden state (see 123// |initialize_webui_hidden_|) by default. 124const bool kHiddenWebUIInitializationDefault = true; 125 126// Switch values that might be used to override WebUI init type. 127const char kWebUIInitParallel[] = "parallel"; 128const char kWebUIInitPostpone[] = "postpone"; 129 130// The delay of triggering initialization of the device policy subsystem 131// after the login screen is initialized. This makes sure that device policy 132// network requests are made while the system is idle waiting for user input. 133const int64 kPolicyServiceInitializationDelayMilliseconds = 100; 134 135// A class to observe an implicit animation and invokes the callback after the 136// animation is completed. 137class AnimationObserver : public ui::ImplicitAnimationObserver { 138 public: 139 explicit AnimationObserver(const base::Closure& callback) 140 : callback_(callback) {} 141 virtual ~AnimationObserver() {} 142 143 private: 144 // ui::ImplicitAnimationObserver implementation: 145 virtual void OnImplicitAnimationsCompleted() OVERRIDE { 146 callback_.Run(); 147 delete this; 148 } 149 150 base::Closure callback_; 151 152 DISALLOW_COPY_AND_ASSIGN(AnimationObserver); 153}; 154 155// ShowLoginWizard is split into two parts. This function is sometimes called 156// from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback() 157// (if locale was updated). 158void ShowLoginWizardFinish( 159 const std::string& first_screen_name, 160 const chromeos::StartupCustomizationDocument* startup_manifest, 161 chromeos::LoginDisplayHost* display_host) { 162 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); 163 164 scoped_ptr<base::DictionaryValue> params; 165 display_host->StartWizard(first_screen_name, params.Pass()); 166 167 // Set initial timezone if specified by customization. 168 const std::string timezone_name = startup_manifest->initial_timezone(); 169 VLOG(1) << "Initial time zone: " << timezone_name; 170 // Apply locale customizations only once to preserve whatever locale 171 // user has changed to during OOBE. 172 if (!timezone_name.empty()) { 173 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( 174 base::UTF8ToUTF16(timezone_name)); 175 } 176} 177 178struct ShowLoginWizardSwitchLanguageCallbackData { 179 explicit ShowLoginWizardSwitchLanguageCallbackData( 180 const std::string& first_screen_name, 181 const chromeos::StartupCustomizationDocument* startup_manifest, 182 chromeos::LoginDisplayHost* display_host) 183 : first_screen_name(first_screen_name), 184 startup_manifest(startup_manifest), 185 display_host(display_host) {} 186 187 const std::string first_screen_name; 188 const chromeos::StartupCustomizationDocument* const startup_manifest; 189 chromeos::LoginDisplayHost* const display_host; 190 191 // lock UI while resource bundle is being reloaded. 192 chromeos::InputEventsBlocker events_blocker; 193}; 194 195void OnLanguageSwitchedCallback( 196 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self, 197 const std::string& locale, 198 const std::string& loaded_locale, 199 const bool success) { 200 if (!success) 201 LOG(WARNING) << "Locale could not be found for '" << locale << "'"; 202 203 ShowLoginWizardFinish( 204 self->first_screen_name, self->startup_manifest, self->display_host); 205} 206 207void EnableSystemSoundsForAccessibility() { 208 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true); 209} 210 211void AddToSetIfIsGaiaAuthIframe(std::set<content::RenderFrameHost*>* frame_set, 212 content::RenderFrameHost* frame) { 213 content::RenderFrameHost* parent = frame->GetParent(); 214 if (parent && parent->GetFrameName() == "signin-frame") 215 frame_set->insert(frame); 216} 217 218// A login implementation of WidgetDelegate. 219class LoginWidgetDelegate : public views::WidgetDelegate { 220 public: 221 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) { 222 } 223 virtual ~LoginWidgetDelegate() {} 224 225 // Overridden from WidgetDelegate: 226 virtual void DeleteDelegate() OVERRIDE { 227 delete this; 228 } 229 virtual views::Widget* GetWidget() OVERRIDE { 230 return widget_; 231 } 232 virtual const views::Widget* GetWidget() const OVERRIDE { 233 return widget_; 234 } 235 virtual bool CanActivate() const OVERRIDE { 236 return true; 237 } 238 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { 239 return true; 240 } 241 242 private: 243 views::Widget* widget_; 244 245 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate); 246}; 247 248// Disables virtual keyboard overscroll. Login UI will scroll user pods 249// into view on JS side when virtual keyboard is shown. 250void DisableKeyboardOverscroll() { 251 keyboard::SetKeyboardOverscrollOverride( 252 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 253} 254 255void ResetKeyboardOverscrollOverride() { 256 keyboard::SetKeyboardOverscrollOverride( 257 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); 258} 259 260} // namespace 261 262namespace chromeos { 263 264// static 265LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL; 266 267// static 268const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111; 269 270// static 271content::RenderFrameHost* LoginDisplayHostImpl::GetGaiaAuthIframe( 272 content::WebContents* web_contents) { 273 std::set<content::RenderFrameHost*> frame_set; 274 web_contents->ForEachFrame( 275 base::Bind(&AddToSetIfIsGaiaAuthIframe, &frame_set)); 276 DCHECK_EQ(1U, frame_set.size()); 277 return *frame_set.begin(); 278} 279 280//////////////////////////////////////////////////////////////////////////////// 281// LoginDisplayHostImpl, public 282 283LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds) 284 : background_bounds_(background_bounds), 285 pointer_factory_(this), 286 shutting_down_(false), 287 oobe_progress_bar_visible_(false), 288 session_starting_(false), 289 login_window_(NULL), 290 login_view_(NULL), 291 webui_login_display_(NULL), 292 is_showing_login_(false), 293 is_wallpaper_loaded_(false), 294 status_area_saved_visibility_(false), 295 crash_count_(0), 296 restore_path_(RESTORE_UNKNOWN), 297 finalize_animation_type_(ANIMATION_WORKSPACE), 298 animation_weak_ptr_factory_(this), 299 startup_sound_played_(false), 300 startup_sound_honors_spoken_feedback_(false), 301 is_observing_keyboard_(false) { 302 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); 303 CrasAudioHandler::Get()->AddAudioObserver(this); 304 if (keyboard::KeyboardController::GetInstance()) { 305 keyboard::KeyboardController::GetInstance()->AddObserver(this); 306 is_observing_keyboard_ = true; 307 } 308 309 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this); 310 ash::Shell::GetScreen()->AddObserver(this); 311 312 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING 313 // because/ APP_TERMINATING will never be fired as long as this keeps 314 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no 315 // browser instance that will block the shutdown. 316 registrar_.Add(this, 317 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 318 content::NotificationService::AllSources()); 319 320 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but 321 // not shown yet. Lock window has to be closed at this point so that 322 // a browser window exists and the window can acquire input focus. 323 registrar_.Add(this, 324 chrome::NOTIFICATION_BROWSER_OPENED, 325 content::NotificationService::AllSources()); 326 327 // Login screen is moved to lock screen container when user logs in. 328 registrar_.Add(this, 329 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 330 content::NotificationService::AllSources()); 331 332 DCHECK(default_host_ == NULL); 333 default_host_ = this; 334 335 // Make sure chrome won't exit while we are at login/oobe screen. 336 chrome::IncrementKeepAliveCount(); 337 338 bool is_registered = StartupUtils::IsDeviceRegistered(); 339 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); 340 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch( 341 switches::kDisableBootAnimation); 342 343 waiting_for_wallpaper_load_ = !zero_delay_enabled && 344 (!is_registered || !disable_boot_animation); 345 346 // For slower hardware we have boot animation disabled so 347 // we'll be initializing WebUI hidden, waiting for user pods to load and then 348 // show WebUI at once. 349 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_; 350 351 initialize_webui_hidden_ = 352 kHiddenWebUIInitializationDefault && !zero_delay_enabled; 353 354 // Check if WebUI init type is overriden. 355 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) { 356 const std::string override_type = 357 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 358 switches::kAshWebUIInit); 359 if (override_type == kWebUIInitParallel) 360 initialize_webui_hidden_ = true; 361 else if (override_type == kWebUIInitPostpone) 362 initialize_webui_hidden_ = false; 363 } 364 365 // Always postpone WebUI initialization on first boot, otherwise we miss 366 // initial animation. 367 if (!StartupUtils::IsOobeCompleted()) 368 initialize_webui_hidden_ = false; 369 370 // There is no wallpaper for KioskMode, don't initialize the webui hidden. 371 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 372 initialize_webui_hidden_ = false; 373 374 if (waiting_for_wallpaper_load_) { 375 registrar_.Add(this, 376 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 377 content::NotificationService::AllSources()); 378 } 379 380 // When we wait for WebUI to be initialized we wait for one of 381 // these notifications. 382 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) && 383 initialize_webui_hidden_) { 384 registrar_.Add(this, 385 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 386 content::NotificationService::AllSources()); 387 registrar_.Add(this, 388 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 389 content::NotificationService::AllSources()); 390 } 391 VLOG(1) << "Login WebUI >> " 392 << "zero_delay: " << zero_delay_enabled 393 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_ 394 << " wait_for_pods_: " << waiting_for_user_pods_ 395 << " init_webui_hidden_: " << initialize_webui_hidden_; 396 397 media::SoundsManager* manager = media::SoundsManager::Get(); 398 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 399 manager->Initialize(chromeos::SOUND_STARTUP, 400 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV)); 401} 402 403LoginDisplayHostImpl::~LoginDisplayHostImpl() { 404 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); 405 CrasAudioHandler::Get()->RemoveAudioObserver(this); 406 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { 407 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 408 is_observing_keyboard_ = false; 409 } 410 411 ash::Shell::GetInstance()->delegate()-> 412 RemoveVirtualKeyboardStateObserver(this); 413 ash::Shell::GetScreen()->RemoveObserver(this); 414 415 if (login_view_ && login_window_) 416 login_window_->RemoveRemovalsObserver(this); 417 418 if (login::LoginScrollIntoViewEnabled()) 419 ResetKeyboardOverscrollOverride(); 420 421 views::FocusManager::set_arrow_key_traversal_enabled(false); 422 ResetLoginWindowAndView(); 423 424 // Let chrome process exit after login/oobe screen if needed. 425 chrome::DecrementKeepAliveCount(); 426 427 default_host_ = NULL; 428 // TODO(tengs): This should be refactored. See crbug.com/314934. 429 if (UserManager::Get()->IsCurrentUserNew()) { 430 // DriveOptInController will delete itself when finished. 431 (new DriveFirstRunController( 432 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode(); 433 } 434} 435 436//////////////////////////////////////////////////////////////////////////////// 437// LoginDisplayHostImpl, LoginDisplayHost implementation: 438 439LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay( 440 LoginDisplay::Delegate* delegate) { 441 webui_login_display_ = new WebUILoginDisplay(delegate); 442 webui_login_display_->set_background_bounds(background_bounds()); 443 return webui_login_display_; 444} 445 446gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const { 447 return login_window_ ? login_window_->GetNativeWindow() : NULL; 448} 449 450WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const { 451 return login_view_; 452} 453 454void LoginDisplayHostImpl::BeforeSessionStart() { 455 session_starting_ = true; 456} 457 458void LoginDisplayHostImpl::Finalize() { 459 DVLOG(1) << "Session starting"; 460 if (ash::Shell::HasInstance()) { 461 ash::Shell::GetInstance()-> 462 desktop_background_controller()->MoveDesktopToUnlockedContainer(); 463 } 464 if (wizard_controller_.get()) 465 wizard_controller_->OnSessionStart(); 466 467 switch (finalize_animation_type_) { 468 case ANIMATION_NONE: 469 ShutdownDisplayHost(false); 470 break; 471 case ANIMATION_WORKSPACE: 472 if (ash::Shell::HasInstance()) 473 ScheduleWorkspaceAnimation(); 474 475 ShutdownDisplayHost(false); 476 break; 477 case ANIMATION_FADE_OUT: 478 // Display host is deleted once animation is completed 479 // since sign in screen widget has to stay alive. 480 ScheduleFadeOutAnimation(); 481 break; 482 } 483} 484 485void LoginDisplayHostImpl::OnCompleteLogin() { 486 if (auto_enrollment_controller_) 487 auto_enrollment_controller_->Cancel(); 488} 489 490void LoginDisplayHostImpl::OpenProxySettings() { 491 if (login_view_) 492 login_view_->OpenProxySettings(); 493} 494 495void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) { 496 if (initialize_webui_hidden_) 497 status_area_saved_visibility_ = visible; 498 else if (login_view_) 499 login_view_->SetStatusAreaVisible(visible); 500} 501 502AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() { 503 if (!auto_enrollment_controller_) { 504 auto_enrollment_controller_.reset(new AutoEnrollmentController()); 505 auto_enrollment_progress_subscription_ = 506 auto_enrollment_controller_->RegisterProgressCallback( 507 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress, 508 base::Unretained(this))); 509 } 510 return auto_enrollment_controller_.get(); 511} 512 513void LoginDisplayHostImpl::StartWizard( 514 const std::string& first_screen_name, 515 scoped_ptr<base::DictionaryValue> screen_parameters) { 516 if (login::LoginScrollIntoViewEnabled()) 517 DisableKeyboardOverscroll(); 518 519 startup_sound_honors_spoken_feedback_ = false; 520 TryToPlayStartupSound(); 521 522 // Keep parameters to restore if renderer crashes. 523 restore_path_ = RESTORE_WIZARD; 524 wizard_first_screen_name_ = first_screen_name; 525 if (screen_parameters.get()) 526 wizard_screen_parameters_.reset(screen_parameters->DeepCopy()); 527 else 528 wizard_screen_parameters_.reset(); 529 is_showing_login_ = false; 530 531 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 532 VLOG(1) << "Login WebUI >> wizard postponed"; 533 return; 534 } 535 VLOG(1) << "Login WebUI >> wizard"; 536 537 if (!login_window_) 538 LoadURL(GURL(kOobeURL)); 539 540 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; 541 // Create and show the wizard. 542 // Note, dtor of the old WizardController should be called before ctor of the 543 // new one, because "default_controller()" is updated there. So pure "reset()" 544 // is done before new controller creation. 545 wizard_controller_.reset(); 546 wizard_controller_.reset(CreateWizardController()); 547 548 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 549 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 550 wizard_controller_->Init(first_screen_name, screen_parameters.Pass()); 551} 552 553WizardController* LoginDisplayHostImpl::GetWizardController() { 554 return wizard_controller_.get(); 555} 556 557AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() { 558 return app_launch_controller_.get(); 559} 560 561void LoginDisplayHostImpl::StartUserAdding( 562 const base::Closure& completion_callback) { 563 if (login::LoginScrollIntoViewEnabled()) 564 DisableKeyboardOverscroll(); 565 566 restore_path_ = RESTORE_ADD_USER_INTO_SESSION; 567 completion_callback_ = completion_callback; 568 finalize_animation_type_ = ANIMATION_NONE; 569 VLOG(1) << "Login WebUI >> user adding"; 570 if (!login_window_) 571 LoadURL(GURL(kUserAddingURL)); 572 // We should emit this signal only at login screen (after reboot or sign out). 573 login_view_->set_should_emit_login_prompt_visible(false); 574 575 // Lock container can be transparent after lock screen animation. 576 aura::Window* lock_container = ash::Shell::GetContainer( 577 ash::Shell::GetPrimaryRootWindow(), 578 ash::kShellWindowId_LockScreenContainersContainer); 579 lock_container->layer()->SetOpacity(1.0); 580 581 ash::Shell::GetInstance()-> 582 desktop_background_controller()->MoveDesktopToLockedContainer(); 583 584 sign_in_controller_.reset(); // Only one controller in a time. 585 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 586 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false); 587 SetStatusAreaVisible(true); 588 sign_in_controller_->Init( 589 chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile()); 590 CHECK(webui_login_display_); 591 GetOobeUI()->ShowSigninScreen(LoginScreenContext(), 592 webui_login_display_, 593 webui_login_display_); 594} 595 596void LoginDisplayHostImpl::StartSignInScreen( 597 const LoginScreenContext& context) { 598 if (login::LoginScrollIntoViewEnabled()) 599 DisableKeyboardOverscroll(); 600 601 startup_sound_honors_spoken_feedback_ = true; 602 TryToPlayStartupSound(); 603 604 restore_path_ = RESTORE_SIGN_IN; 605 is_showing_login_ = true; 606 finalize_animation_type_ = ANIMATION_WORKSPACE; 607 608 PrewarmAuthentication(); 609 610 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { 611 VLOG(1) << "Login WebUI >> sign in postponed"; 612 return; 613 } 614 VLOG(1) << "Login WebUI >> sign in"; 615 616 if (!login_window_) { 617 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid); 618 TRACE_EVENT_ASYNC_STEP_INTO0( 619 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen"); 620 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen"); 621 LoadURL(GURL(kLoginURL)); 622 } 623 624 DVLOG(1) << "Starting sign in screen"; 625 const user_manager::UserList& users = 626 chromeos::UserManager::Get()->GetUsers(); 627 628 // Fix for users who updated device and thus never passed register screen. 629 // If we already have users, we assume that it is not a second part of 630 // OOBE. See http://crosbug.com/6289 631 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) { 632 VLOG(1) << "Mark device registered because there are remembered users: " 633 << users.size(); 634 StartupUtils::MarkDeviceRegistered(base::Closure()); 635 } 636 637 sign_in_controller_.reset(); // Only one controller in a time. 638 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); 639 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); 640 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 641 SetStatusAreaVisible(true); 642 sign_in_controller_->Init(users); 643 644 // We might be here after a reboot that was triggered after OOBE was complete, 645 // so check for auto-enrollment again. This might catch a cached decision from 646 // a previous oobe flow, or might start a new check with the server. 647 if (GetAutoEnrollmentController()->ShouldEnrollSilently()) 648 sign_in_controller_->DoAutoEnrollment(); 649 else 650 GetAutoEnrollmentController()->Start(); 651 652 // Initiate mobile config load. 653 MobileConfig::GetInstance(); 654 655 // Initiate device policy fetching. 656 policy::BrowserPolicyConnectorChromeOS* connector = 657 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 658 connector->ScheduleServiceInitialization( 659 kPolicyServiceInitializationDelayMilliseconds); 660 661 CHECK(webui_login_display_); 662 GetOobeUI()->ShowSigninScreen(context, 663 webui_login_display_, 664 webui_login_display_); 665 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) 666 SetStatusAreaVisible(false); 667 TRACE_EVENT_ASYNC_STEP_INTO0("ui", 668 "ShowLoginWebUI", 669 kShowLoginWebUIid, 670 "WaitForScreenStateInitialize"); 671 BootTimesLoader::Get()->RecordCurrentStats( 672 "login-wait-for-signin-state-initialize"); 673} 674 675void LoginDisplayHostImpl::ResumeSignInScreen() { 676 // We only get here after a previous call the StartSignInScreen. That sign-in 677 // was successful but was interrupted by an auto-enrollment execution; once 678 // auto-enrollment is complete we resume the normal login flow from here. 679 DVLOG(1) << "Resuming sign in screen"; 680 CHECK(sign_in_controller_.get()); 681 SetOobeProgressBarVisible(oobe_progress_bar_visible_); 682 SetStatusAreaVisible(true); 683 sign_in_controller_->ResumeLogin(); 684} 685 686 687void LoginDisplayHostImpl::OnPreferencesChanged() { 688 if (is_showing_login_) 689 webui_login_display_->OnPreferencesChanged(); 690} 691 692void LoginDisplayHostImpl::PrewarmAuthentication() { 693 auth_prewarmer_.reset(new AuthPrewarmer()); 694 auth_prewarmer_->PrewarmAuthentication( 695 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone, 696 pointer_factory_.GetWeakPtr())); 697} 698 699void LoginDisplayHostImpl::StartDemoAppLaunch() { 700 VLOG(1) << "Login WebUI >> starting demo app."; 701 SetStatusAreaVisible(false); 702 703 demo_app_launcher_.reset(new DemoAppLauncher()); 704 demo_app_launcher_->StartDemoAppLaunch(); 705} 706 707void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id, 708 bool diagnostic_mode) { 709 VLOG(1) << "Login WebUI >> start app launch."; 710 SetStatusAreaVisible(false); 711 finalize_animation_type_ = ANIMATION_FADE_OUT; 712 if (!login_window_) 713 LoadURL(GURL(kAppLaunchSplashURL)); 714 715 login_view_->set_should_emit_login_prompt_visible(false); 716 717 app_launch_controller_.reset(new AppLaunchController( 718 app_id, diagnostic_mode, this, GetOobeUI())); 719 720 app_launch_controller_->StartAppLaunch(); 721} 722 723//////////////////////////////////////////////////////////////////////////////// 724// LoginDisplayHostImpl, public 725 726WizardController* LoginDisplayHostImpl::CreateWizardController() { 727 // TODO(altimofeev): ensure that WebUI is ready. 728 OobeDisplay* oobe_display = GetOobeUI(); 729 return new WizardController(this, oobe_display); 730} 731 732void LoginDisplayHostImpl::OnBrowserCreated() { 733 // Close lock window now so that the launched browser can receive focus. 734 ResetLoginWindowAndView(); 735} 736 737OobeUI* LoginDisplayHostImpl::GetOobeUI() const { 738 if (!login_view_) 739 return NULL; 740 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController()); 741} 742 743//////////////////////////////////////////////////////////////////////////////// 744// LoginDisplayHostImpl, content:NotificationObserver implementation: 745 746void LoginDisplayHostImpl::Observe( 747 int type, 748 const content::NotificationSource& source, 749 const content::NotificationDetails& details) { 750 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) { 751 VLOG(1) << "Login WebUI >> wp animation done"; 752 is_wallpaper_loaded_ = true; 753 ash::Shell::GetInstance()->user_wallpaper_delegate() 754 ->OnWallpaperBootAnimationFinished(); 755 if (waiting_for_wallpaper_load_) { 756 // StartWizard / StartSignInScreen could be called multiple times through 757 // the lifetime of host. 758 // Make sure that subsequent calls are not postponed. 759 waiting_for_wallpaper_load_ = false; 760 if (initialize_webui_hidden_) 761 ShowWebUI(); 762 else 763 StartPostponedWebUI(); 764 } 765 registrar_.Remove(this, 766 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, 767 content::NotificationService::AllSources()); 768 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type || 769 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) { 770 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE"; 771 if (waiting_for_user_pods_ && initialize_webui_hidden_) { 772 waiting_for_user_pods_ = false; 773 ShowWebUI(); 774 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { 775 // Reduce time till login UI is shown - show it as soon as possible. 776 waiting_for_wallpaper_load_ = false; 777 ShowWebUI(); 778 } 779 registrar_.Remove(this, 780 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 781 content::NotificationService::AllSources()); 782 registrar_.Remove(this, 783 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, 784 content::NotificationService::AllSources()); 785 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { 786 ShutdownDisplayHost(true); 787 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { 788 // Browsers created before session start (windows opened by extensions, for 789 // example) are ignored. 790 OnBrowserCreated(); 791 registrar_.Remove(this, 792 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, 793 content::NotificationService::AllSources()); 794 registrar_.Remove(this, 795 chrome::NOTIFICATION_BROWSER_OPENED, 796 content::NotificationService::AllSources()); 797 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && 798 chromeos::UserManager::Get()->IsCurrentUserNew()) { 799 // For new user, move desktop to locker container so that windows created 800 // during the user image picker step are below it. 801 ash::Shell::GetInstance()-> 802 desktop_background_controller()->MoveDesktopToLockedContainer(); 803 registrar_.Remove(this, 804 chrome::NOTIFICATION_LOGIN_USER_CHANGED, 805 content::NotificationService::AllSources()); 806 } 807} 808 809//////////////////////////////////////////////////////////////////////////////// 810// LoginDisplayHostImpl, WebContentsObserver implementation: 811 812void 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 834void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() { 835 OnLoginPromptVisible(); 836} 837 838//////////////////////////////////////////////////////////////////////////////// 839// LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver 840// implementation: 841 842void LoginDisplayHostImpl::OnActiveOutputNodeChanged() { 843 TryToPlayStartupSound(); 844} 845 846//////////////////////////////////////////////////////////////////////////////// 847// LoginDisplayHostImpl, ash::KeyboardStateObserver: 848// implementation: 849 850void 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 868void 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 892void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) { 893} 894 895void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) { 896} 897 898void 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: 914void 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 925void 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 939void 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 954void 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 964void 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 974void 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 987void 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 1010void 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 1042void 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 1049 focus_ring_controller_.reset(new FocusRingController); 1050 focus_ring_controller_->SetVisible(true); 1051 1052 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler); 1053 } 1054 1055 views::Widget::InitParams params( 1056 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 1057 params.bounds = background_bounds(); 1058 params.show_state = ui::SHOW_STATE_FULLSCREEN; 1059 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 1060 params.parent = 1061 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), 1062 ash::kShellWindowId_LockScreenContainer); 1063 1064 login_window_ = new views::Widget; 1065 params.delegate = new LoginWidgetDelegate(login_window_); 1066 login_window_->Init(params); 1067 1068 login_view_ = new WebUILoginView(); 1069 login_view_->Init(); 1070 if (login_view_->webui_visible()) 1071 OnLoginPromptVisible(); 1072 1073 wm::SetWindowVisibilityAnimationDuration( 1074 login_window_->GetNativeView(), 1075 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs)); 1076 wm::SetWindowVisibilityAnimationTransition( 1077 login_window_->GetNativeView(), 1078 wm::ANIMATE_HIDE); 1079 1080 login_window_->AddRemovalsObserver(this); 1081 login_window_->SetContentsView(login_view_); 1082 1083 // If WebUI is initialized in hidden state, show it only if we're no 1084 // longer waiting for wallpaper animation/user images loading. Otherwise, 1085 // always show it. 1086 if (!initialize_webui_hidden_ || 1087 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) { 1088 VLOG(1) << "Login WebUI >> show login wnd on create"; 1089 login_window_->Show(); 1090 } else { 1091 VLOG(1) << "Login WebUI >> login wnd is hidden on create"; 1092 login_view_->set_is_hidden(true); 1093 } 1094 login_window_->GetNativeView()->SetName("WebUILoginView"); 1095} 1096 1097void LoginDisplayHostImpl::ResetLoginWindowAndView() { 1098 if (!login_window_) 1099 return; 1100 login_window_->Close(); 1101 login_window_ = NULL; 1102 login_view_ = NULL; 1103} 1104 1105void LoginDisplayHostImpl::OnAuthPrewarmDone() { 1106 auth_prewarmer_.reset(); 1107} 1108 1109void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) { 1110 GetOobeUI()->ShowOobeUI(visible); 1111} 1112 1113void LoginDisplayHostImpl::TryToPlayStartupSound() { 1114 if (startup_sound_played_ || login_prompt_visible_time_.is_null() || 1115 !CrasAudioHandler::Get()->GetActiveOutputNode()) { 1116 return; 1117 } 1118 1119 startup_sound_played_ = true; 1120 1121 // Don't try play startup sound if login prompt is already visible 1122 // for a long time or can't be played. 1123 if (base::TimeTicks::Now() - login_prompt_visible_time_ > 1124 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) { 1125 EnableSystemSoundsForAccessibility(); 1126 return; 1127 } 1128 1129 if (!startup_sound_honors_spoken_feedback_ && 1130 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) { 1131 EnableSystemSoundsForAccessibility(); 1132 return; 1133 } 1134 1135 if (startup_sound_honors_spoken_feedback_ && 1136 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) { 1137 EnableSystemSoundsForAccessibility(); 1138 return; 1139 } 1140 1141 base::MessageLoop::current()->PostDelayedTask( 1142 FROM_HERE, 1143 base::Bind(&EnableSystemSoundsForAccessibility), 1144 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP)); 1145} 1146 1147void LoginDisplayHostImpl::OnLoginPromptVisible() { 1148 if (!login_prompt_visible_time_.is_null()) 1149 return; 1150 login_prompt_visible_time_ = base::TimeTicks::Now(); 1151 TryToPlayStartupSound(); 1152} 1153 1154//////////////////////////////////////////////////////////////////////////////// 1155// external 1156 1157// Declared in login_wizard.h so that others don't need to depend on our .h. 1158// TODO(nkostylev): Split this into a smaller functions. 1159void ShowLoginWizard(const std::string& first_screen_name) { 1160 if (browser_shutdown::IsTryingToQuit()) 1161 return; 1162 1163 VLOG(1) << "Showing OOBE screen: " << first_screen_name; 1164 1165 chromeos::input_method::InputMethodManager* manager = 1166 chromeos::input_method::InputMethodManager::Get(); 1167 1168 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty 1169 // and US dvorak keyboard layouts. 1170 if (g_browser_process && g_browser_process->local_state()) { 1171 manager->SetInputMethodLoginDefault(); 1172 1173 PrefService* prefs = g_browser_process->local_state(); 1174 // Apply owner preferences for tap-to-click and mouse buttons swap for 1175 // login screen. 1176 system::InputDeviceSettings::Get()->SetPrimaryButtonRight( 1177 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); 1178 system::InputDeviceSettings::Get()->SetTapToClick( 1179 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled)); 1180 } 1181 system::InputDeviceSettings::Get()->SetNaturalScroll( 1182 CommandLine::ForCurrentProcess()->HasSwitch( 1183 switches::kNaturalScrollDefault)); 1184 1185 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size())); 1186 1187 g_browser_process->platform_part()->SessionManager()->SetSessionState( 1188 StartupUtils::IsOobeCompleted() 1189 ? session_manager::SESSION_STATE_LOGIN_PRIMARY 1190 : session_manager::SESSION_STATE_OOBE); 1191 1192 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds); 1193 1194 bool show_app_launch_splash_screen = 1195 (first_screen_name == WizardController::kAppLaunchSplashScreenName); 1196 if (show_app_launch_splash_screen) { 1197 const std::string& auto_launch_app_id = 1198 KioskAppManager::Get()->GetAutoLaunchApp(); 1199 display_host->StartAppLaunch(auto_launch_app_id, 1200 false /* diagnostic_mode */); 1201 return; 1202 } 1203 1204 // Check whether we need to execute OOBE flow. 1205 bool oobe_complete = StartupUtils::IsOobeCompleted(); 1206 policy::BrowserPolicyConnectorChromeOS* connector = 1207 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 1208 bool enrollment_screen_wanted = 1209 WizardController::ShouldRecoverEnrollment() || 1210 (WizardController::ShouldAutoStartEnrollment() && oobe_complete && 1211 !connector->IsEnterpriseManaged()); 1212 if (enrollment_screen_wanted && first_screen_name.empty()) { 1213 // Shows networks screen instead of enrollment screen to resume the 1214 // interrupted auto start enrollment flow because enrollment screen does 1215 // not handle flaky network. See http://crbug.com/332572 1216 display_host->StartWizard(WizardController::kNetworkScreenName, 1217 scoped_ptr<base::DictionaryValue>()); 1218 return; 1219 } 1220 1221 if (StartupUtils::IsEulaAccepted()) { 1222 DelayNetworkCall( 1223 ServicesCustomizationDocument::GetInstance() 1224 ->EnsureCustomizationAppliedClosure(), 1225 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)); 1226 } 1227 1228 bool show_login_screen = 1229 (first_screen_name.empty() && oobe_complete) || 1230 first_screen_name == WizardController::kLoginScreenName; 1231 1232 if (show_login_screen) { 1233 display_host->StartSignInScreen(LoginScreenContext()); 1234 return; 1235 } 1236 1237 // Load startup manifest. 1238 const StartupCustomizationDocument* startup_manifest = 1239 StartupCustomizationDocument::GetInstance(); 1240 1241 // Switch to initial locale if specified by customization 1242 // and has not been set yet. We cannot call 1243 // LanguageSwitchMenu::SwitchLanguage here before 1244 // EmitLoginPromptReady. 1245 PrefService* prefs = g_browser_process->local_state(); 1246 const std::string& current_locale = 1247 prefs->GetString(prefs::kApplicationLocale); 1248 VLOG(1) << "Current locale: " << current_locale; 1249 const std::string& locale = startup_manifest->initial_locale_default(); 1250 1251 const std::string& layout = startup_manifest->keyboard_layout(); 1252 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout; 1253 1254 // Determine keyboard layout from OEM customization (if provided) or 1255 // initial locale and save it in preferences. 1256 manager->SetInputMethodLoginDefaultFromVPD(locale, layout); 1257 1258 if (!current_locale.empty() || locale.empty()) { 1259 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host); 1260 return; 1261 } 1262 1263 // Save initial locale from VPD/customization manifest as current 1264 // Chrome locale. Otherwise it will be lost if Chrome restarts. 1265 // Don't need to schedule pref save because setting initial local 1266 // will enforce preference saving. 1267 prefs->SetString(prefs::kApplicationLocale, locale); 1268 StartupUtils::SetInitialLocale(locale); 1269 1270 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( 1271 new ShowLoginWizardSwitchLanguageCallbackData( 1272 first_screen_name, startup_manifest, display_host)); 1273 1274 scoped_ptr<locale_util::SwitchLanguageCallback> callback( 1275 new locale_util::SwitchLanguageCallback( 1276 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass())))); 1277 1278 // Load locale keyboards here. Hardware layout would be automatically enabled. 1279 locale_util::SwitchLanguage( 1280 locale, true, true /* login_layouts_only */, callback.Pass()); 1281} 1282 1283} // namespace chromeos 1284