Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / ui / login_display_host_impl.cc
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.
4
5 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/browser_shutdown.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
23 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
24 #include "chrome/browser/chromeos/base/locale_util.h"
25 #include "chrome/browser/chromeos/boot_times_loader.h"
26 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
27 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
28 #include "chrome/browser/chromeos/first_run/first_run.h"
29 #include "chrome/browser/chromeos/input_method/input_method_util.h"
30 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
31 #include "chrome/browser/chromeos/language_preferences.h"
32 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
33 #include "chrome/browser/chromeos/login/existing_user_controller.h"
34 #include "chrome/browser/chromeos/login/helper.h"
35 #include "chrome/browser/chromeos/login/login_utils.h"
36 #include "chrome/browser/chromeos/login/login_wizard.h"
37 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
38 #include "chrome/browser/chromeos/login/startup_utils.h"
39 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
40 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
41 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
42 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
43 #include "chrome/browser/chromeos/login/wizard_controller.h"
44 #include "chrome/browser/chromeos/mobile_config.h"
45 #include "chrome/browser/chromeos/net/delay_network_call.h"
46 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
47 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
48 #include "chrome/browser/chromeos/system/input_device_settings.h"
49 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
50 #include "chrome/browser/lifetime/application_lifetime.h"
51 #include "chrome/browser/profiles/profile_manager.h"
52 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
53 #include "chrome/common/chrome_constants.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/pref_names.h"
56 #include "chrome/grit/browser_resources.h"
57 #include "chromeos/audio/chromeos_sounds.h"
58 #include "chromeos/chromeos_constants.h"
59 #include "chromeos/chromeos_switches.h"
60 #include "chromeos/dbus/dbus_thread_manager.h"
61 #include "chromeos/dbus/session_manager_client.h"
62 #include "chromeos/ime/extension_ime_util.h"
63 #include "chromeos/ime/input_method_manager.h"
64 #include "chromeos/login/login_state.h"
65 #include "chromeos/settings/timezone_settings.h"
66 #include "components/session_manager/core/session_manager.h"
67 #include "components/user_manager/user_manager.h"
68 #include "content/public/browser/notification_service.h"
69 #include "content/public/browser/notification_types.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_ui.h"
72 #include "media/audio/sounds/sounds_manager.h"
73 #include "ui/aura/window.h"
74 #include "ui/base/resource/resource_bundle.h"
75 #include "ui/base/ui_base_switches_util.h"
76 #include "ui/compositor/layer.h"
77 #include "ui/compositor/layer_animation_observer.h"
78 #include "ui/compositor/scoped_layer_animation_settings.h"
79 #include "ui/events/event_utils.h"
80 #include "ui/gfx/display.h"
81 #include "ui/gfx/rect.h"
82 #include "ui/gfx/screen.h"
83 #include "ui/gfx/size.h"
84 #include "ui/gfx/transform.h"
85 #include "ui/keyboard/keyboard_controller.h"
86 #include "ui/keyboard/keyboard_util.h"
87 #include "ui/views/focus/focus_manager.h"
88 #include "ui/views/widget/widget.h"
89 #include "ui/views/widget/widget_delegate.h"
90 #include "url/gurl.h"
91
92 #if !defined(USE_ATHENA)
93 #include "ash/audio/sounds.h"
94 #include "ash/desktop_background/desktop_background_controller.h"
95 #include "ash/desktop_background/user_wallpaper_delegate.h"
96 #include "ash/shell.h"
97 #include "ash/shell_window_ids.h"
98 #include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
99 #endif
100
101 #if defined(USE_ATHENA)
102 #include "athena/screen/public/screen_manager.h"
103 #include "athena/util/container_priorities.h"
104 #include "athena/util/fill_layout_manager.h"
105 #endif
106
107 namespace {
108
109 // Maximum delay for startup sound after 'loginPromptVisible' signal.
110 const int kStartupSoundMaxDelayMs = 2000;
111
112 // URL which corresponds to the login WebUI.
113 const char kLoginURL[] = "chrome://oobe/login";
114
115 // URL which corresponds to the OOBE WebUI.
116 const char kOobeURL[] = "chrome://oobe/oobe";
117
118 // URL which corresponds to the user adding WebUI.
119 const char kUserAddingURL[] = "chrome://oobe/user-adding";
120
121 // URL which corresponds to the app launch splash WebUI.
122 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
123
124 // Duration of sign-in transition animation.
125 const int kLoginFadeoutTransitionDurationMs = 700;
126
127 // Number of times we try to reload OOBE/login WebUI if it crashes.
128 const int kCrashCountLimit = 5;
129
130 // Whether to enable tnitializing WebUI in hidden state (see
131 // |initialize_webui_hidden_|) by default.
132 const bool kHiddenWebUIInitializationDefault = true;
133
134 // Switch values that might be used to override WebUI init type.
135 const char kWebUIInitParallel[] = "parallel";
136 const char kWebUIInitPostpone[] = "postpone";
137
138 // The delay of triggering initialization of the device policy subsystem
139 // after the login screen is initialized. This makes sure that device policy
140 // network requests are made while the system is idle waiting for user input.
141 const int64 kPolicyServiceInitializationDelayMilliseconds = 100;
142
143 // A class to observe an implicit animation and invokes the callback after the
144 // animation is completed.
145 class AnimationObserver : public ui::ImplicitAnimationObserver {
146  public:
147   explicit AnimationObserver(const base::Closure& callback)
148       : callback_(callback) {}
149   virtual ~AnimationObserver() {}
150
151  private:
152   // ui::ImplicitAnimationObserver implementation:
153   virtual void OnImplicitAnimationsCompleted() override {
154     callback_.Run();
155     delete this;
156   }
157
158   base::Closure callback_;
159
160   DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
161 };
162
163 // ShowLoginWizard is split into two parts. This function is sometimes called
164 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback()
165 // (if locale was updated).
166 void ShowLoginWizardFinish(
167     const std::string& first_screen_name,
168     const chromeos::StartupCustomizationDocument* startup_manifest,
169     chromeos::LoginDisplayHost* display_host) {
170   TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish");
171
172   scoped_ptr<base::DictionaryValue> params;
173   display_host->StartWizard(first_screen_name, params.Pass());
174
175   // Set initial timezone if specified by customization.
176   const std::string timezone_name = startup_manifest->initial_timezone();
177   VLOG(1) << "Initial time zone: " << timezone_name;
178   // Apply locale customizations only once to preserve whatever locale
179   // user has changed to during OOBE.
180   if (!timezone_name.empty()) {
181     chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
182         base::UTF8ToUTF16(timezone_name));
183   }
184 }
185
186 struct ShowLoginWizardSwitchLanguageCallbackData {
187   explicit ShowLoginWizardSwitchLanguageCallbackData(
188       const std::string& first_screen_name,
189       const chromeos::StartupCustomizationDocument* startup_manifest,
190       chromeos::LoginDisplayHost* display_host)
191       : first_screen_name(first_screen_name),
192         startup_manifest(startup_manifest),
193         display_host(display_host) {}
194
195   const std::string first_screen_name;
196   const chromeos::StartupCustomizationDocument* const startup_manifest;
197   chromeos::LoginDisplayHost* const display_host;
198
199   // lock UI while resource bundle is being reloaded.
200   chromeos::InputEventsBlocker events_blocker;
201 };
202
203 void OnLanguageSwitchedCallback(
204     scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self,
205     const std::string& locale,
206     const std::string& loaded_locale,
207     const bool success) {
208   if (!success)
209     LOG(WARNING) << "Locale could not be found for '" << locale << "'";
210
211   ShowLoginWizardFinish(
212       self->first_screen_name, self->startup_manifest, self->display_host);
213 }
214
215 void EnableSystemSoundsForAccessibility() {
216   chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
217 }
218
219 // A login implementation of WidgetDelegate.
220 class LoginWidgetDelegate : public views::WidgetDelegate {
221  public:
222   explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
223   }
224   virtual ~LoginWidgetDelegate() {}
225
226   // Overridden from WidgetDelegate:
227   virtual void DeleteDelegate() override {
228     delete this;
229   }
230   virtual views::Widget* GetWidget() override {
231     return widget_;
232   }
233   virtual const views::Widget* GetWidget() const override {
234     return widget_;
235   }
236   virtual bool CanActivate() const override {
237     return true;
238   }
239   virtual bool ShouldAdvanceFocusToTopLevelWidget() const override {
240     return true;
241   }
242
243  private:
244   views::Widget* widget_;
245
246   DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
247 };
248
249 // Disables virtual keyboard overscroll. Login UI will scroll user pods
250 // into view on JS side when virtual keyboard is shown.
251 void DisableKeyboardOverscroll() {
252   keyboard::SetKeyboardOverscrollOverride(
253       keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
254 }
255
256 void ResetKeyboardOverscrollOverride() {
257   keyboard::SetKeyboardOverscrollOverride(
258       keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
259 }
260
261 }  // namespace
262
263 namespace chromeos {
264
265 // static
266 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL;
267
268 // static
269 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
270
271 ////////////////////////////////////////////////////////////////////////////////
272 // LoginDisplayHostImpl, public
273
274 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds)
275     : background_bounds_(background_bounds),
276       pointer_factory_(this),
277       shutting_down_(false),
278       oobe_progress_bar_visible_(false),
279       session_starting_(false),
280       login_window_(NULL),
281       login_view_(NULL),
282       webui_login_display_(NULL),
283       is_showing_login_(false),
284       is_wallpaper_loaded_(false),
285       status_area_saved_visibility_(false),
286       crash_count_(0),
287       restore_path_(RESTORE_UNKNOWN),
288       finalize_animation_type_(ANIMATION_WORKSPACE),
289       startup_sound_played_(false),
290       startup_sound_honors_spoken_feedback_(false),
291       is_observing_keyboard_(false),
292       animation_weak_ptr_factory_(this) {
293   DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
294   CrasAudioHandler::Get()->AddAudioObserver(this);
295   if (keyboard::KeyboardController::GetInstance()) {
296     keyboard::KeyboardController::GetInstance()->AddObserver(this);
297     is_observing_keyboard_ = true;
298   }
299
300 #if !defined(USE_ATHENA)
301   ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
302   ash::Shell::GetScreen()->AddObserver(this);
303 #endif
304
305   // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING
306   // because/ APP_TERMINATING will never be fired as long as this keeps
307   // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no
308   // browser instance that will block the shutdown.
309   registrar_.Add(this,
310                  chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
311                  content::NotificationService::AllSources());
312
313   // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but
314   // not shown yet. Lock window has to be closed at this point so that
315   // a browser window exists and the window can acquire input focus.
316   registrar_.Add(this,
317                  chrome::NOTIFICATION_BROWSER_OPENED,
318                  content::NotificationService::AllSources());
319
320   // Login screen is moved to lock screen container when user logs in.
321   registrar_.Add(this,
322                  chrome::NOTIFICATION_LOGIN_USER_CHANGED,
323                  content::NotificationService::AllSources());
324
325   DCHECK(default_host_ == NULL);
326   default_host_ = this;
327
328   // Make sure chrome won't exit while we are at login/oobe screen.
329   chrome::IncrementKeepAliveCount();
330
331   bool is_registered = StartupUtils::IsDeviceRegistered();
332   bool zero_delay_enabled = WizardController::IsZeroDelayEnabled();
333   bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch(
334       switches::kDisableBootAnimation);
335
336   waiting_for_wallpaper_load_ = !zero_delay_enabled &&
337                                 (!is_registered || !disable_boot_animation);
338
339 #if defined(USE_ATHENA)
340   // TODO(dpolukhin): remove #ifdef when Athena supports wallpaper manager.
341   // crbug.com/408734
342   waiting_for_wallpaper_load_ = false;
343 #endif
344
345   // For slower hardware we have boot animation disabled so
346   // we'll be initializing WebUI hidden, waiting for user pods to load and then
347   // show WebUI at once.
348   waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_;
349
350   initialize_webui_hidden_ =
351       kHiddenWebUIInitializationDefault && !zero_delay_enabled;
352
353   // Check if WebUI init type is overriden.
354   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) {
355     const std::string override_type =
356         CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
357             switches::kAshWebUIInit);
358     if (override_type == kWebUIInitParallel)
359       initialize_webui_hidden_ = true;
360     else if (override_type == kWebUIInitPostpone)
361       initialize_webui_hidden_ = false;
362   }
363
364   // Always postpone WebUI initialization on first boot, otherwise we miss
365   // initial animation.
366   if (!StartupUtils::IsOobeCompleted())
367     initialize_webui_hidden_ = false;
368
369   // There is no wallpaper for KioskMode, don't initialize the webui hidden.
370   if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
371     initialize_webui_hidden_ = false;
372
373 #if !defined(USE_ATHENA)
374   if (waiting_for_wallpaper_load_) {
375     registrar_.Add(this,
376                    chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
377                    content::NotificationService::AllSources());
378   }
379 #endif
380
381   // When we wait for WebUI to be initialized we wait for one of
382   // these notifications.
383   if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) &&
384       initialize_webui_hidden_) {
385     registrar_.Add(this,
386                    chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
387                    content::NotificationService::AllSources());
388     registrar_.Add(this,
389                    chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
390                    content::NotificationService::AllSources());
391   }
392   VLOG(1) << "Login WebUI >> "
393           << "zero_delay: " << zero_delay_enabled
394           << " wait_for_wp_load_: " << waiting_for_wallpaper_load_
395           << " wait_for_pods_: " << waiting_for_user_pods_
396           << " init_webui_hidden_: " << initialize_webui_hidden_;
397
398   media::SoundsManager* manager = media::SoundsManager::Get();
399   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
400   manager->Initialize(chromeos::SOUND_STARTUP,
401                       bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV));
402 }
403
404 LoginDisplayHostImpl::~LoginDisplayHostImpl() {
405   DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
406   CrasAudioHandler::Get()->RemoveAudioObserver(this);
407   if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
408     keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
409     is_observing_keyboard_ = false;
410   }
411
412 #if !defined(USE_ATHENA)
413   ash::Shell::GetInstance()->delegate()->
414       RemoveVirtualKeyboardStateObserver(this);
415   ash::Shell::GetScreen()->RemoveObserver(this);
416 #endif
417
418   if (login_view_ && login_window_)
419     login_window_->RemoveRemovalsObserver(this);
420
421   if (login::LoginScrollIntoViewEnabled())
422     ResetKeyboardOverscrollOverride();
423
424   views::FocusManager::set_arrow_key_traversal_enabled(false);
425   ResetLoginWindowAndView();
426
427   // Let chrome process exit after login/oobe screen if needed.
428   chrome::DecrementKeepAliveCount();
429
430   default_host_ = NULL;
431   // TODO(tengs): This should be refactored. See crbug.com/314934.
432   if (user_manager::UserManager::Get()->IsCurrentUserNew()) {
433     // DriveOptInController will delete itself when finished.
434     (new DriveFirstRunController(
435         ProfileManager::GetActiveUserProfile()))->EnableOfflineMode();
436   }
437 }
438
439 ////////////////////////////////////////////////////////////////////////////////
440 // LoginDisplayHostImpl, LoginDisplayHost implementation:
441
442 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay(
443     LoginDisplay::Delegate* delegate) {
444   webui_login_display_ = new WebUILoginDisplay(delegate);
445   webui_login_display_->set_background_bounds(background_bounds());
446   return webui_login_display_;
447 }
448
449 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const {
450   return login_window_ ? login_window_->GetNativeWindow() : NULL;
451 }
452
453 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const {
454   return login_view_;
455 }
456
457 void LoginDisplayHostImpl::BeforeSessionStart() {
458   session_starting_ = true;
459 }
460
461 void LoginDisplayHostImpl::Finalize() {
462   DVLOG(1) << "Session starting";
463 #if !defined(USE_ATHENA)
464   if (ash::Shell::HasInstance()) {
465     ash::Shell::GetInstance()->
466         desktop_background_controller()->MoveDesktopToUnlockedContainer();
467   }
468 #endif
469   if (wizard_controller_.get())
470     wizard_controller_->OnSessionStart();
471
472   switch (finalize_animation_type_) {
473     case ANIMATION_NONE:
474       ShutdownDisplayHost(false);
475       break;
476     case ANIMATION_WORKSPACE:
477 #if !defined(USE_ATHENA)
478       if (ash::Shell::HasInstance())
479         ScheduleWorkspaceAnimation();
480 #endif
481
482       ShutdownDisplayHost(false);
483       break;
484     case ANIMATION_FADE_OUT:
485       // Display host is deleted once animation is completed
486       // since sign in screen widget has to stay alive.
487       ScheduleFadeOutAnimation();
488       break;
489   }
490 }
491
492 void LoginDisplayHostImpl::OnCompleteLogin() {
493   if (auto_enrollment_controller_)
494     auto_enrollment_controller_->Cancel();
495 }
496
497 void LoginDisplayHostImpl::OpenProxySettings() {
498   if (login_view_)
499     login_view_->OpenProxySettings();
500 }
501
502 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) {
503   if (initialize_webui_hidden_)
504     status_area_saved_visibility_ = visible;
505   else if (login_view_)
506     login_view_->SetStatusAreaVisible(visible);
507 }
508
509 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() {
510   if (!auto_enrollment_controller_) {
511     auto_enrollment_controller_.reset(new AutoEnrollmentController());
512     auto_enrollment_progress_subscription_ =
513         auto_enrollment_controller_->RegisterProgressCallback(
514             base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress,
515                        base::Unretained(this)));
516   }
517   return auto_enrollment_controller_.get();
518 }
519
520 void LoginDisplayHostImpl::StartWizard(
521     const std::string& first_screen_name,
522     scoped_ptr<base::DictionaryValue> screen_parameters) {
523   if (login::LoginScrollIntoViewEnabled())
524     DisableKeyboardOverscroll();
525
526   startup_sound_honors_spoken_feedback_ = false;
527   TryToPlayStartupSound();
528
529   // Keep parameters to restore if renderer crashes.
530   restore_path_ = RESTORE_WIZARD;
531   first_screen_name_ = first_screen_name;
532   if (screen_parameters.get())
533     screen_parameters_.reset(screen_parameters->DeepCopy());
534   else
535     screen_parameters_.reset();
536   is_showing_login_ = false;
537
538   if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
539     VLOG(1) << "Login WebUI >> wizard postponed";
540     return;
541   }
542   VLOG(1) << "Login WebUI >> wizard";
543
544   if (!login_window_)
545     LoadURL(GURL(kOobeURL));
546
547   DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
548   // Create and show the wizard.
549   // Note, dtor of the old WizardController should be called before ctor of the
550   // new one, because "default_controller()" is updated there. So pure "reset()"
551   // is done before new controller creation.
552   wizard_controller_.reset();
553   wizard_controller_.reset(CreateWizardController());
554
555   oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
556   SetOobeProgressBarVisible(oobe_progress_bar_visible_);
557   wizard_controller_->Init(first_screen_name, screen_parameters.Pass());
558 }
559
560 WizardController* LoginDisplayHostImpl::GetWizardController() {
561   return wizard_controller_.get();
562 }
563
564 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() {
565   return app_launch_controller_.get();
566 }
567
568 void LoginDisplayHostImpl::StartUserAdding(
569     const base::Closure& completion_callback) {
570   if (login::LoginScrollIntoViewEnabled())
571     DisableKeyboardOverscroll();
572
573   restore_path_ = RESTORE_ADD_USER_INTO_SESSION;
574   completion_callback_ = completion_callback;
575   finalize_animation_type_ = ANIMATION_NONE;
576   VLOG(1) << "Login WebUI >> user adding";
577   if (!login_window_)
578     LoadURL(GURL(kUserAddingURL));
579   // We should emit this signal only at login screen (after reboot or sign out).
580   login_view_->set_should_emit_login_prompt_visible(false);
581
582 #if !defined(USE_ATHENA)
583   // Lock container can be transparent after lock screen animation.
584   aura::Window* lock_container = ash::Shell::GetContainer(
585       ash::Shell::GetPrimaryRootWindow(),
586       ash::kShellWindowId_LockScreenContainersContainer);
587   lock_container->layer()->SetOpacity(1.0);
588
589   ash::Shell::GetInstance()->
590       desktop_background_controller()->MoveDesktopToLockedContainer();
591 #endif
592
593   sign_in_controller_.reset();  // Only one controller in a time.
594   sign_in_controller_.reset(new chromeos::ExistingUserController(this));
595   SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false);
596   SetStatusAreaVisible(true);
597   sign_in_controller_->Init(
598       user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile());
599   CHECK(webui_login_display_);
600   GetOobeUI()->ShowSigninScreen(LoginScreenContext(),
601                                 webui_login_display_,
602                                 webui_login_display_);
603 }
604
605 void LoginDisplayHostImpl::StartSignInScreen(
606     const LoginScreenContext& context) {
607   if (login::LoginScrollIntoViewEnabled())
608     DisableKeyboardOverscroll();
609
610   startup_sound_honors_spoken_feedback_ = true;
611   TryToPlayStartupSound();
612
613   restore_path_ = RESTORE_SIGN_IN;
614   is_showing_login_ = true;
615   finalize_animation_type_ = ANIMATION_WORKSPACE;
616
617   PrewarmAuthentication();
618
619   if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) {
620     VLOG(1) << "Login WebUI >> sign in postponed";
621     return;
622   }
623   VLOG(1) << "Login WebUI >> sign in";
624
625   if (!login_window_) {
626     TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid);
627     TRACE_EVENT_ASYNC_STEP_INTO0(
628         "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen");
629     BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen");
630     LoadURL(GURL(kLoginURL));
631   }
632
633   DVLOG(1) << "Starting sign in screen";
634   const user_manager::UserList& users =
635       user_manager::UserManager::Get()->GetUsers();
636
637   // Fix for users who updated device and thus never passed register screen.
638   // If we already have users, we assume that it is not a second part of
639   // OOBE. See http://crosbug.com/6289
640   if (!StartupUtils::IsDeviceRegistered() && !users.empty()) {
641     VLOG(1) << "Mark device registered because there are remembered users: "
642             << users.size();
643     StartupUtils::MarkDeviceRegistered(base::Closure());
644   }
645
646   sign_in_controller_.reset();  // Only one controller in a time.
647   sign_in_controller_.reset(new chromeos::ExistingUserController(this));
648   oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered();
649   SetOobeProgressBarVisible(oobe_progress_bar_visible_);
650   SetStatusAreaVisible(true);
651   sign_in_controller_->Init(users);
652
653   // We might be here after a reboot that was triggered after OOBE was complete,
654   // so check for auto-enrollment again. This might catch a cached decision from
655   // a previous oobe flow, or might start a new check with the server.
656   if (GetAutoEnrollmentController()->ShouldEnrollSilently())
657     sign_in_controller_->DoAutoEnrollment();
658   else
659     GetAutoEnrollmentController()->Start();
660
661   // Initiate mobile config load.
662   MobileConfig::GetInstance();
663
664   // Initiate device policy fetching.
665   policy::BrowserPolicyConnectorChromeOS* connector =
666       g_browser_process->platform_part()->browser_policy_connector_chromeos();
667   connector->ScheduleServiceInitialization(
668       kPolicyServiceInitializationDelayMilliseconds);
669
670   CHECK(webui_login_display_);
671   GetOobeUI()->ShowSigninScreen(context,
672                                 webui_login_display_,
673                                 webui_login_display_);
674   if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
675     SetStatusAreaVisible(false);
676   TRACE_EVENT_ASYNC_STEP_INTO0("ui",
677                                "ShowLoginWebUI",
678                                kShowLoginWebUIid,
679                                "WaitForScreenStateInitialize");
680   BootTimesLoader::Get()->RecordCurrentStats(
681       "login-wait-for-signin-state-initialize");
682 }
683
684 void LoginDisplayHostImpl::ResumeSignInScreen() {
685   // We only get here after a previous call the StartSignInScreen. That sign-in
686   // was successful but was interrupted by an auto-enrollment execution; once
687   // auto-enrollment is complete we resume the normal login flow from here.
688   DVLOG(1) << "Resuming sign in screen";
689   CHECK(sign_in_controller_.get());
690   SetOobeProgressBarVisible(oobe_progress_bar_visible_);
691   SetStatusAreaVisible(true);
692   sign_in_controller_->ResumeLogin();
693 }
694
695
696 void LoginDisplayHostImpl::OnPreferencesChanged() {
697   if (is_showing_login_)
698     webui_login_display_->OnPreferencesChanged();
699 }
700
701 void LoginDisplayHostImpl::PrewarmAuthentication() {
702   auth_prewarmer_.reset(new AuthPrewarmer());
703   auth_prewarmer_->PrewarmAuthentication(
704       base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone,
705                  pointer_factory_.GetWeakPtr()));
706 }
707
708 void LoginDisplayHostImpl::StartDemoAppLaunch() {
709   VLOG(1) << "Login WebUI >> starting demo app.";
710   SetStatusAreaVisible(false);
711
712   demo_app_launcher_.reset(new DemoAppLauncher());
713   demo_app_launcher_->StartDemoAppLaunch();
714 }
715
716 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id,
717                                           bool diagnostic_mode) {
718   VLOG(1) << "Login WebUI >> start app launch.";
719   SetStatusAreaVisible(false);
720   finalize_animation_type_ = ANIMATION_FADE_OUT;
721   if (!login_window_)
722     LoadURL(GURL(kAppLaunchSplashURL));
723
724   login_view_->set_should_emit_login_prompt_visible(false);
725
726   app_launch_controller_.reset(new AppLaunchController(
727       app_id, diagnostic_mode, this, GetOobeUI()));
728
729   app_launch_controller_->StartAppLaunch();
730 }
731
732 ////////////////////////////////////////////////////////////////////////////////
733 // LoginDisplayHostImpl, public
734
735 WizardController* LoginDisplayHostImpl::CreateWizardController() {
736   // TODO(altimofeev): ensure that WebUI is ready.
737   OobeDisplay* oobe_display = GetOobeUI();
738   return new WizardController(this, oobe_display);
739 }
740
741 void LoginDisplayHostImpl::OnBrowserCreated() {
742   // Close lock window now so that the launched browser can receive focus.
743   ResetLoginWindowAndView();
744 }
745
746 OobeUI* LoginDisplayHostImpl::GetOobeUI() const {
747   if (!login_view_)
748     return NULL;
749   return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController());
750 }
751
752 ////////////////////////////////////////////////////////////////////////////////
753 // LoginDisplayHostImpl, content:NotificationObserver implementation:
754
755 void LoginDisplayHostImpl::Observe(
756     int type,
757     const content::NotificationSource& source,
758     const content::NotificationDetails& details) {
759   if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type ||
760       chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) {
761     VLOG(1) << "Login WebUI >> WEBUI_VISIBLE";
762     if (waiting_for_user_pods_ && initialize_webui_hidden_) {
763       waiting_for_user_pods_ = false;
764       ShowWebUI();
765     } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) {
766       // Reduce time till login UI is shown - show it as soon as possible.
767       waiting_for_wallpaper_load_ = false;
768       ShowWebUI();
769     }
770     registrar_.Remove(this,
771                       chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
772                       content::NotificationService::AllSources());
773     registrar_.Remove(this,
774                       chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
775                       content::NotificationService::AllSources());
776   } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) {
777     ShutdownDisplayHost(true);
778   } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) {
779     // Browsers created before session start (windows opened by extensions, for
780     // example) are ignored.
781     OnBrowserCreated();
782     registrar_.Remove(this,
783                       chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
784                       content::NotificationService::AllSources());
785     registrar_.Remove(this,
786                       chrome::NOTIFICATION_BROWSER_OPENED,
787                       content::NotificationService::AllSources());
788   } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED &&
789              user_manager::UserManager::Get()->IsCurrentUserNew()) {
790 #if !defined(USE_ATHENA)
791     // For new user, move desktop to locker container so that windows created
792     // during the user image picker step are below it.
793     ash::Shell::GetInstance()->
794         desktop_background_controller()->MoveDesktopToLockedContainer();
795 #endif
796     registrar_.Remove(this,
797                       chrome::NOTIFICATION_LOGIN_USER_CHANGED,
798                       content::NotificationService::AllSources());
799 #if !defined(USE_ATHENA)
800   } else if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) {
801     VLOG(1) << "Login WebUI >> wp animation done";
802     is_wallpaper_loaded_ = true;
803     ash::Shell::GetInstance()->user_wallpaper_delegate()
804         ->OnWallpaperBootAnimationFinished();
805     if (waiting_for_wallpaper_load_) {
806       // StartWizard / StartSignInScreen could be called multiple times through
807       // the lifetime of host.
808       // Make sure that subsequent calls are not postponed.
809       waiting_for_wallpaper_load_ = false;
810       if (initialize_webui_hidden_)
811         ShowWebUI();
812       else
813         StartPostponedWebUI();
814     }
815     registrar_.Remove(this,
816                       chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
817                       content::NotificationService::AllSources());
818 #endif
819   }
820 }
821
822 ////////////////////////////////////////////////////////////////////////////////
823 // LoginDisplayHostImpl, WebContentsObserver implementation:
824
825 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) {
826   // Do not try to restore on shutdown
827   if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
828     return;
829
830   crash_count_++;
831   if (crash_count_ > kCrashCountLimit)
832     return;
833
834   if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
835     // Render with login screen crashed. Let's crash browser process to let
836     // session manager restart it properly. It is hard to reload the page
837     // and get to controlled state that is fully functional.
838     // If you see check, search for renderer crash for the same client.
839     LOG(FATAL) << "Renderer crash on login window";
840   }
841 }
842
843 ////////////////////////////////////////////////////////////////////////////////
844 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer
845 // implementation:
846
847 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() {
848   OnLoginPromptVisible();
849 }
850
851 ////////////////////////////////////////////////////////////////////////////////
852 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver
853 // implementation:
854
855 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() {
856   TryToPlayStartupSound();
857 }
858
859 #if !defined(USE_ATHENA)
860 ////////////////////////////////////////////////////////////////////////////////
861 // LoginDisplayHostImpl, ash::KeyboardStateObserver:
862 // implementation:
863
864 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) {
865   if (keyboard::KeyboardController::GetInstance()) {
866     if (activated) {
867       if (!is_observing_keyboard_) {
868         keyboard::KeyboardController::GetInstance()->AddObserver(this);
869         is_observing_keyboard_ = true;
870       }
871     } else {
872       keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
873       is_observing_keyboard_ = false;
874     }
875   }
876 }
877 #endif
878
879 ////////////////////////////////////////////////////////////////////////////////
880 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver:
881 // implementation:
882
883 void LoginDisplayHostImpl::OnKeyboardBoundsChanging(
884     const gfx::Rect& new_bounds) {
885   if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
886     // Keyboard has been hidden.
887     if (GetOobeUI()) {
888       GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
889       if (login::LoginScrollIntoViewEnabled())
890         GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds);
891     }
892   } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
893     // Keyboard has been shown.
894     if (GetOobeUI()) {
895       GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
896       if (login::LoginScrollIntoViewEnabled())
897         GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds);
898     }
899   }
900
901   keyboard_bounds_ = new_bounds;
902 }
903
904 ////////////////////////////////////////////////////////////////////////////////
905 // LoginDisplayHostImpl, gfx::DisplayObserver implementation:
906
907 void LoginDisplayHostImpl::OnDisplayAdded(const gfx::Display& new_display) {
908 }
909
910 void LoginDisplayHostImpl::OnDisplayRemoved(const gfx::Display& old_display) {
911 }
912
913 void LoginDisplayHostImpl::OnDisplayMetricsChanged(const gfx::Display& display,
914                                                    uint32_t changed_metrics) {
915   gfx::Display primary_display =
916       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
917   if (display.id() != primary_display.id() ||
918       !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
919     return;
920   }
921
922   if (GetOobeUI()) {
923     const gfx::Size& size = primary_display.size();
924     GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size.width(),
925                                                        size.height());
926   }
927 }
928
929 ////////////////////////////////////////////////////////////////////////////////
930 // LoginDisplayHostImpl, views::WidgetRemovalsObserver implementation:
931 void LoginDisplayHostImpl::OnWillRemoveView(views::Widget* widget,
932                                             views::View* view) {
933   if (view != static_cast<views::View*>(login_view_))
934     return;
935   login_view_ = NULL;
936   widget->RemoveRemovalsObserver(this);
937 }
938
939 ////////////////////////////////////////////////////////////////////////////////
940 // LoginDisplayHostImpl, private
941
942 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) {
943   if (shutting_down_)
944     return;
945
946   shutting_down_ = true;
947   registrar_.RemoveAll();
948   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
949   if (post_quit_task)
950     base::MessageLoop::current()->Quit();
951
952   if (!completion_callback_.is_null())
953     completion_callback_.Run();
954 }
955
956 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() {
957 #if !defined(USE_ATHENA)
958   if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
959                                ash::kShellWindowId_DesktopBackgroundContainer)
960           ->children()
961           .empty()) {
962     // If there is no background window, don't perform any animation on the
963     // default and background layer because there is nothing behind it.
964     return;
965   }
966
967   if (!CommandLine::ForCurrentProcess()->HasSwitch(
968           switches::kDisableLoginAnimations))
969     ash::Shell::GetInstance()->DoInitialWorkspaceAnimation();
970 #endif
971 }
972
973 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() {
974   ui::Layer* layer = login_window_->GetLayer();
975   ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
976   animation.AddObserver(new AnimationObserver(
977       base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost,
978                  animation_weak_ptr_factory_.GetWeakPtr(),
979                  false)));
980   layer->SetOpacity(0);
981 }
982
983 void LoginDisplayHostImpl::OnAutoEnrollmentProgress(
984     policy::AutoEnrollmentState state) {
985   VLOG(1) << "OnAutoEnrollmentProgress, state " << state;
986
987   if (sign_in_controller_ &&
988       auto_enrollment_controller_->ShouldEnrollSilently()) {
989     sign_in_controller_->DoAutoEnrollment();
990   }
991 }
992
993 void LoginDisplayHostImpl::LoadURL(const GURL& url) {
994   InitLoginWindowAndView();
995   // Subscribe to crash events.
996   content::WebContentsObserver::Observe(login_view_->GetWebContents());
997   login_view_->LoadURL(url);
998
999   // LoadURL could be called after the spring charger dialog shows, and
1000   // take away the focus from it. Set the focus back to the charger dialog
1001   // if it is visible.
1002   // See crbug.com/328538.
1003   ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
1004 }
1005
1006 void LoginDisplayHostImpl::ShowWebUI() {
1007   if (!login_window_ || !login_view_) {
1008     NOTREACHED();
1009     return;
1010   }
1011   VLOG(1) << "Login WebUI >> Show already initialized UI";
1012   login_window_->Show();
1013   login_view_->GetWebContents()->Focus();
1014   if (::switches::IsTextInputFocusManagerEnabled())
1015     login_view_->RequestFocus();
1016   login_view_->SetStatusAreaVisible(status_area_saved_visibility_);
1017   login_view_->OnPostponedShow();
1018
1019   // Login window could be shown after the spring charger dialog shows, and
1020   // take away the focus from it. Set the focus back to the charger dialog
1021   // if it is visible.
1022   // See crbug.com/328538.
1023   ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible();
1024
1025   // We should reset this flag to allow changing of status area visibility.
1026   initialize_webui_hidden_ = false;
1027 }
1028
1029 void LoginDisplayHostImpl::StartPostponedWebUI() {
1030   if (!is_wallpaper_loaded_) {
1031     NOTREACHED();
1032     return;
1033   }
1034   VLOG(1) << "Login WebUI >> Init postponed WebUI";
1035
1036   // Wallpaper has finished loading before StartWizard/StartSignInScreen has
1037   // been called. In general this should not happen.
1038   // Let go through normal code path when one of those will be called.
1039   if (restore_path_ == RESTORE_UNKNOWN) {
1040     NOTREACHED();
1041     return;
1042   }
1043
1044   switch (restore_path_) {
1045     case RESTORE_WIZARD:
1046       StartWizard(first_screen_name_, screen_parameters_.Pass());
1047       break;
1048     case RESTORE_SIGN_IN:
1049       StartSignInScreen(LoginScreenContext());
1050       break;
1051     case RESTORE_ADD_USER_INTO_SESSION:
1052       StartUserAdding(completion_callback_);
1053       break;
1054     default:
1055       NOTREACHED();
1056       break;
1057   }
1058 }
1059
1060 void LoginDisplayHostImpl::InitLoginWindowAndView() {
1061   if (login_window_)
1062     return;
1063
1064   if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
1065     views::FocusManager::set_arrow_key_traversal_enabled(true);
1066 #if !defined(USE_ATHENA)
1067     // crbug.com/405859
1068     focus_ring_controller_.reset(new FocusRingController);
1069     focus_ring_controller_->SetVisible(true);
1070
1071     keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler);
1072 #endif
1073   }
1074
1075   views::Widget::InitParams params(
1076       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
1077   params.bounds = background_bounds();
1078   params.show_state = ui::SHOW_STATE_FULLSCREEN;
1079   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1080 #if defined(USE_ATHENA)
1081   athena::ScreenManager::ContainerParams container_params(
1082       "LoginScreen", athena::CP_LOGIN_SCREEN);
1083   container_params.can_activate_children = true;
1084   container_params.block_events = true;
1085   container_params.modal_container_priority =
1086       athena::CP_LOGIN_SCREEN_SYSTEM_MODAL;
1087   login_screen_container_.reset(
1088       athena::ScreenManager::Get()->CreateContainer(container_params));
1089   params.parent = login_screen_container_.get();
1090   login_screen_container_->SetLayoutManager(
1091       new athena::FillLayoutManager(login_screen_container_.get()));
1092 #else
1093   params.parent =
1094       ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
1095                                ash::kShellWindowId_LockScreenContainer);
1096 #endif
1097   login_window_ = new views::Widget;
1098   params.delegate = new LoginWidgetDelegate(login_window_);
1099   login_window_->Init(params);
1100
1101   login_view_ = new WebUILoginView();
1102   login_view_->Init();
1103   if (login_view_->webui_visible())
1104     OnLoginPromptVisible();
1105
1106   login_window_->SetVisibilityAnimationDuration(
1107       base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs));
1108   login_window_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
1109
1110   login_window_->AddRemovalsObserver(this);
1111   login_window_->SetContentsView(login_view_);
1112
1113   // If WebUI is initialized in hidden state, show it only if we're no
1114   // longer waiting for wallpaper animation/user images loading. Otherwise,
1115   // always show it.
1116   if (!initialize_webui_hidden_ ||
1117       (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) {
1118     VLOG(1) << "Login WebUI >> show login wnd on create";
1119     login_window_->Show();
1120   } else {
1121     VLOG(1) << "Login WebUI >> login wnd is hidden on create";
1122     login_view_->set_is_hidden(true);
1123   }
1124   login_window_->GetNativeView()->SetName("WebUILoginView");
1125 }
1126
1127 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
1128   if (!login_window_)
1129     return;
1130   login_window_->Close();
1131   login_window_ = NULL;
1132
1133   if (!login_view_)
1134     return;
1135   login_view_->SetUIEnabled(true);
1136   login_view_ = NULL;
1137 }
1138
1139 void LoginDisplayHostImpl::OnAuthPrewarmDone() {
1140   auth_prewarmer_.reset();
1141 }
1142
1143 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) {
1144   GetOobeUI()->ShowOobeUI(visible);
1145 }
1146
1147 void LoginDisplayHostImpl::TryToPlayStartupSound() {
1148   if (startup_sound_played_ || login_prompt_visible_time_.is_null() ||
1149       !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) {
1150     return;
1151   }
1152
1153   startup_sound_played_ = true;
1154
1155   // Don't try play startup sound if login prompt is already visible
1156   // for a long time or can't be played.
1157   if (base::TimeTicks::Now() - login_prompt_visible_time_ >
1158       base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) {
1159     EnableSystemSoundsForAccessibility();
1160     return;
1161   }
1162
1163 #if !defined(USE_ATHENA)
1164   if (!startup_sound_honors_spoken_feedback_ &&
1165       !ash::PlaySystemSoundAlways(SOUND_STARTUP)) {
1166     EnableSystemSoundsForAccessibility();
1167     return;
1168   }
1169
1170   // crbug.com/408733
1171   if (startup_sound_honors_spoken_feedback_ &&
1172       !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) {
1173     EnableSystemSoundsForAccessibility();
1174     return;
1175   }
1176 #endif
1177
1178   base::MessageLoop::current()->PostDelayedTask(
1179       FROM_HERE,
1180       base::Bind(&EnableSystemSoundsForAccessibility),
1181       media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
1182 }
1183
1184 void LoginDisplayHostImpl::OnLoginPromptVisible() {
1185   if (!login_prompt_visible_time_.is_null())
1186     return;
1187   login_prompt_visible_time_ = base::TimeTicks::Now();
1188   TryToPlayStartupSound();
1189 }
1190
1191 ////////////////////////////////////////////////////////////////////////////////
1192 // external
1193
1194 // Declared in login_wizard.h so that others don't need to depend on our .h.
1195 // TODO(nkostylev): Split this into a smaller functions.
1196 void ShowLoginWizard(const std::string& first_screen_name) {
1197   if (browser_shutdown::IsTryingToQuit())
1198     return;
1199
1200   VLOG(1) << "Showing OOBE screen: " << first_screen_name;
1201
1202 #if !defined(USE_ATHENA)
1203   // TODO(dpolukhin): crbug.com/407579
1204   chromeos::input_method::InputMethodManager* manager =
1205       chromeos::input_method::InputMethodManager::Get();
1206
1207   // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
1208   // and US dvorak keyboard layouts.
1209   if (g_browser_process && g_browser_process->local_state()) {
1210     manager->GetActiveIMEState()->SetInputMethodLoginDefault();
1211
1212     PrefService* prefs = g_browser_process->local_state();
1213     // Apply owner preferences for tap-to-click and mouse buttons swap for
1214     // login screen.
1215     system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
1216         prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
1217     system::InputDeviceSettings::Get()->SetTapToClick(
1218         prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
1219   }
1220   system::InputDeviceSettings::Get()->SetNaturalScroll(
1221       CommandLine::ForCurrentProcess()->HasSwitch(
1222           switches::kNaturalScrollDefault));
1223 #endif
1224
1225   gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
1226
1227   g_browser_process->platform_part()->SessionManager()->SetSessionState(
1228       StartupUtils::IsOobeCompleted()
1229           ? session_manager::SESSION_STATE_LOGIN_PRIMARY
1230           : session_manager::SESSION_STATE_OOBE);
1231
1232   LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds);
1233
1234   bool show_app_launch_splash_screen =
1235       (first_screen_name == WizardController::kAppLaunchSplashScreenName);
1236   if (show_app_launch_splash_screen) {
1237     const std::string& auto_launch_app_id =
1238         KioskAppManager::Get()->GetAutoLaunchApp();
1239     display_host->StartAppLaunch(auto_launch_app_id,
1240                                  false /* diagnostic_mode */);
1241     return;
1242   }
1243
1244   // Check whether we need to execute OOBE flow.
1245   bool oobe_complete = StartupUtils::IsOobeCompleted();
1246   policy::BrowserPolicyConnectorChromeOS* connector =
1247       g_browser_process->platform_part()->browser_policy_connector_chromeos();
1248   bool enrollment_screen_wanted =
1249       WizardController::ShouldRecoverEnrollment() ||
1250       (WizardController::ShouldAutoStartEnrollment() && oobe_complete &&
1251        !connector->IsEnterpriseManaged());
1252   if (enrollment_screen_wanted && first_screen_name.empty()) {
1253     // Shows networks screen instead of enrollment screen to resume the
1254     // interrupted auto start enrollment flow because enrollment screen does
1255     // not handle flaky network. See http://crbug.com/332572
1256     display_host->StartWizard(WizardController::kNetworkScreenName,
1257                               scoped_ptr<base::DictionaryValue>());
1258     return;
1259   }
1260
1261   if (StartupUtils::IsEulaAccepted()) {
1262     DelayNetworkCall(
1263         ServicesCustomizationDocument::GetInstance()
1264             ->EnsureCustomizationAppliedClosure(),
1265         base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS));
1266   }
1267
1268   bool show_login_screen =
1269       (first_screen_name.empty() && oobe_complete) ||
1270       first_screen_name == WizardController::kLoginScreenName;
1271
1272   if (show_login_screen) {
1273     display_host->StartSignInScreen(LoginScreenContext());
1274     return;
1275   }
1276
1277   // Load startup manifest.
1278   const StartupCustomizationDocument* startup_manifest =
1279       StartupCustomizationDocument::GetInstance();
1280
1281   // Switch to initial locale if specified by customization
1282   // and has not been set yet. We cannot call
1283   // LanguageSwitchMenu::SwitchLanguage here before
1284   // EmitLoginPromptReady.
1285   PrefService* prefs = g_browser_process->local_state();
1286   const std::string& current_locale =
1287       prefs->GetString(prefs::kApplicationLocale);
1288   VLOG(1) << "Current locale: " << current_locale;
1289   const std::string& locale = startup_manifest->initial_locale_default();
1290
1291   const std::string& layout = startup_manifest->keyboard_layout();
1292   VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
1293
1294 #if !defined(USE_ATHENA)
1295   // Determine keyboard layout from OEM customization (if provided) or
1296   // initial locale and save it in preferences.
1297   manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale,
1298                                                                   layout);
1299 #endif
1300
1301   if (!current_locale.empty() || locale.empty()) {
1302     ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host);
1303     return;
1304   }
1305
1306   // Save initial locale from VPD/customization manifest as current
1307   // Chrome locale. Otherwise it will be lost if Chrome restarts.
1308   // Don't need to schedule pref save because setting initial local
1309   // will enforce preference saving.
1310   prefs->SetString(prefs::kApplicationLocale, locale);
1311   StartupUtils::SetInitialLocale(locale);
1312
1313   scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data(
1314       new ShowLoginWizardSwitchLanguageCallbackData(
1315           first_screen_name, startup_manifest, display_host));
1316
1317   scoped_ptr<locale_util::SwitchLanguageCallback> callback(
1318       new locale_util::SwitchLanguageCallback(
1319           base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass()))));
1320
1321   // Load locale keyboards here. Hardware layout would be automatically enabled.
1322   locale_util::SwitchLanguage(
1323       locale, true, true /* login_layouts_only */, callback.Pass());
1324 }
1325
1326 }  // namespace chromeos