Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / login_display_host_impl.cc
blob772188d55a09f328c79eb0c9fb6491260bd77ea1
1 // Copyright (c) 2012 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/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/debug/trace_event.h"
17 #include "base/logging.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/browser_shutdown.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
28 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
29 #include "chrome/browser/chromeos/base/locale_util.h"
30 #include "chrome/browser/chromeos/boot_times_loader.h"
31 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
32 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
33 #include "chrome/browser/chromeos/first_run/first_run.h"
34 #include "chrome/browser/chromeos/input_method/input_method_util.h"
35 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
36 #include "chrome/browser/chromeos/language_preferences.h"
37 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
38 #include "chrome/browser/chromeos/login/existing_user_controller.h"
39 #include "chrome/browser/chromeos/login/helper.h"
40 #include "chrome/browser/chromeos/login/input_events_blocker.h"
41 #include "chrome/browser/chromeos/login/keyboard_driven_oobe_key_handler.h"
42 #include "chrome/browser/chromeos/login/login_utils.h"
43 #include "chrome/browser/chromeos/login/login_wizard.h"
44 #include "chrome/browser/chromeos/login/oobe_display.h"
45 #include "chrome/browser/chromeos/login/startup_utils.h"
46 #include "chrome/browser/chromeos/login/user_manager.h"
47 #include "chrome/browser/chromeos/login/webui_login_display.h"
48 #include "chrome/browser/chromeos/login/webui_login_view.h"
49 #include "chrome/browser/chromeos/login/wizard_controller.h"
50 #include "chrome/browser/chromeos/mobile_config.h"
51 #include "chrome/browser/chromeos/net/delay_network_call.h"
52 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
53 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
54 #include "chrome/browser/chromeos/system/input_device_settings.h"
55 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
56 #include "chrome/browser/lifetime/application_lifetime.h"
57 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
58 #include "chrome/common/chrome_constants.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/pref_names.h"
61 #include "chromeos/audio/chromeos_sounds.h"
62 #include "chromeos/chromeos_constants.h"
63 #include "chromeos/chromeos_switches.h"
64 #include "chromeos/dbus/dbus_thread_manager.h"
65 #include "chromeos/dbus/session_manager_client.h"
66 #include "chromeos/ime/extension_ime_util.h"
67 #include "chromeos/ime/input_method_manager.h"
68 #include "chromeos/login/login_state.h"
69 #include "chromeos/settings/timezone_settings.h"
70 #include "content/public/browser/notification_service.h"
71 #include "content/public/browser/notification_types.h"
72 #include "content/public/browser/render_frame_host.h"
73 #include "content/public/browser/web_contents.h"
74 #include "content/public/browser/web_ui.h"
75 #include "grit/browser_resources.h"
76 #include "media/audio/sounds/sounds_manager.h"
77 #include "ui/aura/window.h"
78 #include "ui/base/resource/resource_bundle.h"
79 #include "ui/compositor/layer.h"
80 #include "ui/compositor/layer_animation_observer.h"
81 #include "ui/compositor/scoped_layer_animation_settings.h"
82 #include "ui/events/event_utils.h"
83 #include "ui/gfx/rect.h"
84 #include "ui/gfx/transform.h"
85 #include "ui/keyboard/keyboard_controller.h"
86 #include "ui/views/focus/focus_manager.h"
87 #include "ui/views/widget/widget.h"
88 #include "ui/views/widget/widget_delegate.h"
89 #include "ui/wm/core/window_animations.h"
90 #include "url/gurl.h"
92 namespace {
94 // Maximum delay for startup sound after 'loginPromptVisible' signal.
95 const int kStartupSoundMaxDelayMs = 2000;
97 // URL which corresponds to the login WebUI.
98 const char kLoginURL[] = "chrome://oobe/login";
100 // URL which corresponds to the OOBE WebUI.
101 const char kOobeURL[] = "chrome://oobe/oobe";
103 // URL which corresponds to the user adding WebUI.
104 const char kUserAddingURL[] = "chrome://oobe/user-adding";
106 // URL which corresponds to the app launch splash WebUI.
107 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
109 // Duration of sign-in transition animation.
110 const int kLoginFadeoutTransitionDurationMs = 700;
112 // Number of times we try to reload OOBE/login WebUI if it crashes.
113 const int kCrashCountLimit = 5;
115 // Whether to enable tnitializing WebUI in hidden state (see
116 // |initialize_webui_hidden_|) by default.
117 const bool kHiddenWebUIInitializationDefault = true;
119 // Switch values that might be used to override WebUI init type.
120 const char kWebUIInitParallel[] = "parallel";
121 const char kWebUIInitPostpone[] = "postpone";
123 // The delay of triggering initialization of the device policy subsystem
124 // after the login screen is initialized. This makes sure that device policy
125 // network requests are made while the system is idle waiting for user input.
126 const int64 kPolicyServiceInitializationDelayMilliseconds = 100;
128 // Determines the hardware keyboard from the given locale code
129 // and the OEM layout information, and saves it to "Locale State".
130 // The information will be used in InputMethodUtil::GetHardwareInputMethodId().
131 void DetermineAndSaveHardwareKeyboard(const std::string& locale,
132 const std::string& oem_layout) {
133 chromeos::input_method::InputMethodManager* manager =
134 chromeos::input_method::InputMethodManager::Get();
135 std::string layout;
136 if (!oem_layout.empty()) {
137 // If the OEM layout information is provided, use it.
138 layout = oem_layout;
139 } else {
140 // Otherwise, determine the hardware keyboard from the locale.
141 std::vector<std::string> input_method_ids;
142 if (manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode(
143 locale,
144 chromeos::input_method::kKeyboardLayoutsOnly,
145 &input_method_ids)) {
146 // The output list |input_method_ids| is sorted by popularity, hence
147 // input_method_ids[0] now contains the most popular keyboard layout
148 // for the given locale.
149 layout = input_method_ids[0];
153 if (!layout.empty()) {
154 std::vector<std::string> layouts;
155 base::SplitString(layout, ',', &layouts);
156 manager->MigrateXkbInputMethods(&layouts);
158 PrefService* prefs = g_browser_process->local_state();
159 prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ","));
161 // This asks the file thread to save the prefs (i.e. doesn't block).
162 // The latest values of Local State reside in memory so we can safely
163 // get the value of kHardwareKeyboardLayout even if the data is not
164 // yet saved to disk.
165 prefs->CommitPendingWrite();
167 manager->GetInputMethodUtil()->UpdateHardwareLayoutCache();
168 manager->SetInputMethodLoginDefault();
172 // A class to observe an implicit animation and invokes the callback after the
173 // animation is completed.
174 class AnimationObserver : public ui::ImplicitAnimationObserver {
175 public:
176 explicit AnimationObserver(const base::Closure& callback)
177 : callback_(callback) {}
178 virtual ~AnimationObserver() {}
180 private:
181 // ui::ImplicitAnimationObserver implementation:
182 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
183 callback_.Run();
184 delete this;
187 base::Closure callback_;
189 DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
192 // ShowLoginWizard is split into two parts. This function is sometimes called
193 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback()
194 // (if locale was updated).
195 void ShowLoginWizardFinish(
196 const std::string& first_screen_name,
197 const chromeos::StartupCustomizationDocument* startup_manifest,
198 chromeos::LoginDisplayHost* display_host) {
199 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish");
201 scoped_ptr<base::DictionaryValue> params;
202 display_host->StartWizard(first_screen_name, params.Pass());
204 // Set initial timezone if specified by customization.
205 const std::string timezone_name = startup_manifest->initial_timezone();
206 VLOG(1) << "Initial time zone: " << timezone_name;
207 // Apply locale customizations only once to preserve whatever locale
208 // user has changed to during OOBE.
209 if (!timezone_name.empty()) {
210 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
211 base::UTF8ToUTF16(timezone_name));
215 struct ShowLoginWizardSwitchLanguageCallbackData {
216 explicit ShowLoginWizardSwitchLanguageCallbackData(
217 const std::string& first_screen_name,
218 const chromeos::StartupCustomizationDocument* startup_manifest,
219 chromeos::LoginDisplayHost* display_host)
220 : first_screen_name(first_screen_name),
221 startup_manifest(startup_manifest),
222 display_host(display_host) {}
224 const std::string first_screen_name;
225 const chromeos::StartupCustomizationDocument* const startup_manifest;
226 chromeos::LoginDisplayHost* const display_host;
228 // lock UI while resource bundle is being reloaded.
229 chromeos::InputEventsBlocker events_blocker;
232 void OnLanguageSwitchedCallback(
233 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
234 const std::string& locale,
235 const std::string& loaded_locale,
236 const bool success) {
237 if (!success)
238 LOG(WARNING) << "Locale could not be found for '" << locale << "'";
240 ShowLoginWizardFinish(
241 self->first_screen_name, self->startup_manifest, self->display_host);
244 void EnableSystemSoundsForAccessibility() {
245 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
248 void AddToSetIfIsGaiaAuthIframe(std::set<content::RenderFrameHost*>* frame_set,
249 content::RenderFrameHost* frame) {
250 content::RenderFrameHost* parent = frame->GetParent();
251 if (parent && parent->GetFrameName() == "signin-frame")
252 frame_set->insert(frame);
255 // A login implementation of WidgetDelegate.
256 class LoginWidgetDelegate : public views::WidgetDelegate {
257 public:
258 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
260 virtual ~LoginWidgetDelegate() {}
262 // Overridden from WidgetDelegate:
263 virtual void DeleteDelegate() OVERRIDE {
264 delete this;
266 virtual views::Widget* GetWidget() OVERRIDE {
267 return widget_;
269 virtual const views::Widget* GetWidget() const OVERRIDE {
270 return widget_;
272 virtual bool CanActivate() const OVERRIDE {
273 return true;
275 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE {
276 return true;
279 private:
280 views::Widget* widget_;
282 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
285 } // namespace
287 namespace chromeos {
289 // static
290 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
292 // static
293 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
295 // static
296 content::RenderFrameHost* LoginDisplayHostImpl::GetGaiaAuthIframe(
297 content::WebContents* web_contents) {
298 std::set<content::RenderFrameHost*> frame_set;
299 web_contents->ForEachFrame(
300 base::Bind(&AddToSetIfIsGaiaAuthIframe, &frame_set));
301 DCHECK_EQ(1U, frame_set.size());
302 return *frame_set.begin();
305 ////////////////////////////////////////////////////////////////////////////////
306 // LoginDisplayHostImpl, public
308 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
309 : background_bounds_(background_bounds),
310 pointer_factory_(this),
311 shutting_down_(false),
312 oobe_progress_bar_visible_(false),
313 session_starting_(false),
314 login_window_(NULL),
315 login_view_(NULL),
316 webui_login_display_(NULL),
317 is_showing_login_(false),
318 is_wallpaper_loaded_(false),
319 status_area_saved_visibility_(false),
320 crash_count_(0),
321 restore_path_(RESTORE_UNKNOWN),
322 finalize_animation_type_(ANIMATION_WORKSPACE),
323 animation_weak_ptr_factory_(this),
324 startup_sound_played_(false),
325 startup_sound_honors_spoken_feedback_(false),
326 is_observing_keyboard_(false) {
327 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
328 CrasAudioHandler::Get()->AddAudioObserver(this);
329 if (keyboard::KeyboardController::GetInstance()) {
330 keyboard::KeyboardController::GetInstance()->AddObserver(this);
331 is_observing_keyboard_ = true;
334 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
336 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
337 // because/ APP_TERMINATING will never be fired as long as this keeps
338 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
339 // browser instance that will block the shutdown.
340 registrar_.Add(this,
341 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
342 content::NotificationService::AllSources());
344 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
345 // not shown yet. Lock window has to be closed at this point so that
346 // a browser window exists and the window can acquire input focus.
347 registrar_.Add(this,
348 chrome::NOTIFICATION_BROWSER_OPENED,
349 content::NotificationService::AllSources());
351 // Login screen is moved to lock screen container when user logs in.
352 registrar_.Add(this,
353 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
354 content::NotificationService::AllSources());
356 DCHECK(default_host_ == NULL);
357 default_host_ = this;
359 // Make sure chrome won't exit while we are at login/oobe screen.
360 chrome::IncrementKeepAliveCount();
362 bool is_registered = StartupUtils::IsDeviceRegistered();
363 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
364 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch(
365 switches::kDisableBootAnimation);
367 waiting_for_wallpaper_load_ = !zero_delay_enabled &&
368 (!is_registered || !disable_boot_animation);
370 // For slower hardware we have boot animation disabled so
371 // we'll be initializing WebUI hidden, waiting for user pods to load and then
372 // show WebUI at once.
373 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_;
375 initialize_webui_hidden_ =
376 kHiddenWebUIInitializationDefault && !zero_delay_enabled;
378 // Check if WebUI init type is overriden.
379 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) {
380 const std::string override_type =
381 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
382 switches::kAshWebUIInit);
383 if (override_type == kWebUIInitParallel)
384 initialize_webui_hidden_ = true;
385 else if (override_type == kWebUIInitPostpone)
386 initialize_webui_hidden_ = false;
389 // Always postpone WebUI initialization on first boot, otherwise we miss
390 // initial animation.
391 if (!StartupUtils::IsOobeCompleted())
392 initialize_webui_hidden_ = false;
394 // There is no wallpaper for KioskMode, don't initialize the webui hidden.
395 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
396 initialize_webui_hidden_ = false;
398 if (waiting_for_wallpaper_load_) {
399 registrar_.Add(this,
400 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
401 content::NotificationService::AllSources());
404 // When we wait for WebUI to be initialized we wait for one of
405 // these notifications.
406 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
407 initialize_webui_hidden_) {
408 registrar_.Add(this,
409 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
410 content::NotificationService::AllSources());
411 registrar_.Add(this,
412 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
413 content::NotificationService::AllSources());
415 LOG(WARNING) << "Login WebUI >> "
416 << "zero_delay: " << zero_delay_enabled
417 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
418 << " wait_for_pods_: " << waiting_for_user_pods_
419 << " init_webui_hidden_: " << initialize_webui_hidden_;
421 media::SoundsManager* manager = media::SoundsManager::Get();
422 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
423 manager->Initialize(chromeos::SOUND_STARTUP,
424 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
427 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
428 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
429 CrasAudioHandler::Get()->RemoveAudioObserver(this);
430 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
431 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
432 is_observing_keyboard_ = false;
435 ash::Shell::GetInstance()->delegate()->
436 RemoveVirtualKeyboardStateObserver(this);
438 views::FocusManager::set_arrow_key_traversal_enabled(false);
439 ResetLoginWindowAndView();
441 // Let chrome process exit after login/oobe screen if needed.
442 chrome::DecrementKeepAliveCount();
444 default_host_ = NULL;
445 // TODO(tengs): This should be refactored. See crbug.com/314934.
446 if (UserManager::Get()->IsCurrentUserNew()) {
447 // DriveOptInController will delete itself when finished.
448 (new DriveFirstRunController(
449 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
453 ////////////////////////////////////////////////////////////////////////////////
454 // LoginDisplayHostImpl, LoginDisplayHost implementation:
456 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
457 LoginDisplay::Delegate* delegate) {
458 webui_login_display_ = new WebUILoginDisplay(delegate);
459 webui_login_display_->set_background_bounds(background_bounds());
460 return webui_login_display_;
463 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
464 return login_window_ ? login_window_->GetNativeWindow() : NULL;
467 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
468 return login_view_;
471 void LoginDisplayHostImpl::BeforeSessionStart() {
472 session_starting_ = true;
475 void LoginDisplayHostImpl::Finalize() {
476 DVLOG(1) << "Session starting";
477 if (ash::Shell::HasInstance()) {
478 ash::Shell::GetInstance()->
479 desktop_background_controller()->MoveDesktopToUnlockedContainer();
481 if (wizard_controller_.get())
482 wizard_controller_->OnSessionStart();
484 switch (finalize_animation_type_) {
485 case ANIMATION_NONE:
486 ShutdownDisplayHost(false);
487 break;
488 case ANIMATION_WORKSPACE:
489 if (ash::Shell::HasInstance())
490 ScheduleWorkspaceAnimation();
492 ShutdownDisplayHost(false);
493 break;
494 case ANIMATION_FADE_OUT:
495 // Display host is deleted once animation is completed
496 // since sign in screen widget has to stay alive.
497 ScheduleFadeOutAnimation();
498 break;
502 void LoginDisplayHostImpl::OnCompleteLogin() {
503 if (auto_enrollment_controller_)
504 auto_enrollment_controller_->Cancel();
507 void LoginDisplayHostImpl::OpenProxySettings() {
508 if (login_view_)
509 login_view_->OpenProxySettings();
512 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
513 if (initialize_webui_hidden_)
514 status_area_saved_visibility_ = visible;
515 else if (login_view_)
516 login_view_->SetStatusAreaVisible(visible);
519 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
520 if (!auto_enrollment_controller_) {
521 auto_enrollment_controller_.reset(new AutoEnrollmentController());
522 auto_enrollment_progress_subscription_ =
523 auto_enrollment_controller_->RegisterProgressCallback(
524 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress,
525 base::Unretained(this)));
527 return auto_enrollment_controller_.get();
530 void LoginDisplayHostImpl::StartWizard(
531 const std::string& first_screen_name,
532 scoped_ptr<base::DictionaryValue> screen_parameters) {
533 startup_sound_honors_spoken_feedback_ = true;
534 TryToPlayStartupSound();
536 // Keep parameters to restore if renderer crashes.
537 restore_path_ = RESTORE_WIZARD;
538 wizard_first_screen_name_ = first_screen_name;
539 if (screen_parameters.get())
540 wizard_screen_parameters_.reset(screen_parameters->DeepCopy());
541 else
542 wizard_screen_parameters_.reset();
543 is_showing_login_ = false;
545 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
546 LOG(WARNING) << "Login WebUI >> wizard postponed";
547 return;
549 LOG(WARNING) << "Login WebUI >> wizard";
551 if (!login_window_)
552 LoadURL(GURL(kOobeURL));
554 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
555 // Create and show the wizard.
556 // Note, dtor of the old WizardController should be called before ctor of the
557 // new one, because "default_controller()" is updated there. So pure "reset()"
558 // is done before new controller creation.
559 wizard_controller_.reset();
560 wizard_controller_.reset(CreateWizardController());
562 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
563 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
564 wizard_controller_->Init(first_screen_name, screen_parameters.Pass());
567 WizardController* LoginDisplayHostImpl::GetWizardController() {
568 return wizard_controller_.get();
571 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
572 return app_launch_controller_.get();
575 void LoginDisplayHostImpl::StartUserAdding(
576 const base::Closure& completion_callback) {
577 restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
578 completion_callback_ = completion_callback;
579 finalize_animation_type_ = ANIMATION_NONE;
580 LOG(WARNING) << "Login WebUI >> user adding";
581 if (!login_window_)
582 LoadURL(GURL(kUserAddingURL));
583 // We should emit this signal only at login screen (after reboot or sign out).
584 login_view_->set_should_emit_login_prompt_visible(false);
586 // Lock container can be transparent after lock screen animation.
587 aura::Window* lock_container = ash::Shell::GetContainer(
588 ash::Shell::GetPrimaryRootWindow(),
589 ash::kShellWindowId_LockScreenContainersContainer);
590 lock_container->layer()->SetOpacity(1.0);
592 ash::Shell::GetInstance()->
593 desktop_background_controller()->MoveDesktopToLockedContainer();
595 sign_in_controller_.reset(); // Only one controller in a time.
596 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
597 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
598 SetStatusAreaVisible(true);
599 sign_in_controller_->Init(
600 chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile());
601 CHECK(webui_login_display_);
602 GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
603 webui_login_display_,
604 webui_login_display_);
607 void LoginDisplayHostImpl::StartSignInScreen(
608 const LoginScreenContext& context) {
609 startup_sound_honors_spoken_feedback_ = true;
610 TryToPlayStartupSound();
612 restore_path_ = RESTORE_SIGN_IN;
613 is_showing_login_ = true;
614 finalize_animation_type_ = ANIMATION_WORKSPACE;
616 PrewarmAuthentication();
618 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
619 LOG(WARNING) << "Login WebUI >> sign in postponed";
620 return;
622 LOG(WARNING) << "Login WebUI >> sign in";
624 if (!login_window_) {
625 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
626 TRACE_EVENT_ASYNC_STEP_INTO0(
627 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
628 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen");
629 LoadURL(GURL(kLoginURL));
632 DVLOG(1) << "Starting sign in screen";
633 const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers();
635 // Fix for users who updated device and thus never passed register screen.
636 // If we already have users, we assume that it is not a second part of
637 // OOBE. See http://crosbug.com/6289
638 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
639 VLOG(1) << "Mark device registered because there are remembered users: "
640 << users.size();
641 StartupUtils::MarkDeviceRegistered();
644 sign_in_controller_.reset(); // Only one controller in a time.
645 sign_in_controller_.reset(new chromeos::ExistingUserController(this));
646 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
647 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
648 SetStatusAreaVisible(true);
649 sign_in_controller_->Init(users);
651 // We might be here after a reboot that was triggered after OOBE was complete,
652 // so check for auto-enrollment again. This might catch a cached decision from
653 // a previous oobe flow, or might start a new check with the server.
654 if (GetAutoEnrollmentController()->ShouldEnrollSilently())
655 sign_in_controller_->DoAutoEnrollment();
656 else
657 GetAutoEnrollmentController()->Start();
659 // Initiate mobile config load.
660 MobileConfig::GetInstance();
662 // Initiate device policy fetching.
663 policy::BrowserPolicyConnectorChromeOS* connector =
664 g_browser_process->platform_part()->browser_policy_connector_chromeos();
665 connector->ScheduleServiceInitialization(
666 kPolicyServiceInitializationDelayMilliseconds);
668 CHECK(webui_login_display_);
669 GetOobeUI()->ShowSigninScreen(context,
670 webui_login_display_,
671 webui_login_display_);
672 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
673 SetStatusAreaVisible(false);
674 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
675 "ShowLoginWebUI",
676 kShowLoginWebUIid,
677 "WaitForScreenStateInitialize");
678 BootTimesLoader::Get()->RecordCurrentStats(
679 "login-wait-for-signin-state-initialize");
682 void LoginDisplayHostImpl::ResumeSignInScreen() {
683 // We only get here after a previous call the StartSignInScreen. That sign-in
684 // was successful but was interrupted by an auto-enrollment execution; once
685 // auto-enrollment is complete we resume the normal login flow from here.
686 DVLOG(1) << "Resuming sign in screen";
687 CHECK(sign_in_controller_.get());
688 SetOobeProgressBarVisible(oobe_progress_bar_visible_);
689 SetStatusAreaVisible(true);
690 sign_in_controller_->ResumeLogin();
694 void LoginDisplayHostImpl::OnPreferencesChanged() {
695 if (is_showing_login_)
696 webui_login_display_->OnPreferencesChanged();
699 void LoginDisplayHostImpl::PrewarmAuthentication() {
700 auth_prewarmer_.reset(new AuthPrewarmer());
701 auth_prewarmer_->PrewarmAuthentication(
702 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
703 pointer_factory_.GetWeakPtr()));
706 void LoginDisplayHostImpl::StartDemoAppLaunch() {
707 LOG(WARNING) << "Login WebUI >> starting demo app.";
708 SetStatusAreaVisible(false);
710 demo_app_launcher_.reset(new DemoAppLauncher());
711 demo_app_launcher_->StartDemoAppLaunch();
714 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
715 bool diagnostic_mode) {
716 LOG(WARNING) << "Login WebUI >> start app launch.";
717 SetStatusAreaVisible(false);
718 finalize_animation_type_ = ANIMATION_FADE_OUT;
719 if (!login_window_)
720 LoadURL(GURL(kAppLaunchSplashURL));
722 login_view_->set_should_emit_login_prompt_visible(false);
724 app_launch_controller_.reset(new AppLaunchController(
725 app_id, diagnostic_mode, this, GetOobeUI()));
727 app_launch_controller_->StartAppLaunch();
730 ////////////////////////////////////////////////////////////////////////////////
731 // LoginDisplayHostImpl, public
733 WizardController* LoginDisplayHostImpl::CreateWizardController() {
734 // TODO(altimofeev): ensure that WebUI is ready.
735 OobeDisplay* oobe_display = GetOobeUI();
736 return new WizardController(this, oobe_display);
739 void LoginDisplayHostImpl::OnBrowserCreated() {
740 // Close lock window now so that the launched browser can receive focus.
741 ResetLoginWindowAndView();
744 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
745 if (!login_view_)
746 return NULL;
747 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
750 ////////////////////////////////////////////////////////////////////////////////
751 // LoginDisplayHostImpl, content:NotificationObserver implementation:
753 void LoginDisplayHostImpl::Observe(
754 int type,
755 const content::NotificationSource& source,
756 const content::NotificationDetails& details) {
757 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
758 LOG(WARNING) << "Login WebUI >> wp animation done";
759 is_wallpaper_loaded_ = true;
760 ash::Shell::GetInstance()->user_wallpaper_delegate()
761 ->OnWallpaperBootAnimationFinished();
762 if (waiting_for_wallpaper_load_) {
763 // StartWizard / StartSignInScreen could be called multiple times through
764 // the lifetime of host.
765 // Make sure that subsequent calls are not postponed.
766 waiting_for_wallpaper_load_ = false;
767 if (initialize_webui_hidden_)
768 ShowWebUI();
769 else
770 StartPostponedWebUI();
772 registrar_.Remove(this,
773 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
774 content::NotificationService::AllSources());
775 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
776 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
777 LOG(WARNING) << "Login WebUI >> WEBUI_VISIBLE";
778 if (waiting_for_user_pods_ && initialize_webui_hidden_) {
779 waiting_for_user_pods_ = false;
780 ShowWebUI();
781 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
782 // Reduce time till login UI is shown - show it as soon as possible.
783 waiting_for_wallpaper_load_ = false;
784 ShowWebUI();
786 registrar_.Remove(this,
787 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
788 content::NotificationService::AllSources());
789 registrar_.Remove(this,
790 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
791 content::NotificationService::AllSources());
792 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
793 ShutdownDisplayHost(true);
794 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
795 // Browsers created before session start (windows opened by extensions, for
796 // example) are ignored.
797 OnBrowserCreated();
798 registrar_.Remove(this,
799 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
800 content::NotificationService::AllSources());
801 registrar_.Remove(this,
802 chrome::NOTIFICATION_BROWSER_OPENED,
803 content::NotificationService::AllSources());
804 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
805 chromeos::UserManager::Get()->IsCurrentUserNew()) {
806 // For new user, move desktop to locker container so that windows created
807 // during the user image picker step are below it.
808 ash::Shell::GetInstance()->
809 desktop_background_controller()->MoveDesktopToLockedContainer();
810 registrar_.Remove(this,
811 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
812 content::NotificationService::AllSources());
816 ////////////////////////////////////////////////////////////////////////////////
817 // LoginDisplayHostImpl, WebContentsObserver implementation:
819 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
820 // Do not try to restore on shutdown
821 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
822 return;
824 crash_count_++;
825 if (crash_count_ > kCrashCountLimit)
826 return;
828 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
829 // Render with login screen crashed. Let's crash browser process to let
830 // session manager restart it properly. It is hard to reload the page
831 // and get to controlled state that is fully functional.
832 // If you see check, search for renderer crash for the same client.
833 LOG(FATAL) << "Renderer crash on login window";
837 ////////////////////////////////////////////////////////////////////////////////
838 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
839 // implementation:
841 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
842 OnLoginPromptVisible();
845 ////////////////////////////////////////////////////////////////////////////////
846 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
847 // implementation:
849 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
850 TryToPlayStartupSound();
853 ////////////////////////////////////////////////////////////////////////////////
854 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
855 // implementation:
857 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
858 if (keyboard::KeyboardController::GetInstance()) {
859 if (activated) {
860 if (!is_observing_keyboard_) {
861 keyboard::KeyboardController::GetInstance()->AddObserver(this);
862 is_observing_keyboard_ = true;
864 } else {
865 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
866 is_observing_keyboard_ = false;
871 ////////////////////////////////////////////////////////////////////////////////
872 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
873 // implementation:
875 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
876 const gfx::Rect& new_bounds) {
877 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
878 // Keyboard has been hidden.
879 if (webui_login_display_)
880 webui_login_display_->ShowControlBar(true);
881 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
882 // Keyboard has been shown.
883 if (webui_login_display_)
884 webui_login_display_->ShowControlBar(false);
887 keyboard_bounds_ = new_bounds;
890 ////////////////////////////////////////////////////////////////////////////////
891 // LoginDisplayHostImpl, private
893 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
894 if (shutting_down_)
895 return;
897 shutting_down_ = true;
898 registrar_.RemoveAll();
899 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
900 if (post_quit_task)
901 base::MessageLoop::current()->Quit();
903 if (!completion_callback_.is_null())
904 completion_callback_.Run();
907 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
908 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
909 ash::kShellWindowId_DesktopBackgroundContainer)
910 ->children()
911 .empty()) {
912 // If there is no background window, don't perform any animation on the
913 // default and background layer because there is nothing behind it.
914 return;
917 if (!CommandLine::ForCurrentProcess()->HasSwitch(
918 switches::kDisableLoginAnimations))
919 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
922 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
923 ui::Layer* layer = login_window_->GetLayer();
924 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
925 animation.AddObserver(new AnimationObserver(
926 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
927 animation_weak_ptr_factory_.GetWeakPtr(),
928 false)));
929 layer->SetOpacity(0);
932 void LoginDisplayHostImpl::OnAutoEnrollmentProgress(
933 policy::AutoEnrollmentState state) {
934 VLOG(1) << "OnAutoEnrollmentProgress, state " << state;
936 if (sign_in_controller_ &&
937 auto_enrollment_controller_->ShouldEnrollSilently()) {
938 sign_in_controller_->DoAutoEnrollment();
942 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
943 InitLoginWindowAndView();
944 // Subscribe to crash events.
945 content::WebContentsObserver::Observe(login_view_->GetWebContents());
946 login_view_->LoadURL(url);
948 // LoadURL could be called after the spring charger dialog shows, and
949 // take away the focus from it. Set the focus back to the charger dialog
950 // if it is visible.
951 // See crbug.com/328538.
952 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
955 void LoginDisplayHostImpl::ShowWebUI() {
956 if (!login_window_ || !login_view_) {
957 NOTREACHED();
958 return;
960 LOG(WARNING) << "Login WebUI >> Show already initialized UI";
961 login_window_->Show();
962 login_view_->GetWebContents()->Focus();
963 login_view_->SetStatusAreaVisible(status_area_saved_visibility_);
964 login_view_->OnPostponedShow();
966 // Login window could be shown after the spring charger dialog shows, and
967 // take away the focus from it. Set the focus back to the charger dialog
968 // if it is visible.
969 // See crbug.com/328538.
970 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
972 // We should reset this flag to allow changing of status area visibility.
973 initialize_webui_hidden_ = false;
976 void LoginDisplayHostImpl::StartPostponedWebUI() {
977 if (!is_wallpaper_loaded_) {
978 NOTREACHED();
979 return;
981 LOG(WARNING) << "Login WebUI >> Init postponed WebUI";
983 // Wallpaper has finished loading before StartWizard/StartSignInScreen has
984 // been called. In general this should not happen.
985 // Let go through normal code path when one of those will be called.
986 if (restore_path_ == RESTORE_UNKNOWN) {
987 NOTREACHED();
988 return;
991 switch (restore_path_) {
992 case RESTORE_WIZARD:
993 StartWizard(wizard_first_screen_name_,
994 wizard_screen_parameters_.Pass());
995 break;
996 case RESTORE_SIGN_IN:
997 StartSignInScreen(LoginScreenContext());
998 break;
999 case RESTORE_ADD_USER_INTO_SESSION:
1000 StartUserAdding(completion_callback_);
1001 break;
1002 default:
1003 NOTREACHED();
1004 break;
1008 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1009 if (login_window_)
1010 return;
1012 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1013 views::FocusManager::set_arrow_key_traversal_enabled(true);
1015 focus_ring_controller_.reset(new FocusRingController);
1016 focus_ring_controller_->SetVisible(true);
1018 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1021 views::Widget::InitParams params(
1022 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1023 params.bounds = background_bounds();
1024 params.show_state = ui::SHOW_STATE_MAXIMIZED;
1025 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1026 params.parent =
1027 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1028 ash::kShellWindowId_LockScreenContainer);
1030 login_window_ = new views::Widget;
1031 params.delegate = new LoginWidgetDelegate(login_window_);
1032 login_window_->Init(params);
1034 login_view_ = new WebUILoginView();
1035 login_view_->Init();
1036 if (login_view_->webui_visible())
1037 OnLoginPromptVisible();
1039 wm::SetWindowVisibilityAnimationDuration(
1040 login_window_->GetNativeView(),
1041 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1042 wm::SetWindowVisibilityAnimationTransition(
1043 login_window_->GetNativeView(),
1044 wm::ANIMATE_HIDE);
1046 login_window_->SetContentsView(login_view_);
1048 // If WebUI is initialized in hidden state, show it only if we're no
1049 // longer waiting for wallpaper animation/user images loading. Otherwise,
1050 // always show it.
1051 if (!initialize_webui_hidden_ ||
1052 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1053 LOG(WARNING) << "Login WebUI >> show login wnd on create";
1054 login_window_->Show();
1055 } else {
1056 LOG(WARNING) << "Login WebUI >> login wnd is hidden on create";
1057 login_view_->set_is_hidden(true);
1059 login_window_->GetNativeView()->SetName("WebUILoginView");
1062 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1063 if (!login_window_)
1064 return;
1065 login_window_->Close();
1066 login_window_ = NULL;
1067 login_view_ = NULL;
1070 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1071 auth_prewarmer_.reset();
1074 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1075 GetOobeUI()->ShowOobeUI(visible);
1078 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1079 if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1080 !CrasAudioHandler::Get()->GetActiveOutputNode()) {
1081 return;
1084 startup_sound_played_ = true;
1086 // Don't try play startup sound if login prompt is already visible
1087 // for a long time or can't be played.
1088 if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1089 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1090 EnableSystemSoundsForAccessibility();
1091 return;
1094 if (!startup_sound_honors_spoken_feedback_ &&
1095 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1096 EnableSystemSoundsForAccessibility();
1097 return;
1100 if (startup_sound_honors_spoken_feedback_ &&
1101 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1102 EnableSystemSoundsForAccessibility();
1103 return;
1106 base::MessageLoop::current()->PostDelayedTask(
1107 FROM_HERE,
1108 base::Bind(&EnableSystemSoundsForAccessibility),
1109 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1112 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1113 if (!login_prompt_visible_time_.is_null())
1114 return;
1115 login_prompt_visible_time_ = base::TimeTicks::Now();
1116 TryToPlayStartupSound();
1119 ////////////////////////////////////////////////////////////////////////////////
1120 // external
1122 // Declared in login_wizard.h so that others don't need to depend on our .h.
1123 // TODO(nkostylev): Split this into a smaller functions.
1124 void ShowLoginWizard(const std::string& first_screen_name) {
1125 if (browser_shutdown::IsTryingToQuit())
1126 return;
1128 VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1130 chromeos::input_method::InputMethodManager* manager =
1131 chromeos::input_method::InputMethodManager::Get();
1133 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1134 // and US dvorak keyboard layouts.
1135 if (g_browser_process && g_browser_process->local_state()) {
1136 manager->SetInputMethodLoginDefault();
1138 PrefService* prefs = g_browser_process->local_state();
1139 // Apply owner preferences for tap-to-click and mouse buttons swap for
1140 // login screen.
1141 system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1142 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1143 system::InputDeviceSettings::Get()->SetTapToClick(
1144 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1146 system::InputDeviceSettings::Get()->SetNaturalScroll(
1147 CommandLine::ForCurrentProcess()->HasSwitch(
1148 switches::kNaturalScrollDefault));
1150 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1152 // Check whether we need to execute OOBE process.
1153 bool oobe_complete = chromeos::StartupUtils::IsOobeCompleted();
1154 if (!oobe_complete) {
1155 LoginState::Get()->SetLoggedInState(
1156 LoginState::LOGGED_IN_OOBE, LoginState::LOGGED_IN_USER_NONE);
1157 } else {
1158 LoginState::Get()->SetLoggedInState(
1159 LoginState::LOGGED_IN_NONE, LoginState::LOGGED_IN_USER_NONE);
1162 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds);
1164 bool show_app_launch_splash_screen = (first_screen_name ==
1165 chromeos::WizardController::kAppLaunchSplashScreenName);
1166 if (show_app_launch_splash_screen) {
1167 const std::string& auto_launch_app_id =
1168 chromeos::KioskAppManager::Get()->GetAutoLaunchApp();
1169 display_host->StartAppLaunch(auto_launch_app_id,
1170 false /* diagnostic_mode */);
1171 return;
1174 policy::BrowserPolicyConnectorChromeOS* connector =
1175 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1176 bool should_show_enrollment_screen =
1177 first_screen_name.empty() && oobe_complete &&
1178 chromeos::WizardController::ShouldAutoStartEnrollment() &&
1179 !connector->IsEnterpriseManaged();
1180 if (should_show_enrollment_screen) {
1181 // Shows networks screen instead of enrollment screen to resume the
1182 // interrupted auto start enrollment flow because enrollment screen does
1183 // not handle flaky network. See http://crbug.com/332572
1184 display_host->StartWizard(chromeos::WizardController::kNetworkScreenName,
1185 scoped_ptr<base::DictionaryValue>());
1186 return;
1189 if (StartupUtils::IsEulaAccepted()) {
1190 DelayNetworkCall(
1191 ServicesCustomizationDocument::GetInstance()
1192 ->EnsureCustomizationAppliedClosure(),
1193 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS));
1196 bool show_login_screen =
1197 (first_screen_name.empty() && oobe_complete) ||
1198 first_screen_name == chromeos::WizardController::kLoginScreenName;
1200 if (show_login_screen) {
1201 // R11 > R12 migration fix. See http://crosbug.com/p/4898.
1202 // If user has manually changed locale during R11 OOBE, locale will be set.
1203 // On R12 > R12|R13 etc. this fix won't get activated since
1204 // OOBE process has set kApplicationLocale to non-default value.
1205 PrefService* prefs = g_browser_process->local_state();
1206 if (!prefs->HasPrefPath(prefs::kApplicationLocale)) {
1207 std::string locale = chromeos::StartupUtils::GetInitialLocale();
1208 prefs->SetString(prefs::kApplicationLocale, locale);
1209 manager->EnableLoginLayouts(
1210 locale,
1211 manager->GetInputMethodUtil()->GetHardwareInputMethodIds());
1212 base::ThreadRestrictions::ScopedAllowIO allow_io;
1213 const std::string loaded_locale =
1214 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale);
1215 g_browser_process->SetApplicationLocale(loaded_locale);
1217 display_host->StartSignInScreen(LoginScreenContext());
1218 return;
1221 // Load startup manifest.
1222 const chromeos::StartupCustomizationDocument* startup_manifest =
1223 chromeos::StartupCustomizationDocument::GetInstance();
1225 // Switch to initial locale if specified by customization
1226 // and has not been set yet. We cannot call
1227 // chromeos::LanguageSwitchMenu::SwitchLanguage here before
1228 // EmitLoginPromptReady.
1229 PrefService* prefs = g_browser_process->local_state();
1230 const std::string current_locale =
1231 prefs->GetString(prefs::kApplicationLocale);
1232 VLOG(1) << "Current locale: " << current_locale;
1233 std::string locale = startup_manifest->initial_locale_default();
1235 std::string layout = startup_manifest->keyboard_layout();
1236 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1238 // Determine keyboard layout from OEM customization (if provided) or
1239 // initial locale and save it in preferences.
1240 DetermineAndSaveHardwareKeyboard(locale, layout);
1242 if (!current_locale.empty() || locale.empty()) {
1243 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1244 return;
1247 // Save initial locale from VPD/customization manifest as current
1248 // Chrome locale. Otherwise it will be lost if Chrome restarts.
1249 // Don't need to schedule pref save because setting initial local
1250 // will enforce preference saving.
1251 prefs->SetString(prefs::kApplicationLocale, locale);
1252 chromeos::StartupUtils::SetInitialLocale(locale);
1254 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1255 new ShowLoginWizardSwitchLanguageCallbackData(
1256 first_screen_name, startup_manifest, display_host));
1258 scoped_ptr<locale_util::SwitchLanguageCallback> callback(
1259 new locale_util::SwitchLanguageCallback(
1260 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass()))));
1262 // Load locale keyboards here. Hardware layout would be automatically enabled.
1263 locale_util::SwitchLanguage(
1264 locale, true, true /* login_layouts_only */, callback.Pass());
1267 } // namespace chromeos