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