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.
5 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
9 #include "ash/audio/sounds.h"
10 #include "ash/desktop_background/desktop_background_controller.h"
11 #include "ash/desktop_background/user_wallpaper_delegate.h"
12 #include "ash/shell.h"
13 #include "ash/shell_window_ids.h"
14 #include "base/bind.h"
15 #include "base/command_line.h"
16 #include "base/debug/trace_event.h"
17 #include "base/logging.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/browser_shutdown.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
28 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
29 #include "chrome/browser/chromeos/base/locale_util.h"
30 #include "chrome/browser/chromeos/boot_times_loader.h"
31 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
32 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
33 #include "chrome/browser/chromeos/first_run/first_run.h"
34 #include "chrome/browser/chromeos/input_method/input_method_util.h"
35 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
36 #include "chrome/browser/chromeos/language_preferences.h"
37 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
38 #include "chrome/browser/chromeos/login/existing_user_controller.h"
39 #include "chrome/browser/chromeos/login/helper.h"
40 #include "chrome/browser/chromeos/login/login_utils.h"
41 #include "chrome/browser/chromeos/login/login_wizard.h"
42 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
43 #include "chrome/browser/chromeos/login/startup_utils.h"
44 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
45 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
46 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
47 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
48 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
49 #include "chrome/browser/chromeos/login/wizard_controller.h"
50 #include "chrome/browser/chromeos/mobile_config.h"
51 #include "chrome/browser/chromeos/net/delay_network_call.h"
52 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
53 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
54 #include "chrome/browser/chromeos/system/input_device_settings.h"
55 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
56 #include "chrome/browser/lifetime/application_lifetime.h"
57 #include "chrome/browser/profiles/profile_manager.h"
58 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
59 #include "chrome/common/chrome_constants.h"
60 #include "chrome/common/chrome_switches.h"
61 #include "chrome/common/pref_names.h"
62 #include "chrome/grit/browser_resources.h"
63 #include "chromeos/audio/chromeos_sounds.h"
64 #include "chromeos/chromeos_constants.h"
65 #include "chromeos/chromeos_switches.h"
66 #include "chromeos/dbus/dbus_thread_manager.h"
67 #include "chromeos/dbus/session_manager_client.h"
68 #include "chromeos/ime/extension_ime_util.h"
69 #include "chromeos/ime/input_method_manager.h"
70 #include "chromeos/login/login_state.h"
71 #include "chromeos/settings/timezone_settings.h"
72 #include "components/session_manager/core/session_manager.h"
73 #include "components/user_manager/user_manager.h"
74 #include "content/public/browser/notification_service.h"
75 #include "content/public/browser/notification_types.h"
76 #include "content/public/browser/web_contents.h"
77 #include "content/public/browser/web_ui.h"
78 #include "media/audio/sounds/sounds_manager.h"
79 #include "ui/aura/window.h"
80 #include "ui/base/resource/resource_bundle.h"
81 #include "ui/base/ui_base_switches_util.h"
82 #include "ui/compositor/layer.h"
83 #include "ui/compositor/layer_animation_observer.h"
84 #include "ui/compositor/scoped_layer_animation_settings.h"
85 #include "ui/events/event_utils.h"
86 #include "ui/gfx/display.h"
87 #include "ui/gfx/rect.h"
88 #include "ui/gfx/screen.h"
89 #include "ui/gfx/size.h"
90 #include "ui/gfx/transform.h"
91 #include "ui/keyboard/keyboard_controller.h"
92 #include "ui/keyboard/keyboard_util.h"
93 #include "ui/views/focus/focus_manager.h"
94 #include "ui/views/widget/widget.h"
95 #include "ui/views/widget/widget_delegate.h"
96 #include "ui/wm/core/window_animations.h"
99 #if defined(USE_ATHENA)
100 #include "athena/screen/public/screen_manager.h"
101 #include "athena/util/container_priorities.h"
106 // Maximum delay for startup sound after 'loginPromptVisible' signal.
107 const int kStartupSoundMaxDelayMs = 2000;
109 // URL which corresponds to the login WebUI.
110 const char kLoginURL[] = "chrome://oobe/login";
112 // URL which corresponds to the OOBE WebUI.
113 const char kOobeURL[] = "chrome://oobe/oobe";
115 // URL which corresponds to the user adding WebUI.
116 const char kUserAddingURL[] = "chrome://oobe/user-adding";
118 // URL which corresponds to the app launch splash WebUI.
119 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
121 // Duration of sign-in transition animation.
122 const int kLoginFadeoutTransitionDurationMs = 700;
124 // Number of times we try to reload OOBE/login WebUI if it crashes.
125 const int kCrashCountLimit = 5;
127 // Whether to enable tnitializing WebUI in hidden state (see
128 // |initialize_webui_hidden_|) by default.
129 const bool kHiddenWebUIInitializationDefault = true;
131 // Switch values that might be used to override WebUI init type.
132 const char kWebUIInitParallel[] = "parallel";
133 const char kWebUIInitPostpone[] = "postpone";
135 // The delay of triggering initialization of the device policy subsystem
136 // after the login screen is initialized. This makes sure that device policy
137 // network requests are made while the system is idle waiting for user input.
138 const int64 kPolicyServiceInitializationDelayMilliseconds = 100;
140 // A class to observe an implicit animation and invokes the callback after the
141 // animation is completed.
142 class AnimationObserver : public ui::ImplicitAnimationObserver {
144 explicit AnimationObserver(const base::Closure& callback)
145 : callback_(callback) {}
146 virtual ~AnimationObserver() {}
149 // ui::ImplicitAnimationObserver implementation:
150 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
155 base::Closure callback_;
157 DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
160 // ShowLoginWizard is split into two parts. This function is sometimes called
161 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback()
162 // (if locale was updated).
163 void ShowLoginWizardFinish(
164 const std::string& first_screen_name,
165 const chromeos::StartupCustomizationDocument* startup_manifest,
166 chromeos::LoginDisplayHost* display_host) {
167 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish");
169 scoped_ptr<base::DictionaryValue> params;
170 display_host->StartWizard(first_screen_name, params.Pass());
172 // Set initial timezone if specified by customization.
173 const std::string timezone_name = startup_manifest->initial_timezone();
174 VLOG(1) << "Initial time zone: " << timezone_name;
175 // Apply locale customizations only once to preserve whatever locale
176 // user has changed to during OOBE.
177 if (!timezone_name.empty()) {
178 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
179 base::UTF8ToUTF16(timezone_name));
183 struct ShowLoginWizardSwitchLanguageCallbackData {
184 explicit ShowLoginWizardSwitchLanguageCallbackData(
185 const std::string& first_screen_name,
186 const chromeos::StartupCustomizationDocument* startup_manifest,
187 chromeos::LoginDisplayHost* display_host)
188 : first_screen_name(first_screen_name),
189 startup_manifest(startup_manifest),
190 display_host(display_host) {}
192 const std::string first_screen_name;
193 const chromeos::StartupCustomizationDocument* const startup_manifest;
194 chromeos::LoginDisplayHost* const display_host;
196 // lock UI while resource bundle is being reloaded.
197 chromeos::InputEventsBlocker events_blocker;
200 void OnLanguageSwitchedCallback(
201 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
202 const std::string& locale,
203 const std::string& loaded_locale,
204 const bool success) {
206 LOG(WARNING) << "Locale could not be found for '" << locale << "'";
208 ShowLoginWizardFinish(
209 self->first_screen_name, self->startup_manifest, self->display_host);
212 void EnableSystemSoundsForAccessibility() {
213 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
216 // A login implementation of WidgetDelegate.
217 class LoginWidgetDelegate : public views::WidgetDelegate {
219 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
221 virtual ~LoginWidgetDelegate() {}
223 // Overridden from WidgetDelegate:
224 virtual void DeleteDelegate() OVERRIDE {
227 virtual views::Widget* GetWidget() OVERRIDE {
230 virtual const views::Widget* GetWidget() const OVERRIDE {
233 virtual bool CanActivate() const OVERRIDE {
236 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
241 views::Widget* widget_;
243 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
246 // Disables virtual keyboard overscroll. Login UI will scroll user pods
247 // into view on JS side when virtual keyboard is shown.
248 void DisableKeyboardOverscroll() {
249 keyboard::SetKeyboardOverscrollOverride(
250 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
253 void ResetKeyboardOverscrollOverride() {
254 keyboard::SetKeyboardOverscrollOverride(
255 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
263 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
266 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
268 ////////////////////////////////////////////////////////////////////////////////
269 // LoginDisplayHostImpl, public
271 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
272 : background_bounds_(background_bounds),
273 pointer_factory_(this),
274 shutting_down_(false),
275 oobe_progress_bar_visible_(false),
276 session_starting_(false),
279 webui_login_display_(NULL),
280 is_showing_login_(false),
281 is_wallpaper_loaded_(false),
282 status_area_saved_visibility_(false),
284 restore_path_(RESTORE_UNKNOWN),
285 finalize_animation_type_(ANIMATION_WORKSPACE),
286 startup_sound_played_(false),
287 startup_sound_honors_spoken_feedback_(false),
288 is_observing_keyboard_(false),
289 animation_weak_ptr_factory_(this) {
290 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
291 CrasAudioHandler::Get()->AddAudioObserver(this);
292 if (keyboard::KeyboardController::GetInstance()) {
293 keyboard::KeyboardController::GetInstance()->AddObserver(this);
294 is_observing_keyboard_ = true;
297 #if !defined(USE_ATHENA)
298 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
299 ash::Shell::GetScreen()->AddObserver(this);
302 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
303 // because/ APP_TERMINATING will never be fired as long as this keeps
304 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
305 // browser instance that will block the shutdown.
307 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
308 content::NotificationService::AllSources());
310 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
311 // not shown yet. Lock window has to be closed at this point so that
312 // a browser window exists and the window can acquire input focus.
314 chrome::NOTIFICATION_BROWSER_OPENED,
315 content::NotificationService::AllSources());
317 // Login screen is moved to lock screen container when user logs in.
319 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
320 content::NotificationService::AllSources());
322 DCHECK(default_host_ == NULL);
323 default_host_ = this;
325 // Make sure chrome won't exit while we are at login/oobe screen.
326 chrome::IncrementKeepAliveCount();
328 bool is_registered = StartupUtils::IsDeviceRegistered();
329 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
330 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch(
331 switches::kDisableBootAnimation);
333 waiting_for_wallpaper_load_ = !zero_delay_enabled &&
334 (!is_registered || !disable_boot_animation);
336 #if defined(USE_ATHENA)
337 // TODO(dpolukhin): remove #ifdef when Athena supports wallpaper manager.
339 waiting_for_wallpaper_load_ = false;
342 // For slower hardware we have boot animation disabled so
343 // we'll be initializing WebUI hidden, waiting for user pods to load and then
344 // show WebUI at once.
345 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_;
347 initialize_webui_hidden_ =
348 kHiddenWebUIInitializationDefault && !zero_delay_enabled;
350 // Check if WebUI init type is overriden.
351 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) {
352 const std::string override_type =
353 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
354 switches::kAshWebUIInit);
355 if (override_type == kWebUIInitParallel)
356 initialize_webui_hidden_ = true;
357 else if (override_type == kWebUIInitPostpone)
358 initialize_webui_hidden_ = false;
361 // Always postpone WebUI initialization on first boot, otherwise we miss
362 // initial animation.
363 if (!StartupUtils::IsOobeCompleted())
364 initialize_webui_hidden_ = false;
366 // There is no wallpaper for KioskMode, don't initialize the webui hidden.
367 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
368 initialize_webui_hidden_ = false;
370 if (waiting_for_wallpaper_load_) {
372 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
373 content::NotificationService::AllSources());
376 // When we wait for WebUI to be initialized we wait for one of
377 // these notifications.
378 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
379 initialize_webui_hidden_) {
381 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
382 content::NotificationService::AllSources());
384 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
385 content::NotificationService::AllSources());
387 VLOG(1) << "Login WebUI >> "
388 << "zero_delay: " << zero_delay_enabled
389 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
390 << " wait_for_pods_: " << waiting_for_user_pods_
391 << " init_webui_hidden_: " << initialize_webui_hidden_;
393 media::SoundsManager* manager = media::SoundsManager::Get();
394 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
395 manager->Initialize(chromeos::SOUND_STARTUP,
396 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
399 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
400 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
401 CrasAudioHandler::Get()->RemoveAudioObserver(this);
402 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
403 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
404 is_observing_keyboard_ = false;
407 #if !defined(USE_ATHENA)
408 ash::Shell::GetInstance()->delegate()->
409 RemoveVirtualKeyboardStateObserver(this);
410 ash::Shell::GetScreen()->RemoveObserver(this);
413 if (login_view_ && login_window_)
414 login_window_->RemoveRemovalsObserver(this);
416 if (login::LoginScrollIntoViewEnabled())
417 ResetKeyboardOverscrollOverride();
419 views::FocusManager::set_arrow_key_traversal_enabled(false);
420 ResetLoginWindowAndView();
422 // Let chrome process exit after login/oobe screen if needed.
423 chrome::DecrementKeepAliveCount();
425 default_host_ = NULL;
426 // TODO(tengs): This should be refactored. See crbug.com/314934.
427 if (user_manager::UserManager::Get()->IsCurrentUserNew()) {
428 // DriveOptInController will delete itself when finished.
429 (new DriveFirstRunController(
430 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
434 ////////////////////////////////////////////////////////////////////////////////
435 // LoginDisplayHostImpl, LoginDisplayHost implementation:
437 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
438 LoginDisplay::Delegate* delegate) {
439 webui_login_display_ = new WebUILoginDisplay(delegate);
440 webui_login_display_->set_background_bounds(background_bounds());
441 return webui_login_display_;
444 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
445 return login_window_ ? login_window_->GetNativeWindow() : NULL;
448 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
452 void LoginDisplayHostImpl::BeforeSessionStart() {
453 session_starting_ = true;
456 void LoginDisplayHostImpl::Finalize() {
457 DVLOG(1) << "Session starting";
458 if (ash::Shell::HasInstance()) {
459 ash::Shell::GetInstance()->
460 desktop_background_controller()->MoveDesktopToUnlockedContainer();
462 if (wizard_controller_.get())
463 wizard_controller_->OnSessionStart();
465 switch (finalize_animation_type_) {
467 ShutdownDisplayHost(false);
469 case ANIMATION_WORKSPACE:
470 if (ash::Shell::HasInstance())
471 ScheduleWorkspaceAnimation();
473 ShutdownDisplayHost(false);
475 case ANIMATION_FADE_OUT:
476 // Display host is deleted once animation is completed
477 // since sign in screen widget has to stay alive.
478 ScheduleFadeOutAnimation();
483 void LoginDisplayHostImpl::OnCompleteLogin() {
484 if (auto_enrollment_controller_)
485 auto_enrollment_controller_->Cancel();
488 void LoginDisplayHostImpl::OpenProxySettings() {
490 login_view_->OpenProxySettings();
493 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
494 if (initialize_webui_hidden_)
495 status_area_saved_visibility_ = visible;
496 else if (login_view_)
497 login_view_->SetStatusAreaVisible(visible);
500 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
501 if (!auto_enrollment_controller_) {
502 auto_enrollment_controller_.reset(new AutoEnrollmentController());
503 auto_enrollment_progress_subscription_ =
504 auto_enrollment_controller_->RegisterProgressCallback(
505 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress,
506 base::Unretained(this)));
508 return auto_enrollment_controller_.get();
511 void LoginDisplayHostImpl::StartWizard(
512 const std::string& first_screen_name,
513 scoped_ptr<base::DictionaryValue> screen_parameters) {
514 if (login::LoginScrollIntoViewEnabled())
515 DisableKeyboardOverscroll();
517 startup_sound_honors_spoken_feedback_ = false;
518 TryToPlayStartupSound();
520 // Keep parameters to restore if renderer crashes.
521 restore_path_ = RESTORE_WIZARD;
522 wizard_first_screen_name_ = first_screen_name;
523 if (screen_parameters.get())
524 wizard_screen_parameters_.reset(screen_parameters->DeepCopy());
526 wizard_screen_parameters_.reset();
527 is_showing_login_ = false;
529 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
530 VLOG(1) << "Login WebUI >> wizard postponed";
533 VLOG(1) << "Login WebUI >> wizard";
536 LoadURL(GURL(kOobeURL));
538 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
539 // Create and show the wizard.
540 // Note, dtor of the old WizardController should be called before ctor of the
541 // new one, because "default_controller()" is updated there. So pure "reset()"
542 // is done before new controller creation.
543 wizard_controller_.reset();
544 wizard_controller_.reset(CreateWizardController());
546 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
547 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
548 wizard_controller_->Init(first_screen_name, screen_parameters.Pass());
551 WizardController* LoginDisplayHostImpl::GetWizardController() {
552 return wizard_controller_.get();
555 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
556 return app_launch_controller_.get();
559 void LoginDisplayHostImpl::StartUserAdding(
560 const base::Closure& completion_callback) {
561 if (login::LoginScrollIntoViewEnabled())
562 DisableKeyboardOverscroll();
564 restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
565 completion_callback_ = completion_callback;
566 finalize_animation_type_ = ANIMATION_NONE;
567 VLOG(1) << "Login WebUI >> user adding";
569 LoadURL(GURL(kUserAddingURL));
570 // We should emit this signal only at login screen (after reboot or sign out).
571 login_view_->set_should_emit_login_prompt_visible(false);
573 // Lock container can be transparent after lock screen animation.
574 aura::Window* lock_container = ash::Shell::GetContainer(
575 ash::Shell::GetPrimaryRootWindow(),
576 ash::kShellWindowId_LockScreenContainersContainer);
577 lock_container->layer()->SetOpacity(1.0);
579 ash::Shell::GetInstance()->
580 desktop_background_controller()->MoveDesktopToLockedContainer();
582 sign_in_controller_.reset(); // Only one controller in a time.
583 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
584 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
585 SetStatusAreaVisible(true);
586 sign_in_controller_->Init(
587 user_manager::UserManager::Get()->GetUsersAdmittedForMultiProfile());
588 CHECK(webui_login_display_);
589 GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
590 webui_login_display_,
591 webui_login_display_);
594 void LoginDisplayHostImpl::StartSignInScreen(
595 const LoginScreenContext& context) {
596 if (login::LoginScrollIntoViewEnabled())
597 DisableKeyboardOverscroll();
599 startup_sound_honors_spoken_feedback_ = true;
600 TryToPlayStartupSound();
602 restore_path_ = RESTORE_SIGN_IN;
603 is_showing_login_ = true;
604 finalize_animation_type_ = ANIMATION_WORKSPACE;
606 PrewarmAuthentication();
608 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
609 VLOG(1) << "Login WebUI >> sign in postponed";
612 VLOG(1) << "Login WebUI >> sign in";
614 if (!login_window_) {
615 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
616 TRACE_EVENT_ASYNC_STEP_INTO0(
617 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
618 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen");
619 LoadURL(GURL(kLoginURL));
622 DVLOG(1) << "Starting sign in screen";
623 const user_manager::UserList& users =
624 user_manager::UserManager::Get()->GetUsers();
626 // Fix for users who updated device and thus never passed register screen.
627 // If we already have users, we assume that it is not a second part of
628 // OOBE. See http://crosbug.com/6289
629 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
630 VLOG(1) << "Mark device registered because there are remembered users: "
632 StartupUtils::MarkDeviceRegistered(base::Closure());
635 sign_in_controller_.reset(); // Only one controller in a time.
636 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
637 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
638 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
639 SetStatusAreaVisible(true);
640 sign_in_controller_->Init(users);
642 // We might be here after a reboot that was triggered after OOBE was complete,
643 // so check for auto-enrollment again. This might catch a cached decision from
644 // a previous oobe flow, or might start a new check with the server.
645 if (GetAutoEnrollmentController()->ShouldEnrollSilently())
646 sign_in_controller_->DoAutoEnrollment();
648 GetAutoEnrollmentController()->Start();
650 // Initiate mobile config load.
651 MobileConfig::GetInstance();
653 // Initiate device policy fetching.
654 policy::BrowserPolicyConnectorChromeOS* connector =
655 g_browser_process->platform_part()->browser_policy_connector_chromeos();
656 connector->ScheduleServiceInitialization(
657 kPolicyServiceInitializationDelayMilliseconds);
659 CHECK(webui_login_display_);
660 GetOobeUI()->ShowSigninScreen(context,
661 webui_login_display_,
662 webui_login_display_);
663 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
664 SetStatusAreaVisible(false);
665 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
668 "WaitForScreenStateInitialize");
669 BootTimesLoader::Get()->RecordCurrentStats(
670 "login-wait-for-signin-state-initialize");
673 void LoginDisplayHostImpl::ResumeSignInScreen() {
674 // We only get here after a previous call the StartSignInScreen. That sign-in
675 // was successful but was interrupted by an auto-enrollment execution; once
676 // auto-enrollment is complete we resume the normal login flow from here.
677 DVLOG(1) << "Resuming sign in screen";
678 CHECK(sign_in_controller_.get());
679 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
680 SetStatusAreaVisible(true);
681 sign_in_controller_->ResumeLogin();
685 void LoginDisplayHostImpl::OnPreferencesChanged() {
686 if (is_showing_login_)
687 webui_login_display_->OnPreferencesChanged();
690 void LoginDisplayHostImpl::PrewarmAuthentication() {
691 auth_prewarmer_.reset(new AuthPrewarmer());
692 auth_prewarmer_->PrewarmAuthentication(
693 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
694 pointer_factory_.GetWeakPtr()));
697 void LoginDisplayHostImpl::StartDemoAppLaunch() {
698 VLOG(1) << "Login WebUI >> starting demo app.";
699 SetStatusAreaVisible(false);
701 demo_app_launcher_.reset(new DemoAppLauncher());
702 demo_app_launcher_->StartDemoAppLaunch();
705 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
706 bool diagnostic_mode) {
707 VLOG(1) << "Login WebUI >> start app launch.";
708 SetStatusAreaVisible(false);
709 finalize_animation_type_ = ANIMATION_FADE_OUT;
711 LoadURL(GURL(kAppLaunchSplashURL));
713 login_view_->set_should_emit_login_prompt_visible(false);
715 app_launch_controller_.reset(new AppLaunchController(
716 app_id, diagnostic_mode, this, GetOobeUI()));
718 app_launch_controller_->StartAppLaunch();
721 ////////////////////////////////////////////////////////////////////////////////
722 // LoginDisplayHostImpl, public
724 WizardController* LoginDisplayHostImpl::CreateWizardController() {
725 // TODO(altimofeev): ensure that WebUI is ready.
726 OobeDisplay* oobe_display = GetOobeUI();
727 return new WizardController(this, oobe_display);
730 void LoginDisplayHostImpl::OnBrowserCreated() {
731 // Close lock window now so that the launched browser can receive focus.
732 ResetLoginWindowAndView();
735 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
738 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
741 ////////////////////////////////////////////////////////////////////////////////
742 // LoginDisplayHostImpl, content:NotificationObserver implementation:
744 void LoginDisplayHostImpl::Observe(
746 const content::NotificationSource& source,
747 const content::NotificationDetails& details) {
748 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
749 VLOG(1) << "Login WebUI >> wp animation done";
750 is_wallpaper_loaded_ = true;
751 ash::Shell::GetInstance()->user_wallpaper_delegate()
752 ->OnWallpaperBootAnimationFinished();
753 if (waiting_for_wallpaper_load_) {
754 // StartWizard / StartSignInScreen could be called multiple times through
755 // the lifetime of host.
756 // Make sure that subsequent calls are not postponed.
757 waiting_for_wallpaper_load_ = false;
758 if (initialize_webui_hidden_)
761 StartPostponedWebUI();
763 registrar_.Remove(this,
764 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
765 content::NotificationService::AllSources());
766 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
767 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
768 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE";
769 if (waiting_for_user_pods_ && initialize_webui_hidden_) {
770 waiting_for_user_pods_ = false;
772 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
773 // Reduce time till login UI is shown - show it as soon as possible.
774 waiting_for_wallpaper_load_ = false;
777 registrar_.Remove(this,
778 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
779 content::NotificationService::AllSources());
780 registrar_.Remove(this,
781 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
782 content::NotificationService::AllSources());
783 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
784 ShutdownDisplayHost(true);
785 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
786 // Browsers created before session start (windows opened by extensions, for
787 // example) are ignored.
789 registrar_.Remove(this,
790 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
791 content::NotificationService::AllSources());
792 registrar_.Remove(this,
793 chrome::NOTIFICATION_BROWSER_OPENED,
794 content::NotificationService::AllSources());
795 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
796 user_manager::UserManager::Get()->IsCurrentUserNew()) {
797 #if !defined(USE_ATHENA)
798 // For new user, move desktop to locker container so that windows created
799 // during the user image picker step are below it.
800 ash::Shell::GetInstance()->
801 desktop_background_controller()->MoveDesktopToLockedContainer();
803 registrar_.Remove(this,
804 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
805 content::NotificationService::AllSources());
809 ////////////////////////////////////////////////////////////////////////////////
810 // LoginDisplayHostImpl, WebContentsObserver implementation:
812 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
813 // Do not try to restore on shutdown
814 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
818 if (crash_count_ > kCrashCountLimit)
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";
830 ////////////////////////////////////////////////////////////////////////////////
831 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
834 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
835 OnLoginPromptVisible();
838 ////////////////////////////////////////////////////////////////////////////////
839 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
842 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
843 TryToPlayStartupSound();
846 ////////////////////////////////////////////////////////////////////////////////
847 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
850 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
851 if (keyboard::KeyboardController::GetInstance()) {
853 if (!is_observing_keyboard_) {
854 keyboard::KeyboardController::GetInstance()->AddObserver(this);
855 is_observing_keyboard_ = true;
858 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
859 is_observing_keyboard_ = false;
864 ////////////////////////////////////////////////////////////////////////////////
865 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
868 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
869 const gfx::Rect& new_bounds) {
870 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
871 // Keyboard has been hidden.
873 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
874 if (login::LoginScrollIntoViewEnabled())
875 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds);
877 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
878 // Keyboard has been shown.
880 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
881 if (login::LoginScrollIntoViewEnabled())
882 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds);
886 keyboard_bounds_ = new_bounds;
889 ////////////////////////////////////////////////////////////////////////////////
890 // LoginDisplayHostImpl, gfx::DisplayObserver implementation:
892 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) {
895 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) {
898 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display,
899 uint32_t changed_metrics) {
900 if (display.id() != ash::Shell::GetScreen()->GetPrimaryDisplay().id() ||
901 !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
906 const gfx::Size& size = ash::Shell::GetScreen()->GetPrimaryDisplay().size();
907 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(),
912 ////////////////////////////////////////////////////////////////////////////////
913 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation:
914 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget,
916 if (view != static_cast<views::View*>(login_view_))
919 widget->RemoveRemovalsObserver(this);
922 ////////////////////////////////////////////////////////////////////////////////
923 // LoginDisplayHostImpl, private
925 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
929 shutting_down_ = true;
930 registrar_.RemoveAll();
931 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
933 base::MessageLoop::current()->Quit();
935 if (!completion_callback_.is_null())
936 completion_callback_.Run();
939 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
940 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
941 ash::kShellWindowId_DesktopBackgroundContainer)
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.
949 if (!CommandLine::ForCurrentProcess()->HasSwitch(
950 switches::kDisableLoginAnimations))
951 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
954 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
955 ui::Layer* layer = login_window_->GetLayer();
956 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
957 animation.AddObserver(new AnimationObserver(
958 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
959 animation_weak_ptr_factory_.GetWeakPtr(),
961 layer->SetOpacity(0);
964 void LoginDisplayHostImpl::OnAutoEnrollmentProgress(
965 policy::AutoEnrollmentState state) {
966 VLOG(1) << "OnAutoEnrollmentProgress, state " << state;
968 if (sign_in_controller_ &&
969 auto_enrollment_controller_->ShouldEnrollSilently()) {
970 sign_in_controller_->DoAutoEnrollment();
974 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
975 InitLoginWindowAndView();
976 // Subscribe to crash events.
977 content::WebContentsObserver::Observe(login_view_->GetWebContents());
978 login_view_->LoadURL(url);
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
983 // See crbug.com/328538.
984 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
987 void LoginDisplayHostImpl::ShowWebUI() {
988 if (!login_window_ || !login_view_) {
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();
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();
1006 // We should reset this flag to allow changing of status area visibility.
1007 initialize_webui_hidden_ = false;
1010 void LoginDisplayHostImpl::StartPostponedWebUI() {
1011 if (!is_wallpaper_loaded_) {
1015 VLOG(1) << "Login WebUI >> Init postponed WebUI";
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) {
1025 switch (restore_path_) {
1026 case RESTORE_WIZARD:
1027 StartWizard(wizard_first_screen_name_,
1028 wizard_screen_parameters_.Pass());
1030 case RESTORE_SIGN_IN:
1031 StartSignInScreen(LoginScreenContext());
1033 case RESTORE_ADD_USER_INTO_SESSION:
1034 StartUserAdding(completion_callback_);
1042 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1046 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1047 views::FocusManager::set_arrow_key_traversal_enabled(true);
1048 #if !defined(USE_ATHENA)
1050 focus_ring_controller_.reset(new FocusRingController);
1051 focus_ring_controller_->SetVisible(true);
1054 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1057 views::Widget::InitParams params(
1058 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1059 params.bounds = background_bounds();
1060 params.show_state = ui::SHOW_STATE_FULLSCREEN;
1061 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1062 #if defined(USE_ATHENA)
1063 athena::ScreenManager::ContainerParams container_params(
1064 "LoginScreen", athena::CP_LOGIN_SCREEN);
1065 container_params.can_activate_children = true;
1066 login_screen_container_.reset(
1067 athena::ScreenManager::Get()->CreateContainer(container_params));
1068 params.parent = login_screen_container_.get();
1071 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1072 ash::kShellWindowId_LockScreenContainer);
1074 login_window_ = new views::Widget;
1075 params.delegate = new LoginWidgetDelegate(login_window_);
1076 login_window_->Init(params);
1078 login_view_ = new WebUILoginView();
1079 login_view_->Init();
1080 if (login_view_->webui_visible())
1081 OnLoginPromptVisible();
1083 wm::SetWindowVisibilityAnimationDuration(
1084 login_window_->GetNativeView(),
1085 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1086 wm::SetWindowVisibilityAnimationTransition(
1087 login_window_->GetNativeView(),
1090 login_window_->AddRemovalsObserver(this);
1091 login_window_->SetContentsView(login_view_);
1093 // If WebUI is initialized in hidden state, show it only if we're no
1094 // longer waiting for wallpaper animation/user images loading. Otherwise,
1096 if (!initialize_webui_hidden_ ||
1097 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1098 VLOG(1) << "Login WebUI >> show login wnd on create";
1099 login_window_->Show();
1101 VLOG(1) << "Login WebUI >> login wnd is hidden on create";
1102 login_view_->set_is_hidden(true);
1104 login_window_->GetNativeView()->SetName("WebUILoginView");
1107 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1110 login_window_->Close();
1111 login_window_ = NULL;
1115 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1116 auth_prewarmer_.reset();
1119 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1120 GetOobeUI()->ShowOobeUI(visible);
1123 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1124 if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1125 !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) {
1129 startup_sound_played_ = true;
1131 // Don't try play startup sound if login prompt is already visible
1132 // for a long time or can't be played.
1133 if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1134 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1135 EnableSystemSoundsForAccessibility();
1139 if (!startup_sound_honors_spoken_feedback_ &&
1140 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1141 EnableSystemSoundsForAccessibility();
1145 #if !defined(USE_ATHENA)
1147 if (startup_sound_honors_spoken_feedback_ &&
1148 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1149 EnableSystemSoundsForAccessibility();
1154 base::MessageLoop::current()->PostDelayedTask(
1156 base::Bind(&EnableSystemSoundsForAccessibility),
1157 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1160 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1161 if (!login_prompt_visible_time_.is_null())
1163 login_prompt_visible_time_ = base::TimeTicks::Now();
1164 TryToPlayStartupSound();
1167 ////////////////////////////////////////////////////////////////////////////////
1170 // Declared in login_wizard.h so that others don't need to depend on our .h.
1171 // TODO(nkostylev): Split this into a smaller functions.
1172 void ShowLoginWizard(const std::string& first_screen_name) {
1173 if (browser_shutdown::IsTryingToQuit())
1176 VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1178 #if !defined(USE_ATHENA)
1179 // TODO(dpolukhin): crbug.com/407579
1180 chromeos::input_method::InputMethodManager* manager =
1181 chromeos::input_method::InputMethodManager::Get();
1183 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1184 // and US dvorak keyboard layouts.
1185 if (g_browser_process && g_browser_process->local_state()) {
1186 manager->GetActiveIMEState()->SetInputMethodLoginDefault();
1188 PrefService* prefs = g_browser_process->local_state();
1189 // Apply owner preferences for tap-to-click and mouse buttons swap for
1191 system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1192 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1193 system::InputDeviceSettings::Get()->SetTapToClick(
1194 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1196 system::InputDeviceSettings::Get()->SetNaturalScroll(
1197 CommandLine::ForCurrentProcess()->HasSwitch(
1198 switches::kNaturalScrollDefault));
1201 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1203 g_browser_process->platform_part()->SessionManager()->SetSessionState(
1204 StartupUtils::IsOobeCompleted()
1205 ? session_manager::SESSION_STATE_LOGIN_PRIMARY
1206 : session_manager::SESSION_STATE_OOBE);
1208 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds);
1210 bool show_app_launch_splash_screen =
1211 (first_screen_name == WizardController::kAppLaunchSplashScreenName);
1212 if (show_app_launch_splash_screen) {
1213 const std::string& auto_launch_app_id =
1214 KioskAppManager::Get()->GetAutoLaunchApp();
1215 display_host->StartAppLaunch(auto_launch_app_id,
1216 false /* diagnostic_mode */);
1220 // Check whether we need to execute OOBE flow.
1221 bool oobe_complete = StartupUtils::IsOobeCompleted();
1222 policy::BrowserPolicyConnectorChromeOS* connector =
1223 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1224 bool enrollment_screen_wanted =
1225 WizardController::ShouldRecoverEnrollment() ||
1226 (WizardController::ShouldAutoStartEnrollment() && oobe_complete &&
1227 !connector->IsEnterpriseManaged());
1228 if (enrollment_screen_wanted && first_screen_name.empty()) {
1229 // Shows networks screen instead of enrollment screen to resume the
1230 // interrupted auto start enrollment flow because enrollment screen does
1231 // not handle flaky network. See http://crbug.com/332572
1232 display_host->StartWizard(WizardController::kNetworkScreenName,
1233 scoped_ptr<base::DictionaryValue>());
1237 if (StartupUtils::IsEulaAccepted()) {
1239 ServicesCustomizationDocument::GetInstance()
1240 ->EnsureCustomizationAppliedClosure(),
1241 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS));
1244 bool show_login_screen =
1245 (first_screen_name.empty() && oobe_complete) ||
1246 first_screen_name == WizardController::kLoginScreenName;
1248 if (show_login_screen) {
1249 display_host->StartSignInScreen(LoginScreenContext());
1253 // Load startup manifest.
1254 const StartupCustomizationDocument* startup_manifest =
1255 StartupCustomizationDocument::GetInstance();
1257 // Switch to initial locale if specified by customization
1258 // and has not been set yet. We cannot call
1259 // LanguageSwitchMenu::SwitchLanguage here before
1260 // EmitLoginPromptReady.
1261 PrefService* prefs = g_browser_process->local_state();
1262 const std::string& current_locale =
1263 prefs->GetString(prefs::kApplicationLocale);
1264 VLOG(1) << "Current locale: " << current_locale;
1265 const std::string& locale = startup_manifest->initial_locale_default();
1267 const std::string& layout = startup_manifest->keyboard_layout();
1268 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1270 #if !defined(USE_ATHENA)
1271 // Determine keyboard layout from OEM customization (if provided) or
1272 // initial locale and save it in preferences.
1273 manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale,
1277 if (!current_locale.empty() || locale.empty()) {
1278 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1282 // Save initial locale from VPD/customization manifest as current
1283 // Chrome locale. Otherwise it will be lost if Chrome restarts.
1284 // Don't need to schedule pref save because setting initial local
1285 // will enforce preference saving.
1286 prefs->SetString(prefs::kApplicationLocale, locale);
1287 StartupUtils::SetInitialLocale(locale);
1289 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1290 new ShowLoginWizardSwitchLanguageCallbackData(
1291 first_screen_name, startup_manifest, display_host));
1293 scoped_ptr<locale_util::SwitchLanguageCallback> callback(
1294 new locale_util::SwitchLanguageCallback(
1295 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass()))));
1297 // Load locale keyboards here. Hardware layout would be automatically enabled.
1298 locale_util::SwitchLanguage(
1299 locale, true, true /* login_layouts_only */, callback.Pass());
1302 } // namespace chromeos