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