ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / chromeos / login / ui / login_display_host_impl.cc
blob7e843cc88403d2419e9ca40745ce30ea8cebd694
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"
7 #include <vector>
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/logging.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "base/time/time.h"
22 #include "base/trace_event/trace_event.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/browser_shutdown.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
27 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
28 #include "chrome/browser/chromeos/base/locale_util.h"
29 #include "chrome/browser/chromeos/boot_times_recorder.h"
30 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
31 #include "chrome/browser/chromeos/first_run/first_run.h"
32 #include "chrome/browser/chromeos/input_method/input_method_util.h"
33 #include "chrome/browser/chromeos/language_preferences.h"
34 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
35 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
36 #include "chrome/browser/chromeos/login/existing_user_controller.h"
37 #include "chrome/browser/chromeos/login/helper.h"
38 #include "chrome/browser/chromeos/login/login_wizard.h"
39 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
40 #include "chrome/browser/chromeos/login/startup_utils.h"
41 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
42 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
43 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
44 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
45 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
46 #include "chrome/browser/chromeos/login/wizard_controller.h"
47 #include "chrome/browser/chromeos/mobile_config.h"
48 #include "chrome/browser/chromeos/net/delay_network_call.h"
49 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
50 #include "chrome/browser/chromeos/policy/enrollment_config.h"
51 #include "chrome/browser/chromeos/settings/cros_settings.h"
52 #include "chrome/browser/chromeos/system/device_disabling_manager.h"
53 #include "chrome/browser/chromeos/system/input_device_settings.h"
54 #include "chrome/browser/chromeos/system/timezone_util.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/login/login_state.h"
69 #include "chromeos/settings/cros_settings_names.h"
70 #include "chromeos/settings/cros_settings_provider.h"
71 #include "chromeos/settings/timezone_settings.h"
72 #include "chromeos/timezone/timezone_resolver.h"
73 #include "components/session_manager/core/session_manager.h"
74 #include "components/user_manager/user_manager.h"
75 #include "content/public/browser/notification_service.h"
76 #include "content/public/browser/notification_types.h"
77 #include "content/public/browser/web_contents.h"
78 #include "content/public/browser/web_ui.h"
79 #include "media/audio/sounds/sounds_manager.h"
80 #include "ui/aura/window.h"
81 #include "ui/base/ime/chromeos/extension_ime_util.h"
82 #include "ui/base/ime/chromeos/input_method_manager.h"
83 #include "ui/base/resource/resource_bundle.h"
84 #include "ui/base/ui_base_switches_util.h"
85 #include "ui/compositor/layer.h"
86 #include "ui/compositor/layer_animation_observer.h"
87 #include "ui/compositor/scoped_layer_animation_settings.h"
88 #include "ui/events/event_utils.h"
89 #include "ui/gfx/display.h"
90 #include "ui/gfx/geometry/rect.h"
91 #include "ui/gfx/geometry/size.h"
92 #include "ui/gfx/screen.h"
93 #include "ui/gfx/transform.h"
94 #include "ui/keyboard/keyboard_controller.h"
95 #include "ui/keyboard/keyboard_util.h"
96 #include "ui/views/focus/focus_manager.h"
97 #include "ui/views/widget/widget.h"
98 #include "ui/views/widget/widget_delegate.h"
99 #include "url/gurl.h"
101 namespace {
103 // Maximum delay for startup sound after 'loginPromptVisible' signal.
104 const int kStartupSoundMaxDelayMs = 2000;
106 // URL which corresponds to the login WebUI.
107 const char kLoginURL[] = "chrome://oobe/login";
109 // URL which corresponds to the OOBE WebUI.
110 const char kOobeURL[] = "chrome://oobe/oobe";
112 // URL which corresponds to the new implementation of OOBE WebUI.
113 const char kNewOobeURL[] = "chrome://oobe/new-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 {
143 public:
144 explicit AnimationObserver(const base::Closure& callback)
145 : callback_(callback) {}
146 ~AnimationObserver() override {}
148 private:
149 // ui::ImplicitAnimationObserver implementation:
150 void OnImplicitAnimationsCompleted() override {
151 callback_.Run();
152 delete this;
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 display_host->StartWizard(first_screen_name);
171 // Set initial timezone if specified by customization.
172 const std::string timezone_name = startup_manifest->initial_timezone();
173 VLOG(1) << "Initial time zone: " << timezone_name;
174 // Apply locale customizations only once to preserve whatever locale
175 // user has changed to during OOBE.
176 if (!timezone_name.empty()) {
177 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
178 base::UTF8ToUTF16(timezone_name));
182 struct ShowLoginWizardSwitchLanguageCallbackData {
183 explicit ShowLoginWizardSwitchLanguageCallbackData(
184 const std::string& first_screen_name,
185 const chromeos::StartupCustomizationDocument* startup_manifest,
186 chromeos::LoginDisplayHost* display_host)
187 : first_screen_name(first_screen_name),
188 startup_manifest(startup_manifest),
189 display_host(display_host) {}
191 const std::string first_screen_name;
192 const chromeos::StartupCustomizationDocument* const startup_manifest;
193 chromeos::LoginDisplayHost* const display_host;
195 // lock UI while resource bundle is being reloaded.
196 chromeos::InputEventsBlocker events_blocker;
199 void OnLanguageSwitchedCallback(
200 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
201 const chromeos::locale_util::LanguageSwitchResult& result) {
202 if (!result.success)
203 LOG(WARNING) << "Locale could not be found for '" << result.requested_locale
204 << "'";
206 ShowLoginWizardFinish(
207 self->first_screen_name, self->startup_manifest, self->display_host);
210 void EnableSystemSoundsForAccessibility() {
211 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
214 // A login implementation of WidgetDelegate.
215 class LoginWidgetDelegate : public views::WidgetDelegate {
216 public:
217 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
219 ~LoginWidgetDelegate() override {}
221 // Overridden from WidgetDelegate:
222 void DeleteDelegate() override { delete this; }
223 views::Widget* GetWidget() override { return widget_; }
224 const views::Widget* GetWidget() const override { return widget_; }
225 bool CanActivate() const override { return true; }
226 bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
228 private:
229 views::Widget* widget_;
231 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
234 // Disables virtual keyboard overscroll. Login UI will scroll user pods
235 // into view on JS side when virtual keyboard is shown.
236 void DisableKeyboardOverscroll() {
237 keyboard::SetKeyboardOverscrollOverride(
238 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
241 void ResetKeyboardOverscrollOverride() {
242 keyboard::SetKeyboardOverscrollOverride(
243 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
246 } // namespace
248 namespace chromeos {
250 // static
251 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
253 // static
254 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
256 ////////////////////////////////////////////////////////////////////////////////
257 // LoginDisplayHostImpl, public
259 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
260 : background_bounds_(background_bounds),
261 shutting_down_(false),
262 oobe_progress_bar_visible_(false),
263 session_starting_(false),
264 login_window_(NULL),
265 login_view_(NULL),
266 webui_login_display_(NULL),
267 is_showing_login_(false),
268 is_wallpaper_loaded_(false),
269 status_area_saved_visibility_(false),
270 crash_count_(0),
271 restore_path_(RESTORE_UNKNOWN),
272 finalize_animation_type_(ANIMATION_WORKSPACE),
273 startup_sound_played_(false),
274 startup_sound_honors_spoken_feedback_(false),
275 is_observing_keyboard_(false),
276 pointer_factory_(this),
277 animation_weak_ptr_factory_(this) {
278 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
279 CrasAudioHandler::Get()->AddAudioObserver(this);
280 if (keyboard::KeyboardController::GetInstance()) {
281 keyboard::KeyboardController::GetInstance()->AddObserver(this);
282 is_observing_keyboard_ = true;
285 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
286 ash::Shell::GetScreen()->AddObserver(this);
288 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
289 // because/ APP_TERMINATING will never be fired as long as this keeps
290 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
291 // browser instance that will block the shutdown.
292 registrar_.Add(this,
293 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
294 content::NotificationService::AllSources());
296 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
297 // not shown yet. Lock window has to be closed at this point so that
298 // a browser window exists and the window can acquire input focus.
299 registrar_.Add(this,
300 chrome::NOTIFICATION_BROWSER_OPENED,
301 content::NotificationService::AllSources());
303 // Login screen is moved to lock screen container when user logs in.
304 registrar_.Add(this,
305 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
306 content::NotificationService::AllSources());
308 DCHECK(default_host_ == NULL);
309 default_host_ = this;
311 // Make sure chrome won't exit while we are at login/oobe screen.
312 chrome::IncrementKeepAliveCount();
314 bool is_registered = StartupUtils::IsDeviceRegistered();
315 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
316 bool disable_boot_animation =
317 base::CommandLine::ForCurrentProcess()->HasSwitch(
318 switches::kDisableBootAnimation);
320 waiting_for_wallpaper_load_ = !zero_delay_enabled &&
321 (!is_registered || !disable_boot_animation);
323 // For slower hardware we have boot animation disabled so
324 // we'll be initializing WebUI hidden, waiting for user pods to load and then
325 // show WebUI at once.
326 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_;
328 initialize_webui_hidden_ =
329 kHiddenWebUIInitializationDefault && !zero_delay_enabled;
331 // Check if WebUI init type is overriden.
332 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
333 switches::kAshWebUIInit)) {
334 const std::string override_type =
335 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
336 switches::kAshWebUIInit);
337 if (override_type == kWebUIInitParallel)
338 initialize_webui_hidden_ = true;
339 else if (override_type == kWebUIInitPostpone)
340 initialize_webui_hidden_ = false;
343 // Always postpone WebUI initialization on first boot, otherwise we miss
344 // initial animation.
345 if (!StartupUtils::IsOobeCompleted())
346 initialize_webui_hidden_ = false;
348 if (waiting_for_wallpaper_load_) {
349 registrar_.Add(this,
350 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
351 content::NotificationService::AllSources());
354 // When we wait for WebUI to be initialized we wait for one of
355 // these notifications.
356 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
357 initialize_webui_hidden_) {
358 registrar_.Add(this,
359 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
360 content::NotificationService::AllSources());
361 registrar_.Add(this,
362 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
363 content::NotificationService::AllSources());
365 VLOG(1) << "Login WebUI >> "
366 << "zero_delay: " << zero_delay_enabled
367 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
368 << " wait_for_pods_: " << waiting_for_user_pods_
369 << " init_webui_hidden_: " << initialize_webui_hidden_;
371 media::SoundsManager* manager = media::SoundsManager::Get();
372 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
373 manager->Initialize(chromeos::SOUND_STARTUP,
374 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
377 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
378 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
379 CrasAudioHandler::Get()->RemoveAudioObserver(this);
380 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
381 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
382 is_observing_keyboard_ = false;
385 ash::Shell::GetInstance()->delegate()->
386 RemoveVirtualKeyboardStateObserver(this);
387 ash::Shell::GetScreen()->RemoveObserver(this);
389 if (login_view_ && login_window_)
390 login_window_->RemoveRemovalsObserver(this);
392 if (login::LoginScrollIntoViewEnabled())
393 ResetKeyboardOverscrollOverride();
395 views::FocusManager::set_arrow_key_traversal_enabled(false);
396 ResetLoginWindowAndView();
398 // Let chrome process exit after login/oobe screen if needed.
399 chrome::DecrementKeepAliveCount();
401 default_host_ = NULL;
402 // TODO(tengs): This should be refactored. See crbug.com/314934.
403 if (user_manager::UserManager::Get()->IsCurrentUserNew()) {
404 // DriveOptInController will delete itself when finished.
405 (new DriveFirstRunController(
406 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
410 ////////////////////////////////////////////////////////////////////////////////
411 // LoginDisplayHostImpl, LoginDisplayHost implementation:
413 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
414 LoginDisplay::Delegate* delegate) {
415 webui_login_display_ = new WebUILoginDisplay(delegate);
416 webui_login_display_->set_background_bounds(background_bounds());
417 return webui_login_display_;
420 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
421 return login_window_ ? login_window_->GetNativeWindow() : NULL;
424 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
425 return login_view_;
428 void LoginDisplayHostImpl::BeforeSessionStart() {
429 session_starting_ = true;
432 void LoginDisplayHostImpl::Finalize() {
433 DVLOG(1) << "Session starting";
434 if (ash::Shell::HasInstance()) {
435 ash::Shell::GetInstance()->
436 desktop_background_controller()->MoveDesktopToUnlockedContainer();
438 if (wizard_controller_.get())
439 wizard_controller_->OnSessionStart();
441 switch (finalize_animation_type_) {
442 case ANIMATION_NONE:
443 ShutdownDisplayHost(false);
444 break;
445 case ANIMATION_WORKSPACE:
446 if (ash::Shell::HasInstance())
447 ScheduleWorkspaceAnimation();
449 ShutdownDisplayHost(false);
450 break;
451 case ANIMATION_FADE_OUT:
452 // Display host is deleted once animation is completed
453 // since sign in screen widget has to stay alive.
454 ScheduleFadeOutAnimation();
455 break;
459 void LoginDisplayHostImpl::OnCompleteLogin() {
460 if (auto_enrollment_controller_)
461 auto_enrollment_controller_->Cancel();
464 void LoginDisplayHostImpl::OpenProxySettings() {
465 if (login_view_)
466 login_view_->OpenProxySettings();
469 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
470 if (initialize_webui_hidden_)
471 status_area_saved_visibility_ = visible;
472 else if (login_view_)
473 login_view_->SetStatusAreaVisible(visible);
476 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
477 if (!auto_enrollment_controller_)
478 auto_enrollment_controller_.reset(new AutoEnrollmentController());
479 return auto_enrollment_controller_.get();
482 void LoginDisplayHostImpl::StartWizard(const std::string& first_screen_name) {
483 if (login::LoginScrollIntoViewEnabled())
484 DisableKeyboardOverscroll();
486 startup_sound_honors_spoken_feedback_ = false;
487 TryToPlayStartupSound();
489 // Keep parameters to restore if renderer crashes.
490 restore_path_ = RESTORE_WIZARD;
491 first_screen_name_ = first_screen_name;
492 is_showing_login_ = false;
494 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
495 VLOG(1) << "Login WebUI >> wizard postponed";
496 return;
498 VLOG(1) << "Login WebUI >> wizard";
500 if (!login_window_) {
501 LoadURL(StartupUtils::IsNewOobeActivated() ? GURL(kNewOobeURL)
502 : GURL(kOobeURL));
505 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
506 // Create and show the wizard.
507 // Note, dtor of the old WizardController should be called before ctor of the
508 // new one, because "default_controller()" is updated there. So pure "reset()"
509 // is done before new controller creation.
510 wizard_controller_.reset();
511 wizard_controller_.reset(CreateWizardController());
513 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
514 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
515 wizard_controller_->Init(first_screen_name);
518 WizardController* LoginDisplayHostImpl::GetWizardController() {
519 return wizard_controller_.get();
522 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
523 return app_launch_controller_.get();
526 void LoginDisplayHostImpl::StartUserAdding(
527 const base::Closure& completion_callback) {
528 if (login::LoginScrollIntoViewEnabled())
529 DisableKeyboardOverscroll();
531 restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
532 completion_callback_ = completion_callback;
533 finalize_animation_type_ = ANIMATION_NONE;
534 VLOG(1) << "Login WebUI >> user adding";
535 if (!login_window_)
536 LoadURL(GURL(kUserAddingURL));
537 // We should emit this signal only at login screen (after reboot or sign out).
538 login_view_->set_should_emit_login_prompt_visible(false);
540 // Lock container can be transparent after lock screen animation.
541 aura::Window* lock_container = ash::Shell::GetContainer(
542 ash::Shell::GetPrimaryRootWindow(),
543 ash::kShellWindowId_LockScreenContainersContainer);
544 lock_container->layer()->SetOpacity(1.0);
546 ash::Shell::GetInstance()->
547 desktop_background_controller()->MoveDesktopToLockedContainer();
549 existing_user_controller_.reset(); // Only one controller in a time.
550 existing_user_controller_.reset(new chromeos::ExistingUserController(this));
552 if (!signin_screen_controller_.get()) {
553 OobeDisplay* oobe_display = GetOobeUI();
554 signin_screen_controller_.reset(new SignInScreenController(
555 oobe_display, webui_login_display_->delegate()));
558 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
559 SetStatusAreaVisible(true);
560 existing_user_controller_->Init(
561 user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile());
562 CHECK(webui_login_display_);
563 GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
564 webui_login_display_,
565 webui_login_display_);
568 void LoginDisplayHostImpl::StartSignInScreen(
569 const LoginScreenContext& context) {
570 if (login::LoginScrollIntoViewEnabled())
571 DisableKeyboardOverscroll();
573 startup_sound_honors_spoken_feedback_ = true;
574 TryToPlayStartupSound();
576 restore_path_ = RESTORE_SIGN_IN;
577 is_showing_login_ = true;
578 finalize_animation_type_ = ANIMATION_WORKSPACE;
580 PrewarmAuthentication();
582 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
583 VLOG(1) << "Login WebUI >> sign in postponed";
584 return;
586 VLOG(1) << "Login WebUI >> sign in";
588 if (!login_window_) {
589 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
590 TRACE_EVENT_ASYNC_STEP_INTO0(
591 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
592 BootTimesRecorder::Get()->RecordCurrentStats("login-start-signin-screen");
593 LoadURL(GURL(kLoginURL));
596 DVLOG(1) << "Starting sign in screen";
597 const user_manager::UserList& users =
598 user_manager::UserManager::Get()->GetUsers();
600 // Fix for users who updated device and thus never passed register screen.
601 // If we already have users, we assume that it is not a second part of
602 // OOBE. See http://crosbug.com/6289
603 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
604 VLOG(1) << "Mark device registered because there are remembered users: "
605 << users.size();
606 StartupUtils::MarkDeviceRegistered(base::Closure());
609 existing_user_controller_.reset(); // Only one controller in a time.
610 existing_user_controller_.reset(new chromeos::ExistingUserController(this));
612 if (!signin_screen_controller_.get()) {
613 OobeDisplay* oobe_display = GetOobeUI();
614 signin_screen_controller_.reset(new SignInScreenController(
615 oobe_display, webui_login_display_->delegate()));
618 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
619 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
620 SetStatusAreaVisible(true);
621 existing_user_controller_->Init(users);
623 // We might be here after a reboot that was triggered after OOBE was complete,
624 // so check for auto-enrollment again. This might catch a cached decision from
625 // a previous oobe flow, or might start a new check with the server.
626 GetAutoEnrollmentController()->Start();
628 // Initiate mobile config load.
629 MobileConfig::GetInstance();
631 // Initiate device policy fetching.
632 policy::BrowserPolicyConnectorChromeOS* connector =
633 g_browser_process->platform_part()->browser_policy_connector_chromeos();
634 connector->ScheduleServiceInitialization(
635 kPolicyServiceInitializationDelayMilliseconds);
637 CHECK(webui_login_display_);
638 GetOobeUI()->ShowSigninScreen(context,
639 webui_login_display_,
640 webui_login_display_);
641 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
642 "ShowLoginWebUI",
643 kShowLoginWebUIid,
644 "WaitForScreenStateInitialize");
645 BootTimesRecorder::Get()->RecordCurrentStats(
646 "login-wait-for-signin-state-initialize");
649 void LoginDisplayHostImpl::OnPreferencesChanged() {
650 if (is_showing_login_)
651 webui_login_display_->OnPreferencesChanged();
654 void LoginDisplayHostImpl::PrewarmAuthentication() {
655 auth_prewarmer_.reset(new AuthPrewarmer());
656 auth_prewarmer_->PrewarmAuthentication(
657 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
658 pointer_factory_.GetWeakPtr()));
661 void LoginDisplayHostImpl::StartDemoAppLaunch() {
662 VLOG(1) << "Login WebUI >> starting demo app.";
663 SetStatusAreaVisible(false);
665 demo_app_launcher_.reset(new DemoAppLauncher());
666 demo_app_launcher_->StartDemoAppLaunch();
669 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
670 bool diagnostic_mode,
671 bool auto_launch) {
672 VLOG(1) << "Login WebUI >> start app launch.";
673 SetStatusAreaVisible(false);
675 // Wait for the |CrosSettings| to become either trusted or permanently
676 // untrusted.
677 const CrosSettingsProvider::TrustedStatus status =
678 CrosSettings::Get()->PrepareTrustedValues(base::Bind(
679 &LoginDisplayHostImpl::StartAppLaunch,
680 pointer_factory_.GetWeakPtr(),
681 app_id,
682 diagnostic_mode,
683 auto_launch));
684 if (status == CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
685 return;
687 if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
688 // If the |CrosSettings| are permanently untrusted, refuse to launch a
689 // single-app kiosk mode session.
690 LOG(ERROR) << "Login WebUI >> Refusing to launch single-app kiosk mode.";
691 SetStatusAreaVisible(true);
692 return;
695 bool device_disabled = false;
696 CrosSettings::Get()->GetBoolean(kDeviceDisabled, &device_disabled);
697 if (device_disabled && system::DeviceDisablingManager::
698 HonorDeviceDisablingDuringNormalOperation()) {
699 // If the device is disabled, bail out. A device disabled screen will be
700 // shown by the DeviceDisablingManager.
701 return;
704 finalize_animation_type_ = ANIMATION_FADE_OUT;
705 if (!login_window_)
706 LoadURL(GURL(kAppLaunchSplashURL));
708 login_view_->set_should_emit_login_prompt_visible(false);
710 app_launch_controller_.reset(new AppLaunchController(
711 app_id, diagnostic_mode, this, GetOobeUI()));
713 app_launch_controller_->StartAppLaunch(auto_launch);
716 ////////////////////////////////////////////////////////////////////////////////
717 // LoginDisplayHostImpl, public
719 WizardController* LoginDisplayHostImpl::CreateWizardController() {
720 // TODO(altimofeev): ensure that WebUI is ready.
721 OobeDisplay* oobe_display = GetOobeUI();
722 return new WizardController(this, oobe_display);
725 void LoginDisplayHostImpl::OnBrowserCreated() {
726 // Close lock window now so that the launched browser can receive focus.
727 ResetLoginWindowAndView();
730 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
731 if (!login_view_)
732 return NULL;
733 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
736 ////////////////////////////////////////////////////////////////////////////////
737 // LoginDisplayHostImpl, content:NotificationObserver implementation:
739 void LoginDisplayHostImpl::Observe(
740 int type,
741 const content::NotificationSource& source,
742 const content::NotificationDetails& details) {
743 if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
744 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
745 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE";
746 if (waiting_for_user_pods_ && initialize_webui_hidden_) {
747 waiting_for_user_pods_ = false;
748 ShowWebUI();
749 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
750 // Reduce time till login UI is shown - show it as soon as possible.
751 waiting_for_wallpaper_load_ = false;
752 ShowWebUI();
754 registrar_.Remove(this,
755 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
756 content::NotificationService::AllSources());
757 registrar_.Remove(this,
758 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
759 content::NotificationService::AllSources());
760 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
761 ShutdownDisplayHost(true);
762 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
763 // Browsers created before session start (windows opened by extensions, for
764 // example) are ignored.
765 OnBrowserCreated();
766 registrar_.Remove(this,
767 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
768 content::NotificationService::AllSources());
769 registrar_.Remove(this,
770 chrome::NOTIFICATION_BROWSER_OPENED,
771 content::NotificationService::AllSources());
772 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
773 user_manager::UserManager::Get()->IsCurrentUserNew()) {
774 // For new user, move desktop to locker container so that windows created
775 // during the user image picker step are below it.
776 ash::Shell::GetInstance()->
777 desktop_background_controller()->MoveDesktopToLockedContainer();
778 registrar_.Remove(this,
779 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
780 content::NotificationService::AllSources());
781 } else if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
782 VLOG(1) << "Login WebUI >> wp animation done";
783 is_wallpaper_loaded_ = true;
784 ash::Shell::GetInstance()->user_wallpaper_delegate()
785 ->OnWallpaperBootAnimationFinished();
786 if (waiting_for_wallpaper_load_) {
787 // StartWizard / StartSignInScreen could be called multiple times through
788 // the lifetime of host.
789 // Make sure that subsequent calls are not postponed.
790 waiting_for_wallpaper_load_ = false;
791 if (initialize_webui_hidden_)
792 ShowWebUI();
793 else
794 StartPostponedWebUI();
796 registrar_.Remove(this,
797 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
798 content::NotificationService::AllSources());
802 ////////////////////////////////////////////////////////////////////////////////
803 // LoginDisplayHostImpl, WebContentsObserver implementation:
805 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
806 // Do not try to restore on shutdown
807 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
808 return;
810 crash_count_++;
811 if (crash_count_ > kCrashCountLimit)
812 return;
814 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
815 // Render with login screen crashed. Let's crash browser process to let
816 // session manager restart it properly. It is hard to reload the page
817 // and get to controlled state that is fully functional.
818 // If you see check, search for renderer crash for the same client.
819 LOG(FATAL) << "Renderer crash on login window";
823 ////////////////////////////////////////////////////////////////////////////////
824 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
825 // implementation:
827 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
828 OnLoginPromptVisible();
831 ////////////////////////////////////////////////////////////////////////////////
832 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
833 // implementation:
835 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
836 TryToPlayStartupSound();
839 ////////////////////////////////////////////////////////////////////////////////
840 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
841 // implementation:
843 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
844 if (keyboard::KeyboardController::GetInstance()) {
845 if (activated) {
846 if (!is_observing_keyboard_) {
847 keyboard::KeyboardController::GetInstance()->AddObserver(this);
848 is_observing_keyboard_ = true;
850 } else {
851 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
852 is_observing_keyboard_ = false;
857 ////////////////////////////////////////////////////////////////////////////////
858 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
859 // implementation:
861 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
862 const gfx::Rect& new_bounds) {
863 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
864 // Keyboard has been hidden.
865 if (GetOobeUI()) {
866 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
867 if (login::LoginScrollIntoViewEnabled())
868 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds);
870 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
871 // Keyboard has been shown.
872 if (GetOobeUI()) {
873 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
874 if (login::LoginScrollIntoViewEnabled())
875 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds);
879 keyboard_bounds_ = new_bounds;
882 ////////////////////////////////////////////////////////////////////////////////
883 // LoginDisplayHostImpl, gfx::DisplayObserver implementation:
885 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) {
888 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) {
891 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display,
892 uint32_t changed_metrics) {
893 gfx::Display primary_display =
894 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
895 if (display.id() != primary_display.id() ||
896 !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
897 return;
900 if (GetOobeUI()) {
901 const gfx::Size& size = primary_display.size();
902 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(),
903 size.height());
907 ////////////////////////////////////////////////////////////////////////////////
908 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation:
909 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget,
910 views::View* view) {
911 if (view != static_cast<views::View*>(login_view_))
912 return;
913 login_view_ = NULL;
914 widget->RemoveRemovalsObserver(this);
917 ////////////////////////////////////////////////////////////////////////////////
918 // LoginDisplayHostImpl, private
920 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
921 if (shutting_down_)
922 return;
924 shutting_down_ = true;
925 registrar_.RemoveAll();
926 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
927 if (post_quit_task)
928 base::MessageLoop::current()->Quit();
930 if (!completion_callback_.is_null())
931 completion_callback_.Run();
934 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
935 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
936 ash::kShellWindowId_DesktopBackgroundContainer)
937 ->children()
938 .empty()) {
939 // If there is no background window, don't perform any animation on the
940 // default and background layer because there is nothing behind it.
941 return;
944 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
945 switches::kDisableLoginAnimations))
946 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
949 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
950 ui::Layer* layer = login_window_->GetLayer();
951 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
952 animation.AddObserver(new AnimationObserver(
953 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
954 animation_weak_ptr_factory_.GetWeakPtr(),
955 false)));
956 layer->SetOpacity(0);
959 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
960 InitLoginWindowAndView();
961 // Subscribe to crash events.
962 content::WebContentsObserver::Observe(login_view_->GetWebContents());
963 login_view_->LoadURL(url);
966 void LoginDisplayHostImpl::ShowWebUI() {
967 if (!login_window_ || !login_view_) {
968 NOTREACHED();
969 return;
971 VLOG(1) << "Login WebUI >> Show already initialized UI";
972 login_window_->Show();
973 login_view_->GetWebContents()->Focus();
974 if (::switches::IsTextInputFocusManagerEnabled())
975 login_view_->RequestFocus();
976 login_view_->SetStatusAreaVisible(status_area_saved_visibility_);
977 login_view_->OnPostponedShow();
979 // We should reset this flag to allow changing of status area visibility.
980 initialize_webui_hidden_ = false;
983 void LoginDisplayHostImpl::StartPostponedWebUI() {
984 if (!is_wallpaper_loaded_) {
985 NOTREACHED();
986 return;
988 VLOG(1) << "Login WebUI >> Init postponed WebUI";
990 // Wallpaper has finished loading before StartWizard/StartSignInScreen has
991 // been called. In general this should not happen.
992 // Let go through normal code path when one of those will be called.
993 if (restore_path_ == RESTORE_UNKNOWN) {
994 NOTREACHED();
995 return;
998 switch (restore_path_) {
999 case RESTORE_WIZARD:
1000 StartWizard(first_screen_name_);
1001 break;
1002 case RESTORE_SIGN_IN:
1003 StartSignInScreen(LoginScreenContext());
1004 break;
1005 case RESTORE_ADD_USER_INTO_SESSION:
1006 StartUserAdding(completion_callback_);
1007 break;
1008 default:
1009 NOTREACHED();
1010 break;
1014 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1015 if (login_window_)
1016 return;
1018 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1019 views::FocusManager::set_arrow_key_traversal_enabled(true);
1020 // crbug.com/405859
1021 focus_ring_controller_.reset(new FocusRingController);
1022 focus_ring_controller_->SetVisible(true);
1024 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1027 views::Widget::InitParams params(
1028 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1029 params.bounds = background_bounds();
1030 params.show_state = ui::SHOW_STATE_FULLSCREEN;
1031 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1032 params.parent =
1033 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1034 ash::kShellWindowId_LockScreenContainer);
1035 login_window_ = new views::Widget;
1036 params.delegate = new LoginWidgetDelegate(login_window_);
1037 login_window_->Init(params);
1039 login_view_ = new WebUILoginView();
1040 login_view_->Init();
1041 if (login_view_->webui_visible())
1042 OnLoginPromptVisible();
1044 login_window_->SetVisibilityAnimationDuration(
1045 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1046 login_window_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
1048 login_window_->AddRemovalsObserver(this);
1049 login_window_->SetContentsView(login_view_);
1051 // If WebUI is initialized in hidden state, show it only if we're no
1052 // longer waiting for wallpaper animation/user images loading. Otherwise,
1053 // always show it.
1054 if (!initialize_webui_hidden_ ||
1055 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1056 VLOG(1) << "Login WebUI >> show login wnd on create";
1057 login_window_->Show();
1058 } else {
1059 VLOG(1) << "Login WebUI >> login wnd is hidden on create";
1060 login_view_->set_is_hidden(true);
1062 login_window_->GetNativeView()->SetName("WebUILoginView");
1065 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1066 if (!login_window_)
1067 return;
1068 login_window_->Close();
1069 login_window_ = NULL;
1071 if (!login_view_)
1072 return;
1073 login_view_->SetUIEnabled(true);
1074 login_view_ = NULL;
1077 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1078 auth_prewarmer_.reset();
1081 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1082 GetOobeUI()->ShowOobeUI(visible);
1085 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1086 if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1087 !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) {
1088 return;
1091 startup_sound_played_ = true;
1093 // Don't try play startup sound if login prompt is already visible
1094 // for a long time or can't be played.
1095 if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1096 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1097 EnableSystemSoundsForAccessibility();
1098 return;
1101 if (!startup_sound_honors_spoken_feedback_ &&
1102 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1103 EnableSystemSoundsForAccessibility();
1104 return;
1107 if (startup_sound_honors_spoken_feedback_ &&
1108 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1109 EnableSystemSoundsForAccessibility();
1110 return;
1113 base::MessageLoop::current()->PostDelayedTask(
1114 FROM_HERE,
1115 base::Bind(&EnableSystemSoundsForAccessibility),
1116 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1119 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1120 if (!login_prompt_visible_time_.is_null())
1121 return;
1122 login_prompt_visible_time_ = base::TimeTicks::Now();
1123 TryToPlayStartupSound();
1126 void LoginDisplayHostImpl::StartTimeZoneResolve() {
1127 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1128 chromeos::switches::kDisableTimeZoneTrackingOption)) {
1129 return;
1132 if (!g_browser_process->local_state()->GetBoolean(
1133 prefs::kResolveDeviceTimezoneByGeolocation)) {
1134 return;
1137 if (system::HasSystemTimezonePolicy())
1138 return;
1140 // Do not start resolver if we are inside active user session.
1141 // If user preferences permit, it will be started on preferences
1142 // initialization.
1143 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kLoginUser))
1144 return;
1146 g_browser_process->platform_part()->GetTimezoneResolver()->Start();
1149 ////////////////////////////////////////////////////////////////////////////////
1150 // external
1152 // Declared in login_wizard.h so that others don't need to depend on our .h.
1153 // TODO(nkostylev): Split this into a smaller functions.
1154 void ShowLoginWizard(const std::string& first_screen_name) {
1155 if (browser_shutdown::IsTryingToQuit())
1156 return;
1158 VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1160 chromeos::input_method::InputMethodManager* manager =
1161 chromeos::input_method::InputMethodManager::Get();
1163 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1164 // and US dvorak keyboard layouts.
1165 if (g_browser_process && g_browser_process->local_state()) {
1166 manager->GetActiveIMEState()->SetInputMethodLoginDefault();
1168 PrefService* prefs = g_browser_process->local_state();
1169 // Apply owner preferences for tap-to-click and mouse buttons swap for
1170 // login screen.
1171 system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1172 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1173 system::InputDeviceSettings::Get()->SetTapToClick(
1174 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1176 system::InputDeviceSettings::Get()->SetNaturalScroll(
1177 base::CommandLine::ForCurrentProcess()->HasSwitch(
1178 switches::kNaturalScrollDefault));
1180 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1182 g_browser_process->platform_part()->SessionManager()->SetSessionState(
1183 StartupUtils::IsOobeCompleted()
1184 ? session_manager::SESSION_STATE_LOGIN_PRIMARY
1185 : session_manager::SESSION_STATE_OOBE);
1187 LoginDisplayHostImpl* display_host = new LoginDisplayHostImpl(screen_bounds);
1189 bool show_app_launch_splash_screen =
1190 (first_screen_name == WizardController::kAppLaunchSplashScreenName);
1191 if (show_app_launch_splash_screen) {
1192 const std::string& auto_launch_app_id =
1193 KioskAppManager::Get()->GetAutoLaunchApp();
1194 const bool diagnostic_mode = false;
1195 const bool auto_launch = true;
1196 display_host->StartAppLaunch(auto_launch_app_id,
1197 diagnostic_mode,
1198 auto_launch);
1199 return;
1202 // Check whether we need to execute OOBE flow.
1203 const policy::EnrollmentConfig enrollment_config =
1204 g_browser_process->platform_part()
1205 ->browser_policy_connector_chromeos()
1206 ->GetPrescribedEnrollmentConfig();
1207 if (enrollment_config.should_enroll() && first_screen_name.empty()) {
1208 // Shows networks screen instead of enrollment screen to resume the
1209 // interrupted auto start enrollment flow because enrollment screen does
1210 // not handle flaky network. See http://crbug.com/332572
1211 display_host->StartWizard(WizardController::kNetworkScreenName);
1212 return;
1215 if (StartupUtils::IsEulaAccepted()) {
1216 DelayNetworkCall(
1217 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS),
1218 ServicesCustomizationDocument::GetInstance()
1219 ->EnsureCustomizationAppliedClosure());
1221 display_host->StartTimeZoneResolve();
1224 bool show_login_screen =
1225 (first_screen_name.empty() && StartupUtils::IsOobeCompleted()) ||
1226 first_screen_name == WizardController::kLoginScreenName;
1228 if (show_login_screen) {
1229 display_host->StartSignInScreen(LoginScreenContext());
1230 return;
1233 // Load startup manifest.
1234 const StartupCustomizationDocument* startup_manifest =
1235 StartupCustomizationDocument::GetInstance();
1237 // Switch to initial locale if specified by customization
1238 // and has not been set yet. We cannot call
1239 // LanguageSwitchMenu::SwitchLanguage here before
1240 // EmitLoginPromptReady.
1241 PrefService* prefs = g_browser_process->local_state();
1242 const std::string& current_locale =
1243 prefs->GetString(prefs::kApplicationLocale);
1244 VLOG(1) << "Current locale: " << current_locale;
1245 const std::string& locale = startup_manifest->initial_locale_default();
1247 const std::string& layout = startup_manifest->keyboard_layout();
1248 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1250 // Determine keyboard layout from OEM customization (if provided) or
1251 // initial locale and save it in preferences.
1252 manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale,
1253 layout);
1255 if (!current_locale.empty() || locale.empty()) {
1256 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1257 return;
1260 // Save initial locale from VPD/customization manifest as current
1261 // Chrome locale. Otherwise it will be lost if Chrome restarts.
1262 // Don't need to schedule pref save because setting initial local
1263 // will enforce preference saving.
1264 prefs->SetString(prefs::kApplicationLocale, locale);
1265 StartupUtils::SetInitialLocale(locale);
1267 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1268 new ShowLoginWizardSwitchLanguageCallbackData(
1269 first_screen_name, startup_manifest, display_host));
1271 locale_util::SwitchLanguageCallback callback(
1272 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass())));
1274 // Load locale keyboards here. Hardware layout would be automatically enabled.
1275 locale_util::SwitchLanguage(
1276 locale, true, true /* login_layouts_only */, callback);
1279 } // namespace chromeos