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"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/browser_shutdown.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
23 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
24 #include "chrome/browser/chromeos/base/locale_util.h"
25 #include "chrome/browser/chromeos/boot_times_loader.h"
26 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
27 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
28 #include "chrome/browser/chromeos/first_run/first_run.h"
29 #include "chrome/browser/chromeos/input_method/input_method_util.h"
30 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
31 #include "chrome/browser/chromeos/language_preferences.h"
32 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
33 #include "chrome/browser/chromeos/login/existing_user_controller.h"
34 #include "chrome/browser/chromeos/login/helper.h"
35 #include "chrome/browser/chromeos/login/login_utils.h"
36 #include "chrome/browser/chromeos/login/login_wizard.h"
37 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
38 #include "chrome/browser/chromeos/login/startup_utils.h"
39 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
40 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
41 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
42 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
43 #include "chrome/browser/chromeos/login/wizard_controller.h"
44 #include "chrome/browser/chromeos/mobile_config.h"
45 #include "chrome/browser/chromeos/net/delay_network_call.h"
46 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
47 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
48 #include "chrome/browser/chromeos/system/input_device_settings.h"
49 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
50 #include "chrome/browser/lifetime/application_lifetime.h"
51 #include "chrome/browser/profiles/profile_manager.h"
52 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
53 #include "chrome/common/chrome_constants.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/pref_names.h"
56 #include "chrome/grit/browser_resources.h"
57 #include "chromeos/audio/chromeos_sounds.h"
58 #include "chromeos/chromeos_constants.h"
59 #include "chromeos/chromeos_switches.h"
60 #include "chromeos/dbus/dbus_thread_manager.h"
61 #include "chromeos/dbus/session_manager_client.h"
62 #include "chromeos/ime/extension_ime_util.h"
63 #include "chromeos/ime/input_method_manager.h"
64 #include "chromeos/login/login_state.h"
65 #include "chromeos/settings/timezone_settings.h"
66 #include "components/session_manager/core/session_manager.h"
67 #include "components/user_manager/user_manager.h"
68 #include "content/public/browser/notification_service.h"
69 #include "content/public/browser/notification_types.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_ui.h"
72 #include "media/audio/sounds/sounds_manager.h"
73 #include "ui/aura/window.h"
74 #include "ui/base/resource/resource_bundle.h"
75 #include "ui/base/ui_base_switches_util.h"
76 #include "ui/compositor/layer.h"
77 #include "ui/compositor/layer_animation_observer.h"
78 #include "ui/compositor/scoped_layer_animation_settings.h"
79 #include "ui/events/event_utils.h"
80 #include "ui/gfx/display.h"
81 #include "ui/gfx/rect.h"
82 #include "ui/gfx/screen.h"
83 #include "ui/gfx/size.h"
84 #include "ui/gfx/transform.h"
85 #include "ui/keyboard/keyboard_controller.h"
86 #include "ui/keyboard/keyboard_util.h"
87 #include "ui/views/focus/focus_manager.h"
88 #include "ui/views/widget/widget.h"
89 #include "ui/views/widget/widget_delegate.h"
92 #if !defined(USE_ATHENA)
93 #include "ash/audio/sounds.h"
94 #include "ash/desktop_background/desktop_background_controller.h"
95 #include "ash/desktop_background/user_wallpaper_delegate.h"
96 #include "ash/shell.h"
97 #include "ash/shell_window_ids.h"
98 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
101 #if defined(USE_ATHENA)
102 #include "athena/screen/public/screen_manager.h"
103 #include "athena/util/container_priorities.h"
104 #include "athena/util/fill_layout_manager.h"
109 // Maximum delay for startup sound after 'loginPromptVisible' signal.
110 const int kStartupSoundMaxDelayMs = 2000;
112 // URL which corresponds to the login WebUI.
113 const char kLoginURL[] = "chrome://oobe/login";
115 // URL which corresponds to the OOBE WebUI.
116 const char kOobeURL[] = "chrome://oobe/oobe";
118 // URL which corresponds to the user adding WebUI.
119 const char kUserAddingURL[] = "chrome://oobe/user-adding";
121 // URL which corresponds to the app launch splash WebUI.
122 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
124 // Duration of sign-in transition animation.
125 const int kLoginFadeoutTransitionDurationMs = 700;
127 // Number of times we try to reload OOBE/login WebUI if it crashes.
128 const int kCrashCountLimit = 5;
130 // Whether to enable tnitializing WebUI in hidden state (see
131 // |initialize_webui_hidden_|) by default.
132 const bool kHiddenWebUIInitializationDefault = true;
134 // Switch values that might be used to override WebUI init type.
135 const char kWebUIInitParallel[] = "parallel";
136 const char kWebUIInitPostpone[] = "postpone";
138 // The delay of triggering initialization of the device policy subsystem
139 // after the login screen is initialized. This makes sure that device policy
140 // network requests are made while the system is idle waiting for user input.
141 const int64 kPolicyServiceInitializationDelayMilliseconds = 100;
143 // A class to observe an implicit animation and invokes the callback after the
144 // animation is completed.
145 class AnimationObserver : public ui::ImplicitAnimationObserver {
147 explicit AnimationObserver(const base::Closure& callback)
148 : callback_(callback) {}
149 virtual ~AnimationObserver() {}
152 // ui::ImplicitAnimationObserver implementation:
153 virtual void OnImplicitAnimationsCompleted() override {
158 base::Closure callback_;
160 DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
163 // ShowLoginWizard is split into two parts. This function is sometimes called
164 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback()
165 // (if locale was updated).
166 void ShowLoginWizardFinish(
167 const std::string& first_screen_name,
168 const chromeos::StartupCustomizationDocument* startup_manifest,
169 chromeos::LoginDisplayHost* display_host) {
170 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish");
172 scoped_ptr<base::DictionaryValue> params;
173 display_host->StartWizard(first_screen_name, params.Pass());
175 // Set initial timezone if specified by customization.
176 const std::string timezone_name = startup_manifest->initial_timezone();
177 VLOG(1) << "Initial time zone: " << timezone_name;
178 // Apply locale customizations only once to preserve whatever locale
179 // user has changed to during OOBE.
180 if (!timezone_name.empty()) {
181 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
182 base::UTF8ToUTF16(timezone_name));
186 struct ShowLoginWizardSwitchLanguageCallbackData {
187 explicit ShowLoginWizardSwitchLanguageCallbackData(
188 const std::string& first_screen_name,
189 const chromeos::StartupCustomizationDocument* startup_manifest,
190 chromeos::LoginDisplayHost* display_host)
191 : first_screen_name(first_screen_name),
192 startup_manifest(startup_manifest),
193 display_host(display_host) {}
195 const std::string first_screen_name;
196 const chromeos::StartupCustomizationDocument* const startup_manifest;
197 chromeos::LoginDisplayHost* const display_host;
199 // lock UI while resource bundle is being reloaded.
200 chromeos::InputEventsBlocker events_blocker;
203 void OnLanguageSwitchedCallback(
204 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
205 const std::string& locale,
206 const std::string& loaded_locale,
207 const bool success) {
209 LOG(WARNING) << "Locale could not be found for '" << locale << "'";
211 ShowLoginWizardFinish(
212 self->first_screen_name, self->startup_manifest, self->display_host);
215 void EnableSystemSoundsForAccessibility() {
216 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
219 // A login implementation of WidgetDelegate.
220 class LoginWidgetDelegate : public views::WidgetDelegate {
222 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
224 virtual ~LoginWidgetDelegate() {}
226 // Overridden from WidgetDelegate:
227 virtual void DeleteDelegate() override {
230 virtual views::Widget* GetWidget() override {
233 virtual const views::Widget* GetWidget() const override {
236 virtual bool CanActivate() const override {
239 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
244 views::Widget* widget_;
246 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
249 // Disables virtual keyboard overscroll. Login UI will scroll user pods
250 // into view on JS side when virtual keyboard is shown.
251 void DisableKeyboardOverscroll() {
252 keyboard::SetKeyboardOverscrollOverride(
253 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
256 void ResetKeyboardOverscrollOverride() {
257 keyboard::SetKeyboardOverscrollOverride(
258 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
266 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
269 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
271 ////////////////////////////////////////////////////////////////////////////////
272 // LoginDisplayHostImpl, public
274 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
275 : background_bounds_(background_bounds),
276 pointer_factory_(this),
277 shutting_down_(false),
278 oobe_progress_bar_visible_(false),
279 session_starting_(false),
282 webui_login_display_(NULL),
283 is_showing_login_(false),
284 is_wallpaper_loaded_(false),
285 status_area_saved_visibility_(false),
287 restore_path_(RESTORE_UNKNOWN),
288 finalize_animation_type_(ANIMATION_WORKSPACE),
289 startup_sound_played_(false),
290 startup_sound_honors_spoken_feedback_(false),
291 is_observing_keyboard_(false),
292 animation_weak_ptr_factory_(this) {
293 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
294 CrasAudioHandler::Get()->AddAudioObserver(this);
295 if (keyboard::KeyboardController::GetInstance()) {
296 keyboard::KeyboardController::GetInstance()->AddObserver(this);
297 is_observing_keyboard_ = true;
300 #if !defined(USE_ATHENA)
301 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
302 ash::Shell::GetScreen()->AddObserver(this);
305 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
306 // because/ APP_TERMINATING will never be fired as long as this keeps
307 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
308 // browser instance that will block the shutdown.
310 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
311 content::NotificationService::AllSources());
313 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
314 // not shown yet. Lock window has to be closed at this point so that
315 // a browser window exists and the window can acquire input focus.
317 chrome::NOTIFICATION_BROWSER_OPENED,
318 content::NotificationService::AllSources());
320 // Login screen is moved to lock screen container when user logs in.
322 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
323 content::NotificationService::AllSources());
325 DCHECK(default_host_ == NULL);
326 default_host_ = this;
328 // Make sure chrome won't exit while we are at login/oobe screen.
329 chrome::IncrementKeepAliveCount();
331 bool is_registered = StartupUtils::IsDeviceRegistered();
332 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
333 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch(
334 switches::kDisableBootAnimation);
336 waiting_for_wallpaper_load_ = !zero_delay_enabled &&
337 (!is_registered || !disable_boot_animation);
339 #if defined(USE_ATHENA)
340 // TODO(dpolukhin): remove #ifdef when Athena supports wallpaper manager.
342 waiting_for_wallpaper_load_ = false;
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_;
350 initialize_webui_hidden_ =
351 kHiddenWebUIInitializationDefault && !zero_delay_enabled;
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;
364 // Always postpone WebUI initialization on first boot, otherwise we miss
365 // initial animation.
366 if (!StartupUtils::IsOobeCompleted())
367 initialize_webui_hidden_ = false;
369 // There is no wallpaper for KioskMode, don't initialize the webui hidden.
370 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
371 initialize_webui_hidden_ = false;
373 #if !defined(USE_ATHENA)
374 if (waiting_for_wallpaper_load_) {
376 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
377 content::NotificationService::AllSources());
381 // When we wait for WebUI to be initialized we wait for one of
382 // these notifications.
383 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
384 initialize_webui_hidden_) {
386 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
387 content::NotificationService::AllSources());
389 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
390 content::NotificationService::AllSources());
392 VLOG(1) << "Login WebUI >> "
393 << "zero_delay: " << zero_delay_enabled
394 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
395 << " wait_for_pods_: " << waiting_for_user_pods_
396 << " init_webui_hidden_: " << initialize_webui_hidden_;
398 media::SoundsManager* manager = media::SoundsManager::Get();
399 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
400 manager->Initialize(chromeos::SOUND_STARTUP,
401 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
404 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
405 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
406 CrasAudioHandler::Get()->RemoveAudioObserver(this);
407 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
408 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
409 is_observing_keyboard_ = false;
412 #if !defined(USE_ATHENA)
413 ash::Shell::GetInstance()->delegate()->
414 RemoveVirtualKeyboardStateObserver(this);
415 ash::Shell::GetScreen()->RemoveObserver(this);
418 if (login_view_ && login_window_)
419 login_window_->RemoveRemovalsObserver(this);
421 if (login::LoginScrollIntoViewEnabled())
422 ResetKeyboardOverscrollOverride();
424 views::FocusManager::set_arrow_key_traversal_enabled(false);
425 ResetLoginWindowAndView();
427 // Let chrome process exit after login/oobe screen if needed.
428 chrome::DecrementKeepAliveCount();
430 default_host_ = NULL;
431 // TODO(tengs): This should be refactored. See crbug.com/314934.
432 if (user_manager::UserManager::Get()->IsCurrentUserNew()) {
433 // DriveOptInController will delete itself when finished.
434 (new DriveFirstRunController(
435 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
439 ////////////////////////////////////////////////////////////////////////////////
440 // LoginDisplayHostImpl, LoginDisplayHost implementation:
442 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
443 LoginDisplay::Delegate* delegate) {
444 webui_login_display_ = new WebUILoginDisplay(delegate);
445 webui_login_display_->set_background_bounds(background_bounds());
446 return webui_login_display_;
449 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
450 return login_window_ ? login_window_->GetNativeWindow() : NULL;
453 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
457 void LoginDisplayHostImpl::BeforeSessionStart() {
458 session_starting_ = true;
461 void LoginDisplayHostImpl::Finalize() {
462 DVLOG(1) << "Session starting";
463 #if !defined(USE_ATHENA)
464 if (ash::Shell::HasInstance()) {
465 ash::Shell::GetInstance()->
466 desktop_background_controller()->MoveDesktopToUnlockedContainer();
469 if (wizard_controller_.get())
470 wizard_controller_->OnSessionStart();
472 switch (finalize_animation_type_) {
474 ShutdownDisplayHost(false);
476 case ANIMATION_WORKSPACE:
477 #if !defined(USE_ATHENA)
478 if (ash::Shell::HasInstance())
479 ScheduleWorkspaceAnimation();
482 ShutdownDisplayHost(false);
484 case ANIMATION_FADE_OUT:
485 // Display host is deleted once animation is completed
486 // since sign in screen widget has to stay alive.
487 ScheduleFadeOutAnimation();
492 void LoginDisplayHostImpl::OnCompleteLogin() {
493 if (auto_enrollment_controller_)
494 auto_enrollment_controller_->Cancel();
497 void LoginDisplayHostImpl::OpenProxySettings() {
499 login_view_->OpenProxySettings();
502 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
503 if (initialize_webui_hidden_)
504 status_area_saved_visibility_ = visible;
505 else if (login_view_)
506 login_view_->SetStatusAreaVisible(visible);
509 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
510 if (!auto_enrollment_controller_) {
511 auto_enrollment_controller_.reset(new AutoEnrollmentController());
512 auto_enrollment_progress_subscription_ =
513 auto_enrollment_controller_->RegisterProgressCallback(
514 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress,
515 base::Unretained(this)));
517 return auto_enrollment_controller_.get();
520 void LoginDisplayHostImpl::StartWizard(
521 const std::string& first_screen_name,
522 scoped_ptr<base::DictionaryValue> screen_parameters) {
523 if (login::LoginScrollIntoViewEnabled())
524 DisableKeyboardOverscroll();
526 startup_sound_honors_spoken_feedback_ = false;
527 TryToPlayStartupSound();
529 // Keep parameters to restore if renderer crashes.
530 restore_path_ = RESTORE_WIZARD;
531 first_screen_name_ = first_screen_name;
532 if (screen_parameters.get())
533 screen_parameters_.reset(screen_parameters->DeepCopy());
535 screen_parameters_.reset();
536 is_showing_login_ = false;
538 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
539 VLOG(1) << "Login WebUI >> wizard postponed";
542 VLOG(1) << "Login WebUI >> wizard";
545 LoadURL(GURL(kOobeURL));
547 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
548 // Create and show the wizard.
549 // Note, dtor of the old WizardController should be called before ctor of the
550 // new one, because "default_controller()" is updated there. So pure "reset()"
551 // is done before new controller creation.
552 wizard_controller_.reset();
553 wizard_controller_.reset(CreateWizardController());
555 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
556 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
557 wizard_controller_->Init(first_screen_name, screen_parameters.Pass());
560 WizardController* LoginDisplayHostImpl::GetWizardController() {
561 return wizard_controller_.get();
564 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
565 return app_launch_controller_.get();
568 void LoginDisplayHostImpl::StartUserAdding(
569 const base::Closure& completion_callback) {
570 if (login::LoginScrollIntoViewEnabled())
571 DisableKeyboardOverscroll();
573 restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
574 completion_callback_ = completion_callback;
575 finalize_animation_type_ = ANIMATION_NONE;
576 VLOG(1) << "Login WebUI >> user adding";
578 LoadURL(GURL(kUserAddingURL));
579 // We should emit this signal only at login screen (after reboot or sign out).
580 login_view_->set_should_emit_login_prompt_visible(false);
582 #if !defined(USE_ATHENA)
583 // Lock container can be transparent after lock screen animation.
584 aura::Window* lock_container = ash::Shell::GetContainer(
585 ash::Shell::GetPrimaryRootWindow(),
586 ash::kShellWindowId_LockScreenContainersContainer);
587 lock_container->layer()->SetOpacity(1.0);
589 ash::Shell::GetInstance()->
590 desktop_background_controller()->MoveDesktopToLockedContainer();
593 sign_in_controller_.reset(); // Only one controller in a time.
594 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
595 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
596 SetStatusAreaVisible(true);
597 sign_in_controller_->Init(
598 user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile());
599 CHECK(webui_login_display_);
600 GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
601 webui_login_display_,
602 webui_login_display_);
605 void LoginDisplayHostImpl::StartSignInScreen(
606 const LoginScreenContext& context) {
607 if (login::LoginScrollIntoViewEnabled())
608 DisableKeyboardOverscroll();
610 startup_sound_honors_spoken_feedback_ = true;
611 TryToPlayStartupSound();
613 restore_path_ = RESTORE_SIGN_IN;
614 is_showing_login_ = true;
615 finalize_animation_type_ = ANIMATION_WORKSPACE;
617 PrewarmAuthentication();
619 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
620 VLOG(1) << "Login WebUI >> sign in postponed";
623 VLOG(1) << "Login WebUI >> sign in";
625 if (!login_window_) {
626 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
627 TRACE_EVENT_ASYNC_STEP_INTO0(
628 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
629 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen");
630 LoadURL(GURL(kLoginURL));
633 DVLOG(1) << "Starting sign in screen";
634 const user_manager::UserList& users =
635 user_manager::UserManager::Get()->GetUsers();
637 // Fix for users who updated device and thus never passed register screen.
638 // If we already have users, we assume that it is not a second part of
639 // OOBE. See http://crosbug.com/6289
640 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
641 VLOG(1) << "Mark device registered because there are remembered users: "
643 StartupUtils::MarkDeviceRegistered(base::Closure());
646 sign_in_controller_.reset(); // Only one controller in a time.
647 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
648 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
649 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
650 SetStatusAreaVisible(true);
651 sign_in_controller_->Init(users);
653 // We might be here after a reboot that was triggered after OOBE was complete,
654 // so check for auto-enrollment again. This might catch a cached decision from
655 // a previous oobe flow, or might start a new check with the server.
656 if (GetAutoEnrollmentController()->ShouldEnrollSilently())
657 sign_in_controller_->DoAutoEnrollment();
659 GetAutoEnrollmentController()->Start();
661 // Initiate mobile config load.
662 MobileConfig::GetInstance();
664 // Initiate device policy fetching.
665 policy::BrowserPolicyConnectorChromeOS* connector =
666 g_browser_process->platform_part()->browser_policy_connector_chromeos();
667 connector->ScheduleServiceInitialization(
668 kPolicyServiceInitializationDelayMilliseconds);
670 CHECK(webui_login_display_);
671 GetOobeUI()->ShowSigninScreen(context,
672 webui_login_display_,
673 webui_login_display_);
674 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
675 SetStatusAreaVisible(false);
676 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
679 "WaitForScreenStateInitialize");
680 BootTimesLoader::Get()->RecordCurrentStats(
681 "login-wait-for-signin-state-initialize");
684 void LoginDisplayHostImpl::ResumeSignInScreen() {
685 // We only get here after a previous call the StartSignInScreen. That sign-in
686 // was successful but was interrupted by an auto-enrollment execution; once
687 // auto-enrollment is complete we resume the normal login flow from here.
688 DVLOG(1) << "Resuming sign in screen";
689 CHECK(sign_in_controller_.get());
690 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
691 SetStatusAreaVisible(true);
692 sign_in_controller_->ResumeLogin();
696 void LoginDisplayHostImpl::OnPreferencesChanged() {
697 if (is_showing_login_)
698 webui_login_display_->OnPreferencesChanged();
701 void LoginDisplayHostImpl::PrewarmAuthentication() {
702 auth_prewarmer_.reset(new AuthPrewarmer());
703 auth_prewarmer_->PrewarmAuthentication(
704 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
705 pointer_factory_.GetWeakPtr()));
708 void LoginDisplayHostImpl::StartDemoAppLaunch() {
709 VLOG(1) << "Login WebUI >> starting demo app.";
710 SetStatusAreaVisible(false);
712 demo_app_launcher_.reset(new DemoAppLauncher());
713 demo_app_launcher_->StartDemoAppLaunch();
716 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
717 bool diagnostic_mode) {
718 VLOG(1) << "Login WebUI >> start app launch.";
719 SetStatusAreaVisible(false);
720 finalize_animation_type_ = ANIMATION_FADE_OUT;
722 LoadURL(GURL(kAppLaunchSplashURL));
724 login_view_->set_should_emit_login_prompt_visible(false);
726 app_launch_controller_.reset(new AppLaunchController(
727 app_id, diagnostic_mode, this, GetOobeUI()));
729 app_launch_controller_->StartAppLaunch();
732 ////////////////////////////////////////////////////////////////////////////////
733 // LoginDisplayHostImpl, public
735 WizardController* LoginDisplayHostImpl::CreateWizardController() {
736 // TODO(altimofeev): ensure that WebUI is ready.
737 OobeDisplay* oobe_display = GetOobeUI();
738 return new WizardController(this, oobe_display);
741 void LoginDisplayHostImpl::OnBrowserCreated() {
742 // Close lock window now so that the launched browser can receive focus.
743 ResetLoginWindowAndView();
746 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
749 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
752 ////////////////////////////////////////////////////////////////////////////////
753 // LoginDisplayHostImpl, content:NotificationObserver implementation:
755 void LoginDisplayHostImpl::Observe(
757 const content::NotificationSource& source,
758 const content::NotificationDetails& details) {
759 if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
760 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
761 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE";
762 if (waiting_for_user_pods_ && initialize_webui_hidden_) {
763 waiting_for_user_pods_ = false;
765 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
766 // Reduce time till login UI is shown - show it as soon as possible.
767 waiting_for_wallpaper_load_ = false;
770 registrar_.Remove(this,
771 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
772 content::NotificationService::AllSources());
773 registrar_.Remove(this,
774 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
775 content::NotificationService::AllSources());
776 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
777 ShutdownDisplayHost(true);
778 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
779 // Browsers created before session start (windows opened by extensions, for
780 // example) are ignored.
782 registrar_.Remove(this,
783 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
784 content::NotificationService::AllSources());
785 registrar_.Remove(this,
786 chrome::NOTIFICATION_BROWSER_OPENED,
787 content::NotificationService::AllSources());
788 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
789 user_manager::UserManager::Get()->IsCurrentUserNew()) {
790 #if !defined(USE_ATHENA)
791 // For new user, move desktop to locker container so that windows created
792 // during the user image picker step are below it.
793 ash::Shell::GetInstance()->
794 desktop_background_controller()->MoveDesktopToLockedContainer();
796 registrar_.Remove(this,
797 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
798 content::NotificationService::AllSources());
799 #if !defined(USE_ATHENA)
800 } else if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
801 VLOG(1) << "Login WebUI >> wp animation done";
802 is_wallpaper_loaded_ = true;
803 ash::Shell::GetInstance()->user_wallpaper_delegate()
804 ->OnWallpaperBootAnimationFinished();
805 if (waiting_for_wallpaper_load_) {
806 // StartWizard / StartSignInScreen could be called multiple times through
807 // the lifetime of host.
808 // Make sure that subsequent calls are not postponed.
809 waiting_for_wallpaper_load_ = false;
810 if (initialize_webui_hidden_)
813 StartPostponedWebUI();
815 registrar_.Remove(this,
816 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
817 content::NotificationService::AllSources());
822 ////////////////////////////////////////////////////////////////////////////////
823 // LoginDisplayHostImpl, WebContentsObserver implementation:
825 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
826 // Do not try to restore on shutdown
827 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
831 if (crash_count_ > kCrashCountLimit)
834 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
835 // Render with login screen crashed. Let's crash browser process to let
836 // session manager restart it properly. It is hard to reload the page
837 // and get to controlled state that is fully functional.
838 // If you see check, search for renderer crash for the same client.
839 LOG(FATAL) << "Renderer crash on login window";
843 ////////////////////////////////////////////////////////////////////////////////
844 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
847 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
848 OnLoginPromptVisible();
851 ////////////////////////////////////////////////////////////////////////////////
852 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
855 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
856 TryToPlayStartupSound();
859 #if !defined(USE_ATHENA)
860 ////////////////////////////////////////////////////////////////////////////////
861 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
864 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
865 if (keyboard::KeyboardController::GetInstance()) {
867 if (!is_observing_keyboard_) {
868 keyboard::KeyboardController::GetInstance()->AddObserver(this);
869 is_observing_keyboard_ = true;
872 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
873 is_observing_keyboard_ = false;
879 ////////////////////////////////////////////////////////////////////////////////
880 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
883 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
884 const gfx::Rect& new_bounds) {
885 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
886 // Keyboard has been hidden.
888 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
889 if (login::LoginScrollIntoViewEnabled())
890 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds);
892 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
893 // Keyboard has been shown.
895 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
896 if (login::LoginScrollIntoViewEnabled())
897 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds);
901 keyboard_bounds_ = new_bounds;
904 ////////////////////////////////////////////////////////////////////////////////
905 // LoginDisplayHostImpl, gfx::DisplayObserver implementation:
907 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) {
910 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) {
913 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display,
914 uint32_t changed_metrics) {
915 gfx::Display primary_display =
916 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
917 if (display.id() != primary_display.id() ||
918 !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
923 const gfx::Size& size = primary_display.size();
924 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(),
929 ////////////////////////////////////////////////////////////////////////////////
930 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation:
931 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget,
933 if (view != static_cast<views::View*>(login_view_))
936 widget->RemoveRemovalsObserver(this);
939 ////////////////////////////////////////////////////////////////////////////////
940 // LoginDisplayHostImpl, private
942 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
946 shutting_down_ = true;
947 registrar_.RemoveAll();
948 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
950 base::MessageLoop::current()->Quit();
952 if (!completion_callback_.is_null())
953 completion_callback_.Run();
956 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
957 #if !defined(USE_ATHENA)
958 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
959 ash::kShellWindowId_DesktopBackgroundContainer)
962 // If there is no background window, don't perform any animation on the
963 // default and background layer because there is nothing behind it.
967 if (!CommandLine::ForCurrentProcess()->HasSwitch(
968 switches::kDisableLoginAnimations))
969 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
973 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
974 ui::Layer* layer = login_window_->GetLayer();
975 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
976 animation.AddObserver(new AnimationObserver(
977 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
978 animation_weak_ptr_factory_.GetWeakPtr(),
980 layer->SetOpacity(0);
983 void LoginDisplayHostImpl::OnAutoEnrollmentProgress(
984 policy::AutoEnrollmentState state) {
985 VLOG(1) << "OnAutoEnrollmentProgress, state " << state;
987 if (sign_in_controller_ &&
988 auto_enrollment_controller_->ShouldEnrollSilently()) {
989 sign_in_controller_->DoAutoEnrollment();
993 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
994 InitLoginWindowAndView();
995 // Subscribe to crash events.
996 content::WebContentsObserver::Observe(login_view_->GetWebContents());
997 login_view_->LoadURL(url);
999 // LoadURL could be called after the spring charger dialog shows, and
1000 // take away the focus from it. Set the focus back to the charger dialog
1001 // if it is visible.
1002 // See crbug.com/328538.
1003 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
1006 void LoginDisplayHostImpl::ShowWebUI() {
1007 if (!login_window_ || !login_view_) {
1011 VLOG(1) << "Login WebUI >> Show already initialized UI";
1012 login_window_->Show();
1013 login_view_->GetWebContents()->Focus();
1014 if (::switches::IsTextInputFocusManagerEnabled())
1015 login_view_->RequestFocus();
1016 login_view_->SetStatusAreaVisible(status_area_saved_visibility_);
1017 login_view_->OnPostponedShow();
1019 // Login window could be shown after the spring charger dialog shows, and
1020 // take away the focus from it. Set the focus back to the charger dialog
1021 // if it is visible.
1022 // See crbug.com/328538.
1023 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
1025 // We should reset this flag to allow changing of status area visibility.
1026 initialize_webui_hidden_ = false;
1029 void LoginDisplayHostImpl::StartPostponedWebUI() {
1030 if (!is_wallpaper_loaded_) {
1034 VLOG(1) << "Login WebUI >> Init postponed WebUI";
1036 // Wallpaper has finished loading before StartWizard/StartSignInScreen has
1037 // been called. In general this should not happen.
1038 // Let go through normal code path when one of those will be called.
1039 if (restore_path_ == RESTORE_UNKNOWN) {
1044 switch (restore_path_) {
1045 case RESTORE_WIZARD:
1046 StartWizard(first_screen_name_, screen_parameters_.Pass());
1048 case RESTORE_SIGN_IN:
1049 StartSignInScreen(LoginScreenContext());
1051 case RESTORE_ADD_USER_INTO_SESSION:
1052 StartUserAdding(completion_callback_);
1060 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1064 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1065 views::FocusManager::set_arrow_key_traversal_enabled(true);
1066 #if !defined(USE_ATHENA)
1068 focus_ring_controller_.reset(new FocusRingController);
1069 focus_ring_controller_->SetVisible(true);
1071 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1075 views::Widget::InitParams params(
1076 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1077 params.bounds = background_bounds();
1078 params.show_state = ui::SHOW_STATE_FULLSCREEN;
1079 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1080 #if defined(USE_ATHENA)
1081 athena::ScreenManager::ContainerParams container_params(
1082 "LoginScreen", athena::CP_LOGIN_SCREEN);
1083 container_params.can_activate_children = true;
1084 container_params.block_events = true;
1085 container_params.modal_container_priority =
1086 athena::CP_LOGIN_SCREEN_SYSTEM_MODAL;
1087 login_screen_container_.reset(
1088 athena::ScreenManager::Get()->CreateContainer(container_params));
1089 params.parent = login_screen_container_.get();
1090 login_screen_container_->SetLayoutManager(
1091 new athena::FillLayoutManager(login_screen_container_.get()));
1094 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1095 ash::kShellWindowId_LockScreenContainer);
1097 login_window_ = new views::Widget;
1098 params.delegate = new LoginWidgetDelegate(login_window_);
1099 login_window_->Init(params);
1101 login_view_ = new WebUILoginView();
1102 login_view_->Init();
1103 if (login_view_->webui_visible())
1104 OnLoginPromptVisible();
1106 login_window_->SetVisibilityAnimationDuration(
1107 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1108 login_window_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
1110 login_window_->AddRemovalsObserver(this);
1111 login_window_->SetContentsView(login_view_);
1113 // If WebUI is initialized in hidden state, show it only if we're no
1114 // longer waiting for wallpaper animation/user images loading. Otherwise,
1116 if (!initialize_webui_hidden_ ||
1117 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1118 VLOG(1) << "Login WebUI >> show login wnd on create";
1119 login_window_->Show();
1121 VLOG(1) << "Login WebUI >> login wnd is hidden on create";
1122 login_view_->set_is_hidden(true);
1124 login_window_->GetNativeView()->SetName("WebUILoginView");
1127 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1130 login_window_->Close();
1131 login_window_ = NULL;
1135 login_view_->SetUIEnabled(true);
1139 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1140 auth_prewarmer_.reset();
1143 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1144 GetOobeUI()->ShowOobeUI(visible);
1147 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1148 if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1149 !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) {
1153 startup_sound_played_ = true;
1155 // Don't try play startup sound if login prompt is already visible
1156 // for a long time or can't be played.
1157 if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1158 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1159 EnableSystemSoundsForAccessibility();
1163 #if !defined(USE_ATHENA)
1164 if (!startup_sound_honors_spoken_feedback_ &&
1165 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1166 EnableSystemSoundsForAccessibility();
1171 if (startup_sound_honors_spoken_feedback_ &&
1172 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1173 EnableSystemSoundsForAccessibility();
1178 base::MessageLoop::current()->PostDelayedTask(
1180 base::Bind(&EnableSystemSoundsForAccessibility),
1181 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1184 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1185 if (!login_prompt_visible_time_.is_null())
1187 login_prompt_visible_time_ = base::TimeTicks::Now();
1188 TryToPlayStartupSound();
1191 ////////////////////////////////////////////////////////////////////////////////
1194 // Declared in login_wizard.h so that others don't need to depend on our .h.
1195 // TODO(nkostylev): Split this into a smaller functions.
1196 void ShowLoginWizard(const std::string& first_screen_name) {
1197 if (browser_shutdown::IsTryingToQuit())
1200 VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1202 #if !defined(USE_ATHENA)
1203 // TODO(dpolukhin): crbug.com/407579
1204 chromeos::input_method::InputMethodManager* manager =
1205 chromeos::input_method::InputMethodManager::Get();
1207 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1208 // and US dvorak keyboard layouts.
1209 if (g_browser_process && g_browser_process->local_state()) {
1210 manager->GetActiveIMEState()->SetInputMethodLoginDefault();
1212 PrefService* prefs = g_browser_process->local_state();
1213 // Apply owner preferences for tap-to-click and mouse buttons swap for
1215 system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1216 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1217 system::InputDeviceSettings::Get()->SetTapToClick(
1218 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1220 system::InputDeviceSettings::Get()->SetNaturalScroll(
1221 CommandLine::ForCurrentProcess()->HasSwitch(
1222 switches::kNaturalScrollDefault));
1225 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1227 g_browser_process->platform_part()->SessionManager()->SetSessionState(
1228 StartupUtils::IsOobeCompleted()
1229 ? session_manager::SESSION_STATE_LOGIN_PRIMARY
1230 : session_manager::SESSION_STATE_OOBE);
1232 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds);
1234 bool show_app_launch_splash_screen =
1235 (first_screen_name == WizardController::kAppLaunchSplashScreenName);
1236 if (show_app_launch_splash_screen) {
1237 const std::string& auto_launch_app_id =
1238 KioskAppManager::Get()->GetAutoLaunchApp();
1239 display_host->StartAppLaunch(auto_launch_app_id,
1240 false /* diagnostic_mode */);
1244 // Check whether we need to execute OOBE flow.
1245 bool oobe_complete = StartupUtils::IsOobeCompleted();
1246 policy::BrowserPolicyConnectorChromeOS* connector =
1247 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1248 bool enrollment_screen_wanted =
1249 WizardController::ShouldRecoverEnrollment() ||
1250 (WizardController::ShouldAutoStartEnrollment() && oobe_complete &&
1251 !connector->IsEnterpriseManaged());
1252 if (enrollment_screen_wanted && first_screen_name.empty()) {
1253 // Shows networks screen instead of enrollment screen to resume the
1254 // interrupted auto start enrollment flow because enrollment screen does
1255 // not handle flaky network. See http://crbug.com/332572
1256 display_host->StartWizard(WizardController::kNetworkScreenName,
1257 scoped_ptr<base::DictionaryValue>());
1261 if (StartupUtils::IsEulaAccepted()) {
1263 ServicesCustomizationDocument::GetInstance()
1264 ->EnsureCustomizationAppliedClosure(),
1265 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS));
1268 bool show_login_screen =
1269 (first_screen_name.empty() && oobe_complete) ||
1270 first_screen_name == WizardController::kLoginScreenName;
1272 if (show_login_screen) {
1273 display_host->StartSignInScreen(LoginScreenContext());
1277 // Load startup manifest.
1278 const StartupCustomizationDocument* startup_manifest =
1279 StartupCustomizationDocument::GetInstance();
1281 // Switch to initial locale if specified by customization
1282 // and has not been set yet. We cannot call
1283 // LanguageSwitchMenu::SwitchLanguage here before
1284 // EmitLoginPromptReady.
1285 PrefService* prefs = g_browser_process->local_state();
1286 const std::string& current_locale =
1287 prefs->GetString(prefs::kApplicationLocale);
1288 VLOG(1) << "Current locale: " << current_locale;
1289 const std::string& locale = startup_manifest->initial_locale_default();
1291 const std::string& layout = startup_manifest->keyboard_layout();
1292 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1294 #if !defined(USE_ATHENA)
1295 // Determine keyboard layout from OEM customization (if provided) or
1296 // initial locale and save it in preferences.
1297 manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale,
1301 if (!current_locale.empty() || locale.empty()) {
1302 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1306 // Save initial locale from VPD/customization manifest as current
1307 // Chrome locale. Otherwise it will be lost if Chrome restarts.
1308 // Don't need to schedule pref save because setting initial local
1309 // will enforce preference saving.
1310 prefs->SetString(prefs::kApplicationLocale, locale);
1311 StartupUtils::SetInitialLocale(locale);
1313 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1314 new ShowLoginWizardSwitchLanguageCallbackData(
1315 first_screen_name, startup_manifest, display_host));
1317 scoped_ptr<locale_util::SwitchLanguageCallback> callback(
1318 new locale_util::SwitchLanguageCallback(
1319 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass()))));
1321 // Load locale keyboards here. Hardware layout would be automatically enabled.
1322 locale_util::SwitchLanguage(
1323 locale, true, true /* login_layouts_only */, callback.Pass());
1326 } // namespace chromeos