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