Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / chromeos / login / ui / login_display_host_impl.cc
blobae9d5658b54785dccebd2a9b6c24d4c10a5518a3
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/signin/token_handle_util.h"
41 #include "chrome/browser/chromeos/login/startup_utils.h"
42 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
43 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
44 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
45 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
46 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
47 #include "chrome/browser/chromeos/login/wizard_controller.h"
48 #include "chrome/browser/chromeos/mobile_config.h"
49 #include "chrome/browser/chromeos/net/delay_network_call.h"
50 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
51 #include "chrome/browser/chromeos/policy/enrollment_config.h"
52 #include "chrome/browser/chromeos/settings/cros_settings.h"
53 #include "chrome/browser/chromeos/system/device_disabling_manager.h"
54 #include "chrome/browser/chromeos/system/input_device_settings.h"
55 #include "chrome/browser/chromeos/system/timezone_util.h"
56 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
57 #include "chrome/browser/lifetime/application_lifetime.h"
58 #include "chrome/browser/profiles/profile_manager.h"
59 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
60 #include "chrome/common/chrome_constants.h"
61 #include "chrome/common/chrome_switches.h"
62 #include "chrome/common/pref_names.h"
63 #include "chrome/grit/browser_resources.h"
64 #include "chromeos/audio/chromeos_sounds.h"
65 #include "chromeos/chromeos_constants.h"
66 #include "chromeos/chromeos_switches.h"
67 #include "chromeos/dbus/dbus_thread_manager.h"
68 #include "chromeos/dbus/session_manager_client.h"
69 #include "chromeos/login/login_state.h"
70 #include "chromeos/settings/cros_settings_names.h"
71 #include "chromeos/settings/cros_settings_provider.h"
72 #include "chromeos/settings/timezone_settings.h"
73 #include "chromeos/timezone/timezone_resolver.h"
74 #include "components/session_manager/core/session_manager.h"
75 #include "components/user_manager/user.h"
76 #include "components/user_manager/user_manager.h"
77 #include "content/public/browser/notification_service.h"
78 #include "content/public/browser/notification_types.h"
79 #include "content/public/browser/web_contents.h"
80 #include "content/public/browser/web_ui.h"
81 #include "media/audio/sounds/sounds_manager.h"
82 #include "ui/aura/window.h"
83 #include "ui/base/ime/chromeos/extension_ime_util.h"
84 #include "ui/base/ime/chromeos/input_method_manager.h"
85 #include "ui/base/resource/resource_bundle.h"
86 #include "ui/compositor/layer.h"
87 #include "ui/compositor/layer_animation_observer.h"
88 #include "ui/compositor/scoped_layer_animation_settings.h"
89 #include "ui/events/event_utils.h"
90 #include "ui/gfx/display.h"
91 #include "ui/gfx/geometry/rect.h"
92 #include "ui/gfx/geometry/size.h"
93 #include "ui/gfx/screen.h"
94 #include "ui/gfx/transform.h"
95 #include "ui/keyboard/keyboard_controller.h"
96 #include "ui/keyboard/keyboard_util.h"
97 #include "ui/views/focus/focus_manager.h"
98 #include "ui/views/widget/widget.h"
99 #include "ui/views/widget/widget_delegate.h"
100 #include "url/gurl.h"
102 namespace {
104 // Maximum delay for startup sound after 'loginPromptVisible' signal.
105 const int kStartupSoundMaxDelayMs = 2000;
107 // URL which corresponds to the login WebUI.
108 const char kLoginURL[] = "chrome://oobe/login";
110 // URL which corresponds to the OOBE WebUI.
111 const char kOobeURL[] = "chrome://oobe/oobe";
113 // URL which corresponds to the user adding WebUI.
114 const char kUserAddingURL[] = "chrome://oobe/user-adding";
116 // URL which corresponds to the app launch splash WebUI.
117 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
119 // Duration of sign-in transition animation.
120 const int kLoginFadeoutTransitionDurationMs = 700;
122 // Number of times we try to reload OOBE/login WebUI if it crashes.
123 const int kCrashCountLimit = 5;
125 // Whether to enable tnitializing WebUI in hidden state (see
126 // |initialize_webui_hidden_|) by default.
127 const bool kHiddenWebUIInitializationDefault = true;
129 // Switch values that might be used to override WebUI init type.
130 const char kWebUIInitParallel[] = "parallel";
131 const char kWebUIInitPostpone[] = "postpone";
133 // The delay of triggering initialization of the device policy subsystem
134 // after the login screen is initialized. This makes sure that device policy
135 // network requests are made while the system is idle waiting for user input.
136 const int64 kPolicyServiceInitializationDelayMilliseconds = 100;
138 // A class to observe an implicit animation and invokes the callback after the
139 // animation is completed.
140 class AnimationObserver : public ui::ImplicitAnimationObserver {
141 public:
142 explicit AnimationObserver(const base::Closure& callback)
143 : callback_(callback) {}
144 ~AnimationObserver() override {}
146 private:
147 // ui::ImplicitAnimationObserver implementation:
148 void OnImplicitAnimationsCompleted() override {
149 callback_.Run();
150 delete this;
153 base::Closure callback_;
155 DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
158 // ShowLoginWizard is split into two parts. This function is sometimes called
159 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback()
160 // (if locale was updated).
161 void ShowLoginWizardFinish(
162 const std::string& first_screen_name,
163 const chromeos::StartupCustomizationDocument* startup_manifest,
164 chromeos::LoginDisplayHost* display_host) {
165 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish");
167 display_host->StartWizard(first_screen_name);
169 // Set initial timezone if specified by customization.
170 const std::string timezone_name = startup_manifest->initial_timezone();
171 VLOG(1) << "Initial time zone: " << timezone_name;
172 // Apply locale customizations only once to preserve whatever locale
173 // user has changed to during OOBE.
174 if (!timezone_name.empty()) {
175 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
176 base::UTF8ToUTF16(timezone_name));
180 struct ShowLoginWizardSwitchLanguageCallbackData {
181 explicit ShowLoginWizardSwitchLanguageCallbackData(
182 const std::string& first_screen_name,
183 const chromeos::StartupCustomizationDocument* startup_manifest,
184 chromeos::LoginDisplayHost* display_host)
185 : first_screen_name(first_screen_name),
186 startup_manifest(startup_manifest),
187 display_host(display_host) {}
189 const std::string first_screen_name;
190 const chromeos::StartupCustomizationDocument* const startup_manifest;
191 chromeos::LoginDisplayHost* const display_host;
193 // lock UI while resource bundle is being reloaded.
194 chromeos::InputEventsBlocker events_blocker;
197 void OnLanguageSwitchedCallback(
198 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
199 const chromeos::locale_util::LanguageSwitchResult& result) {
200 if (!result.success)
201 LOG(WARNING) << "Locale could not be found for '" << result.requested_locale
202 << "'";
204 ShowLoginWizardFinish(
205 self->first_screen_name, self->startup_manifest, self->display_host);
208 void EnableSystemSoundsForAccessibility() {
209 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
212 // A login implementation of WidgetDelegate.
213 class LoginWidgetDelegate : public views::WidgetDelegate {
214 public:
215 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
217 ~LoginWidgetDelegate() override {}
219 // Overridden from WidgetDelegate:
220 void DeleteDelegate() override { delete this; }
221 views::Widget* GetWidget() override { return widget_; }
222 const views::Widget* GetWidget() const override { return widget_; }
223 bool CanActivate() const override { return true; }
224 bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
226 private:
227 views::Widget* widget_;
229 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
232 // Disables virtual keyboard overscroll. Login UI will scroll user pods
233 // into view on JS side when virtual keyboard is shown.
234 void DisableKeyboardOverscroll() {
235 keyboard::SetKeyboardOverscrollOverride(
236 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
239 void ResetKeyboardOverscrollOverride() {
240 keyboard::SetKeyboardOverscrollOverride(
241 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
244 } // namespace
246 namespace chromeos {
248 // static
249 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
251 // static
252 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
254 ////////////////////////////////////////////////////////////////////////////////
255 // LoginDisplayHostImpl, public
257 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
258 : background_bounds_(background_bounds),
259 shutting_down_(false),
260 oobe_progress_bar_visible_(false),
261 session_starting_(false),
262 login_window_(NULL),
263 login_view_(NULL),
264 webui_login_display_(NULL),
265 is_showing_login_(false),
266 is_wallpaper_loaded_(false),
267 status_area_saved_visibility_(false),
268 crash_count_(0),
269 restore_path_(RESTORE_UNKNOWN),
270 finalize_animation_type_(ANIMATION_WORKSPACE),
271 startup_sound_played_(false),
272 startup_sound_honors_spoken_feedback_(false),
273 is_observing_keyboard_(false),
274 pointer_factory_(this),
275 animation_weak_ptr_factory_(this) {
276 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
277 CrasAudioHandler::Get()->AddAudioObserver(this);
278 if (keyboard::KeyboardController::GetInstance()) {
279 keyboard::KeyboardController::GetInstance()->AddObserver(this);
280 is_observing_keyboard_ = true;
283 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
284 ash::Shell::GetScreen()->AddObserver(this);
286 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
287 // because/ APP_TERMINATING will never be fired as long as this keeps
288 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
289 // browser instance that will block the shutdown.
290 registrar_.Add(this,
291 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
292 content::NotificationService::AllSources());
294 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
295 // not shown yet. Lock window has to be closed at this point so that
296 // a browser window exists and the window can acquire input focus.
297 registrar_.Add(this,
298 chrome::NOTIFICATION_BROWSER_OPENED,
299 content::NotificationService::AllSources());
301 // Login screen is moved to lock screen container when user logs in.
302 registrar_.Add(this,
303 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
304 content::NotificationService::AllSources());
306 DCHECK(default_host_ == NULL);
307 default_host_ = this;
309 // Make sure chrome won't exit while we are at login/oobe screen.
310 chrome::IncrementKeepAliveCount();
312 bool is_registered = StartupUtils::IsDeviceRegistered();
313 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
314 bool disable_boot_animation =
315 base::CommandLine::ForCurrentProcess()->HasSwitch(
316 switches::kDisableBootAnimation);
318 waiting_for_wallpaper_load_ = !zero_delay_enabled &&
319 (!is_registered || !disable_boot_animation);
321 // For slower hardware we have boot animation disabled so
322 // we'll be initializing WebUI hidden, waiting for user pods to load and then
323 // show WebUI at once.
324 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_;
326 initialize_webui_hidden_ =
327 kHiddenWebUIInitializationDefault && !zero_delay_enabled;
329 // Check if WebUI init type is overriden.
330 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
331 switches::kAshWebUIInit)) {
332 const std::string override_type =
333 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
334 switches::kAshWebUIInit);
335 if (override_type == kWebUIInitParallel)
336 initialize_webui_hidden_ = true;
337 else if (override_type == kWebUIInitPostpone)
338 initialize_webui_hidden_ = false;
341 // Always postpone WebUI initialization on first boot, otherwise we miss
342 // initial animation.
343 if (!StartupUtils::IsOobeCompleted())
344 initialize_webui_hidden_ = false;
346 if (waiting_for_wallpaper_load_) {
347 registrar_.Add(this,
348 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
349 content::NotificationService::AllSources());
352 // When we wait for WebUI to be initialized we wait for one of
353 // these notifications.
354 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
355 initialize_webui_hidden_) {
356 registrar_.Add(this,
357 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
358 content::NotificationService::AllSources());
359 registrar_.Add(this,
360 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
361 content::NotificationService::AllSources());
363 VLOG(1) << "Login WebUI >> "
364 << "zero_delay: " << zero_delay_enabled
365 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
366 << " wait_for_pods_: " << waiting_for_user_pods_
367 << " init_webui_hidden_: " << initialize_webui_hidden_;
369 media::SoundsManager* manager = media::SoundsManager::Get();
370 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
371 manager->Initialize(chromeos::SOUND_STARTUP,
372 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
374 // Disable Drag'n'Drop for the login session.
375 scoped_drag_drop_disabler_.reset(new aura::client::ScopedDragDropDisabler(
376 ash::Shell::GetPrimaryRootWindow()));
379 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
380 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
381 CrasAudioHandler::Get()->RemoveAudioObserver(this);
382 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
383 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
384 is_observing_keyboard_ = false;
387 ash::Shell::GetInstance()->delegate()->
388 RemoveVirtualKeyboardStateObserver(this);
389 ash::Shell::GetScreen()->RemoveObserver(this);
391 if (login_view_ && login_window_)
392 login_window_->RemoveRemovalsObserver(this);
394 ResetKeyboardOverscrollOverride();
396 views::FocusManager::set_arrow_key_traversal_enabled(false);
397 ResetLoginWindowAndView();
399 // Let chrome process exit after login/oobe screen if needed.
400 chrome::DecrementKeepAliveCount();
402 default_host_ = NULL;
403 // TODO(tengs): This should be refactored. See crbug.com/314934.
404 if (user_manager::UserManager::Get()->IsCurrentUserNew()) {
405 // DriveOptInController will delete itself when finished.
406 (new DriveFirstRunController(
407 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
411 ////////////////////////////////////////////////////////////////////////////////
412 // LoginDisplayHostImpl, LoginDisplayHost implementation:
414 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
415 LoginDisplay::Delegate* delegate) {
416 webui_login_display_ = new WebUILoginDisplay(delegate);
417 webui_login_display_->set_background_bounds(background_bounds());
418 return webui_login_display_;
421 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
422 return login_window_ ? login_window_->GetNativeWindow() : NULL;
425 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
426 return login_view_;
429 void LoginDisplayHostImpl::BeforeSessionStart() {
430 session_starting_ = true;
433 void LoginDisplayHostImpl::Finalize() {
434 DVLOG(1) << "Session starting";
435 if (ash::Shell::HasInstance()) {
436 ash::Shell::GetInstance()->
437 desktop_background_controller()->MoveDesktopToUnlockedContainer();
439 if (wizard_controller_.get())
440 wizard_controller_->OnSessionStart();
442 switch (finalize_animation_type_) {
443 case ANIMATION_NONE:
444 ShutdownDisplayHost(false);
445 break;
446 case ANIMATION_WORKSPACE:
447 if (ash::Shell::HasInstance())
448 ScheduleWorkspaceAnimation();
450 ShutdownDisplayHost(false);
451 break;
452 case ANIMATION_FADE_OUT:
453 // Display host is deleted once animation is completed
454 // since sign in screen widget has to stay alive.
455 ScheduleFadeOutAnimation();
456 break;
460 void LoginDisplayHostImpl::OnCompleteLogin() {
461 if (auto_enrollment_controller_)
462 auto_enrollment_controller_->Cancel();
465 void LoginDisplayHostImpl::OpenProxySettings() {
466 if (login_view_)
467 login_view_->OpenProxySettings();
470 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
471 if (initialize_webui_hidden_)
472 status_area_saved_visibility_ = visible;
473 else if (login_view_)
474 login_view_->SetStatusAreaVisible(visible);
477 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
478 if (!auto_enrollment_controller_)
479 auto_enrollment_controller_.reset(new AutoEnrollmentController());
480 return auto_enrollment_controller_.get();
483 void LoginDisplayHostImpl::StartWizard(const std::string& first_screen_name) {
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(GURL(kOobeURL));
503 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
504 // Create and show the wizard.
505 // Note, dtor of the old WizardController should be called before ctor of the
506 // new one, because "default_controller()" is updated there. So pure "reset()"
507 // is done before new controller creation.
508 wizard_controller_.reset();
509 wizard_controller_.reset(CreateWizardController());
511 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
512 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
513 wizard_controller_->Init(first_screen_name);
516 WizardController* LoginDisplayHostImpl::GetWizardController() {
517 return wizard_controller_.get();
520 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
521 return app_launch_controller_.get();
524 void LoginDisplayHostImpl::StartUserAdding(
525 const base::Closure& completion_callback) {
526 DisableKeyboardOverscroll();
528 restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
529 completion_callback_ = completion_callback;
530 finalize_animation_type_ = ANIMATION_NONE;
531 VLOG(1) << "Login WebUI >> user adding";
532 if (!login_window_)
533 LoadURL(GURL(kUserAddingURL));
534 // We should emit this signal only at login screen (after reboot or sign out).
535 login_view_->set_should_emit_login_prompt_visible(false);
537 // Lock container can be transparent after lock screen animation.
538 aura::Window* lock_container = ash::Shell::GetContainer(
539 ash::Shell::GetPrimaryRootWindow(),
540 ash::kShellWindowId_LockScreenContainersContainer);
541 lock_container->layer()->SetOpacity(1.0);
543 ash::Shell::GetInstance()->
544 desktop_background_controller()->MoveDesktopToLockedContainer();
546 existing_user_controller_.reset(); // Only one controller in a time.
547 existing_user_controller_.reset(new chromeos::ExistingUserController(this));
549 if (!signin_screen_controller_.get()) {
550 OobeDisplay* oobe_display = GetOobeUI();
551 signin_screen_controller_.reset(new SignInScreenController(
552 oobe_display, webui_login_display_->delegate()));
555 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
556 SetStatusAreaVisible(true);
557 existing_user_controller_->Init(
558 user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile());
559 CHECK(webui_login_display_);
560 GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
561 webui_login_display_,
562 webui_login_display_);
565 void LoginDisplayHostImpl::StartSignInScreen(
566 const LoginScreenContext& context) {
567 DisableKeyboardOverscroll();
569 startup_sound_honors_spoken_feedback_ = true;
570 TryToPlayStartupSound();
572 restore_path_ = RESTORE_SIGN_IN;
573 is_showing_login_ = true;
574 finalize_animation_type_ = ANIMATION_WORKSPACE;
576 PrewarmAuthentication();
578 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
579 VLOG(1) << "Login WebUI >> sign in postponed";
580 return;
582 VLOG(1) << "Login WebUI >> sign in";
584 if (!login_window_) {
585 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
586 TRACE_EVENT_ASYNC_STEP_INTO0(
587 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
588 BootTimesRecorder::Get()->RecordCurrentStats("login-start-signin-screen");
589 LoadURL(GURL(kLoginURL));
592 DVLOG(1) << "Starting sign in screen";
593 const user_manager::UserList& users =
594 user_manager::UserManager::Get()->GetUsers();
596 // Fix for users who updated device and thus never passed register screen.
597 // If we already have users, we assume that it is not a second part of
598 // OOBE. See http://crosbug.com/6289
599 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
600 VLOG(1) << "Mark device registered because there are remembered users: "
601 << users.size();
602 StartupUtils::MarkDeviceRegistered(base::Closure());
605 existing_user_controller_.reset(); // Only one controller in a time.
606 existing_user_controller_.reset(new chromeos::ExistingUserController(this));
608 if (!signin_screen_controller_.get()) {
609 OobeDisplay* oobe_display = GetOobeUI();
610 signin_screen_controller_.reset(new SignInScreenController(
611 oobe_display, webui_login_display_->delegate()));
614 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
615 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
616 SetStatusAreaVisible(true);
617 existing_user_controller_->Init(users);
619 // We might be here after a reboot that was triggered after OOBE was complete,
620 // so check for auto-enrollment again. This might catch a cached decision from
621 // a previous oobe flow, or might start a new check with the server.
622 GetAutoEnrollmentController()->Start();
624 // Initiate mobile config load.
625 MobileConfig::GetInstance();
627 // Initiate device policy fetching.
628 policy::BrowserPolicyConnectorChromeOS* connector =
629 g_browser_process->platform_part()->browser_policy_connector_chromeos();
630 connector->ScheduleServiceInitialization(
631 kPolicyServiceInitializationDelayMilliseconds);
633 CHECK(webui_login_display_);
634 GetOobeUI()->ShowSigninScreen(context,
635 webui_login_display_,
636 webui_login_display_);
637 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
638 "ShowLoginWebUI",
639 kShowLoginWebUIid,
640 "WaitForScreenStateInitialize");
641 BootTimesRecorder::Get()->RecordCurrentStats(
642 "login-wait-for-signin-state-initialize");
645 void LoginDisplayHostImpl::OnPreferencesChanged() {
646 if (is_showing_login_)
647 webui_login_display_->OnPreferencesChanged();
650 void LoginDisplayHostImpl::PrewarmAuthentication() {
651 auth_prewarmer_.reset(new AuthPrewarmer());
652 auth_prewarmer_->PrewarmAuthentication(
653 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
654 pointer_factory_.GetWeakPtr()));
657 void LoginDisplayHostImpl::StartDemoAppLaunch() {
658 VLOG(1) << "Login WebUI >> starting demo app.";
659 SetStatusAreaVisible(false);
661 demo_app_launcher_.reset(new DemoAppLauncher());
662 demo_app_launcher_->StartDemoAppLaunch();
665 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
666 bool diagnostic_mode,
667 bool auto_launch) {
668 VLOG(1) << "Login WebUI >> start app launch.";
669 SetStatusAreaVisible(false);
671 // Wait for the |CrosSettings| to become either trusted or permanently
672 // untrusted.
673 const CrosSettingsProvider::TrustedStatus status =
674 CrosSettings::Get()->PrepareTrustedValues(base::Bind(
675 &LoginDisplayHostImpl::StartAppLaunch,
676 pointer_factory_.GetWeakPtr(),
677 app_id,
678 diagnostic_mode,
679 auto_launch));
680 if (status == CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
681 return;
683 if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
684 // If the |CrosSettings| are permanently untrusted, refuse to launch a
685 // single-app kiosk mode session.
686 LOG(ERROR) << "Login WebUI >> Refusing to launch single-app kiosk mode.";
687 SetStatusAreaVisible(true);
688 return;
691 bool device_disabled = false;
692 CrosSettings::Get()->GetBoolean(kDeviceDisabled, &device_disabled);
693 if (device_disabled && system::DeviceDisablingManager::
694 HonorDeviceDisablingDuringNormalOperation()) {
695 // If the device is disabled, bail out. A device disabled screen will be
696 // shown by the DeviceDisablingManager.
697 return;
700 finalize_animation_type_ = ANIMATION_FADE_OUT;
701 if (!login_window_)
702 LoadURL(GURL(kAppLaunchSplashURL));
704 login_view_->set_should_emit_login_prompt_visible(false);
706 app_launch_controller_.reset(new AppLaunchController(
707 app_id, diagnostic_mode, this, GetOobeUI()));
709 app_launch_controller_->StartAppLaunch(auto_launch);
712 ////////////////////////////////////////////////////////////////////////////////
713 // LoginDisplayHostImpl, public
715 WizardController* LoginDisplayHostImpl::CreateWizardController() {
716 // TODO(altimofeev): ensure that WebUI is ready.
717 OobeDisplay* oobe_display = GetOobeUI();
718 return new WizardController(this, oobe_display);
721 void LoginDisplayHostImpl::OnBrowserCreated() {
722 // Close lock window now so that the launched browser can receive focus.
723 ResetLoginWindowAndView();
726 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
727 if (!login_view_)
728 return NULL;
729 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
732 ////////////////////////////////////////////////////////////////////////////////
733 // LoginDisplayHostImpl, content:NotificationObserver implementation:
735 void LoginDisplayHostImpl::Observe(
736 int type,
737 const content::NotificationSource& source,
738 const content::NotificationDetails& details) {
739 if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
740 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
741 VLOG(1) << "Login WebUI >> WEBUI_VISIBLE";
742 if (waiting_for_user_pods_ && initialize_webui_hidden_) {
743 waiting_for_user_pods_ = false;
744 ShowWebUI();
745 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
746 // Reduce time till login UI is shown - show it as soon as possible.
747 waiting_for_wallpaper_load_ = false;
748 ShowWebUI();
750 registrar_.Remove(this,
751 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
752 content::NotificationService::AllSources());
753 registrar_.Remove(this,
754 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
755 content::NotificationService::AllSources());
756 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
757 ShutdownDisplayHost(true);
758 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
759 // Browsers created before session start (windows opened by extensions, for
760 // example) are ignored.
761 OnBrowserCreated();
762 registrar_.Remove(this,
763 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
764 content::NotificationService::AllSources());
765 registrar_.Remove(this,
766 chrome::NOTIFICATION_BROWSER_OPENED,
767 content::NotificationService::AllSources());
768 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
769 user_manager::UserManager::Get()->IsCurrentUserNew()) {
770 // For new user, move desktop to locker container so that windows created
771 // during the user image picker step are below it.
772 ash::Shell::GetInstance()->
773 desktop_background_controller()->MoveDesktopToLockedContainer();
774 registrar_.Remove(this,
775 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
776 content::NotificationService::AllSources());
777 } else if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
778 VLOG(1) << "Login WebUI >> wp animation done";
779 is_wallpaper_loaded_ = true;
780 ash::Shell::GetInstance()->user_wallpaper_delegate()
781 ->OnWallpaperBootAnimationFinished();
782 if (waiting_for_wallpaper_load_) {
783 // StartWizard / StartSignInScreen could be called multiple times through
784 // the lifetime of host.
785 // Make sure that subsequent calls are not postponed.
786 waiting_for_wallpaper_load_ = false;
787 if (initialize_webui_hidden_)
788 ShowWebUI();
789 else
790 StartPostponedWebUI();
792 registrar_.Remove(this,
793 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
794 content::NotificationService::AllSources());
798 ////////////////////////////////////////////////////////////////////////////////
799 // LoginDisplayHostImpl, WebContentsObserver implementation:
801 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
802 // Do not try to restore on shutdown
803 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
804 return;
806 crash_count_++;
807 if (crash_count_ > kCrashCountLimit)
808 return;
810 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
811 // Render with login screen crashed. Let's crash browser process to let
812 // session manager restart it properly. It is hard to reload the page
813 // and get to controlled state that is fully functional.
814 // If you see check, search for renderer crash for the same client.
815 LOG(FATAL) << "Renderer crash on login window";
819 ////////////////////////////////////////////////////////////////////////////////
820 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
821 // implementation:
823 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
824 OnLoginPromptVisible();
827 ////////////////////////////////////////////////////////////////////////////////
828 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
829 // implementation:
831 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
832 TryToPlayStartupSound();
835 ////////////////////////////////////////////////////////////////////////////////
836 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
837 // implementation:
839 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
840 if (keyboard::KeyboardController::GetInstance()) {
841 if (activated) {
842 if (!is_observing_keyboard_) {
843 keyboard::KeyboardController::GetInstance()->AddObserver(this);
844 is_observing_keyboard_ = true;
846 } else {
847 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
848 is_observing_keyboard_ = false;
853 ////////////////////////////////////////////////////////////////////////////////
854 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
855 // implementation:
857 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
858 const gfx::Rect& new_bounds) {
859 if (new_bounds.IsEmpty()) {
860 // Keyboard has been hidden.
861 if (GetOobeUI())
862 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
863 } else if (!new_bounds.IsEmpty()) {
864 // Keyboard has been shown.
865 if (GetOobeUI())
866 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
870 ////////////////////////////////////////////////////////////////////////////////
871 // LoginDisplayHostImpl, gfx::DisplayObserver implementation:
873 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) {
876 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) {
879 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display,
880 uint32_t changed_metrics) {
881 gfx::Display primary_display =
882 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
883 if (display.id() != primary_display.id() ||
884 !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
885 return;
888 if (GetOobeUI()) {
889 const gfx::Size& size = primary_display.size();
890 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(),
891 size.height());
895 ////////////////////////////////////////////////////////////////////////////////
896 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation:
897 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget,
898 views::View* view) {
899 if (view != static_cast<views::View*>(login_view_))
900 return;
901 login_view_ = NULL;
902 widget->RemoveRemovalsObserver(this);
905 ////////////////////////////////////////////////////////////////////////////////
906 // LoginDisplayHostImpl, private
908 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
909 if (shutting_down_)
910 return;
912 shutting_down_ = true;
913 registrar_.RemoveAll();
914 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
915 if (post_quit_task)
916 base::MessageLoop::current()->Quit();
918 if (!completion_callback_.is_null())
919 completion_callback_.Run();
922 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
923 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
924 ash::kShellWindowId_DesktopBackgroundContainer)
925 ->children()
926 .empty()) {
927 // If there is no background window, don't perform any animation on the
928 // default and background layer because there is nothing behind it.
929 return;
932 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
933 switches::kDisableLoginAnimations))
934 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
937 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
938 ui::Layer* layer = login_window_->GetLayer();
939 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
940 animation.AddObserver(new AnimationObserver(
941 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
942 animation_weak_ptr_factory_.GetWeakPtr(),
943 false)));
944 layer->SetOpacity(0);
947 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
948 InitLoginWindowAndView();
949 // Subscribe to crash events.
950 content::WebContentsObserver::Observe(login_view_->GetWebContents());
951 login_view_->LoadURL(url);
954 void LoginDisplayHostImpl::ShowWebUI() {
955 if (!login_window_ || !login_view_) {
956 NOTREACHED();
957 return;
959 VLOG(1) << "Login WebUI >> Show already initialized UI";
960 login_window_->Show();
961 login_view_->GetWebContents()->Focus();
962 login_view_->SetStatusAreaVisible(status_area_saved_visibility_);
963 login_view_->OnPostponedShow();
965 // We should reset this flag to allow changing of status area visibility.
966 initialize_webui_hidden_ = false;
969 void LoginDisplayHostImpl::StartPostponedWebUI() {
970 if (!is_wallpaper_loaded_) {
971 NOTREACHED();
972 return;
974 VLOG(1) << "Login WebUI >> Init postponed WebUI";
976 // Wallpaper has finished loading before StartWizard/StartSignInScreen has
977 // been called. In general this should not happen.
978 // Let go through normal code path when one of those will be called.
979 if (restore_path_ == RESTORE_UNKNOWN) {
980 NOTREACHED();
981 return;
984 switch (restore_path_) {
985 case RESTORE_WIZARD:
986 StartWizard(first_screen_name_);
987 break;
988 case RESTORE_SIGN_IN:
989 StartSignInScreen(LoginScreenContext());
990 break;
991 case RESTORE_ADD_USER_INTO_SESSION:
992 StartUserAdding(completion_callback_);
993 break;
994 default:
995 NOTREACHED();
996 break;
1000 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1001 if (login_window_)
1002 return;
1004 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1005 views::FocusManager::set_arrow_key_traversal_enabled(true);
1006 // crbug.com/405859
1007 focus_ring_controller_.reset(new FocusRingController);
1008 focus_ring_controller_->SetVisible(true);
1010 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1013 views::Widget::InitParams params(
1014 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1015 params.bounds = background_bounds();
1016 params.show_state = ui::SHOW_STATE_FULLSCREEN;
1017 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1018 params.parent =
1019 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1020 ash::kShellWindowId_LockScreenContainer);
1021 login_window_ = new views::Widget;
1022 params.delegate = new LoginWidgetDelegate(login_window_);
1023 login_window_->Init(params);
1025 login_view_ = new WebUILoginView();
1026 login_view_->Init();
1027 if (login_view_->webui_visible())
1028 OnLoginPromptVisible();
1030 login_window_->SetVisibilityAnimationDuration(
1031 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1032 login_window_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
1034 login_window_->AddRemovalsObserver(this);
1035 login_window_->SetContentsView(login_view_);
1037 // If WebUI is initialized in hidden state, show it only if we're no
1038 // longer waiting for wallpaper animation/user images loading. Otherwise,
1039 // always show it.
1040 if (!initialize_webui_hidden_ ||
1041 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1042 VLOG(1) << "Login WebUI >> show login wnd on create";
1043 login_window_->Show();
1044 } else {
1045 VLOG(1) << "Login WebUI >> login wnd is hidden on create";
1046 login_view_->set_is_hidden(true);
1048 login_window_->GetNativeView()->SetName("WebUILoginView");
1051 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1052 if (!login_window_)
1053 return;
1054 login_window_->Close();
1055 login_window_ = NULL;
1057 if (!login_view_)
1058 return;
1059 login_view_->SetUIEnabled(true);
1060 login_view_ = NULL;
1063 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1064 auth_prewarmer_.reset();
1067 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1068 GetOobeUI()->ShowOobeUI(visible);
1071 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1072 if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1073 !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) {
1074 return;
1077 startup_sound_played_ = true;
1079 // Don't try play startup sound if login prompt is already visible
1080 // for a long time or can't be played.
1081 if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1082 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1083 EnableSystemSoundsForAccessibility();
1084 return;
1087 if (!startup_sound_honors_spoken_feedback_ &&
1088 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1089 EnableSystemSoundsForAccessibility();
1090 return;
1093 if (startup_sound_honors_spoken_feedback_ &&
1094 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1095 EnableSystemSoundsForAccessibility();
1096 return;
1099 base::MessageLoop::current()->PostDelayedTask(
1100 FROM_HERE,
1101 base::Bind(&EnableSystemSoundsForAccessibility),
1102 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1105 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1106 if (!login_prompt_visible_time_.is_null())
1107 return;
1108 login_prompt_visible_time_ = base::TimeTicks::Now();
1109 TryToPlayStartupSound();
1112 void LoginDisplayHostImpl::StartTimeZoneResolve() {
1113 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1114 chromeos::switches::kDisableTimeZoneTrackingOption)) {
1115 return;
1118 if (!g_browser_process->local_state()->GetBoolean(
1119 prefs::kResolveDeviceTimezoneByGeolocation)) {
1120 return;
1123 if (system::HasSystemTimezonePolicy())
1124 return;
1126 // Do not start resolver if we are inside active user session.
1127 // If user preferences permit, it will be started on preferences
1128 // initialization.
1129 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kLoginUser))
1130 return;
1132 g_browser_process->platform_part()->GetTimezoneResolver()->Start();
1135 ////////////////////////////////////////////////////////////////////////////////
1136 // external
1138 // Declared in login_wizard.h so that others don't need to depend on our .h.
1139 // TODO(nkostylev): Split this into a smaller functions.
1140 void ShowLoginWizard(const std::string& first_screen_name) {
1141 if (browser_shutdown::IsTryingToQuit())
1142 return;
1144 VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1146 chromeos::input_method::InputMethodManager* manager =
1147 chromeos::input_method::InputMethodManager::Get();
1149 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1150 // and US dvorak keyboard layouts.
1151 if (g_browser_process && g_browser_process->local_state()) {
1152 manager->GetActiveIMEState()->SetInputMethodLoginDefault();
1154 PrefService* prefs = g_browser_process->local_state();
1155 // Apply owner preferences for tap-to-click and mouse buttons swap for
1156 // login screen.
1157 system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1158 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1159 system::InputDeviceSettings::Get()->SetTapToClick(
1160 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1162 system::InputDeviceSettings::Get()->SetNaturalScroll(
1163 base::CommandLine::ForCurrentProcess()->HasSwitch(
1164 switches::kNaturalScrollDefault));
1166 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1168 g_browser_process->platform_part()->SessionManager()->SetSessionState(
1169 StartupUtils::IsOobeCompleted()
1170 ? session_manager::SESSION_STATE_LOGIN_PRIMARY
1171 : session_manager::SESSION_STATE_OOBE);
1173 LoginDisplayHostImpl* display_host = new LoginDisplayHostImpl(screen_bounds);
1175 bool show_app_launch_splash_screen =
1176 (first_screen_name == WizardController::kAppLaunchSplashScreenName);
1177 if (show_app_launch_splash_screen) {
1178 const std::string& auto_launch_app_id =
1179 KioskAppManager::Get()->GetAutoLaunchApp();
1180 const bool diagnostic_mode = false;
1181 const bool auto_launch = true;
1182 display_host->StartAppLaunch(auto_launch_app_id,
1183 diagnostic_mode,
1184 auto_launch);
1185 return;
1188 // Check whether we need to execute OOBE flow.
1189 const policy::EnrollmentConfig enrollment_config =
1190 g_browser_process->platform_part()
1191 ->browser_policy_connector_chromeos()
1192 ->GetPrescribedEnrollmentConfig();
1193 if (enrollment_config.should_enroll() && first_screen_name.empty()) {
1194 // Shows networks screen instead of enrollment screen to resume the
1195 // interrupted auto start enrollment flow because enrollment screen does
1196 // not handle flaky network. See http://crbug.com/332572
1197 display_host->StartWizard(WizardController::kNetworkScreenName);
1198 return;
1201 if (StartupUtils::IsEulaAccepted()) {
1202 DelayNetworkCall(
1203 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS),
1204 ServicesCustomizationDocument::GetInstance()
1205 ->EnsureCustomizationAppliedClosure());
1207 display_host->StartTimeZoneResolve();
1210 bool show_login_screen =
1211 (first_screen_name.empty() && StartupUtils::IsOobeCompleted()) ||
1212 first_screen_name == WizardController::kLoginScreenName;
1214 if (show_login_screen) {
1215 display_host->StartSignInScreen(LoginScreenContext());
1216 return;
1219 // Load startup manifest.
1220 const StartupCustomizationDocument* startup_manifest =
1221 StartupCustomizationDocument::GetInstance();
1223 // Switch to initial locale if specified by customization
1224 // and has not been set yet. We cannot call
1225 // LanguageSwitchMenu::SwitchLanguage here before
1226 // EmitLoginPromptReady.
1227 PrefService* prefs = g_browser_process->local_state();
1228 const std::string& current_locale =
1229 prefs->GetString(prefs::kApplicationLocale);
1230 VLOG(1) << "Current locale: " << current_locale;
1231 const std::string& locale = startup_manifest->initial_locale_default();
1233 const std::string& layout = startup_manifest->keyboard_layout();
1234 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1236 // Determine keyboard layout from OEM customization (if provided) or
1237 // initial locale and save it in preferences.
1238 manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale,
1239 layout);
1241 if (!current_locale.empty() || locale.empty()) {
1242 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1243 return;
1246 // Save initial locale from VPD/customization manifest as current
1247 // Chrome locale. Otherwise it will be lost if Chrome restarts.
1248 // Don't need to schedule pref save because setting initial local
1249 // will enforce preference saving.
1250 prefs->SetString(prefs::kApplicationLocale, locale);
1251 StartupUtils::SetInitialLocale(locale);
1253 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1254 new ShowLoginWizardSwitchLanguageCallbackData(
1255 first_screen_name, startup_manifest, display_host));
1257 locale_util::SwitchLanguageCallback callback(
1258 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass())));
1260 // Load locale keyboards here. Hardware layout would be automatically enabled.
1261 locale_util::SwitchLanguage(locale, true, true /* login_layouts_only */,
1262 callback, ProfileManager::GetActiveUserProfile());
1265 } // namespace chromeos