[cros] Refactor OOBE/login controllers.

1. Introduce LoginDisplayHost interface.

2. BaseLoginDisplayHost is an abstract class that manages lifetime of the
WizardController and ExistingUserController.
Moved ShowLoginWizard from WizardController here.

3. ViewsLoginDisplayHost is host for views specific implementation:
- ViewsLoginDisplay
- BackgroundView (currently contains StatusArea as well)

Left unchanged:
- Both WC and EUC expose default instance.
- Should move to a concept of "screen" so that it'll better integrates with WebUI login implementation.

Enabled SwitchLanguage test.

BUG=chromium-os:11864, chromium-os:8974
TEST=existing tests, autotests, manually

Review URL: http://codereview.chromium.org/6610014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78684 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chromeos/login/base_login_display_host.cc b/chrome/browser/chromeos/login/base_login_display_host.cc
new file mode 100644
index 0000000..13ac0e5
--- /dev/null
+++ b/chrome/browser/chromeos/login/base_login_display_host.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/base_login_display_host.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/input_method_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
+#include "chrome/browser/chromeos/cros/system_library.h"
+#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chrome/browser/chromeos/language_preferences.h"
+#include "chrome/browser/chromeos/login/apply_services_customization.h"
+#include "chrome/browser/chromeos/login/existing_user_controller.h"
+#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/views_login_display_host.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/chromeos/wm_ipc.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "content/common/notification_service.h"
+#include "content/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "unicode/timezone.h"
+
+
+namespace {
+
+// Determines the hardware keyboard from the given locale code
+// and the OEM layout information, and saves it to "Locale State".
+// The information will be used in input_method::GetHardwareInputMethodId().
+void DetermineAndSaveHardwareKeyboard(const std::string& locale,
+                                      const std::string& oem_layout) {
+  std::string layout;
+  if (!oem_layout.empty()) {
+    // If the OEM layout information is provided, use it.
+    layout = oem_layout;
+  } else {
+    // Otherwise, determine the hardware keyboard from the locale.
+    std::vector<std::string> input_method_ids;
+    if (chromeos::input_method::GetInputMethodIdsFromLanguageCode(
+            locale,
+            chromeos::input_method::kKeyboardLayoutsOnly,
+            &input_method_ids)) {
+      // The output list |input_method_ids| is sorted by popularity, hence
+      // input_method_ids[0] now contains the most popular keyboard layout
+      // for the given locale.
+      layout = input_method_ids[0];
+    }
+  }
+
+  if (!layout.empty()) {
+    PrefService* prefs = g_browser_process->local_state();
+    prefs->SetString(prefs::kHardwareKeyboardLayout, layout);
+    // This asks the file thread to save the prefs (i.e. doesn't block).
+    // The latest values of Local State reside in memory so we can safely
+    // get the value of kHardwareKeyboardLayout even if the data is not
+    // yet saved to disk.
+    prefs->SavePersistentPrefs();
+  }
+}
+
+}  // namespace
+
+namespace chromeos {
+
+// static
+LoginDisplayHost* BaseLoginDisplayHost::default_host_ = NULL;
+
+// BaseLoginDisplayHost --------------------------------------------------------
+
+BaseLoginDisplayHost::BaseLoginDisplayHost(const gfx::Rect& background_bounds)
+    : background_bounds_(background_bounds) {
+  registrar_.Add(
+      this,
+      NotificationType::APP_TERMINATING,
+      NotificationService::AllSources());
+  DCHECK(default_host_ == NULL);
+  default_host_ = this;
+}
+
+BaseLoginDisplayHost::~BaseLoginDisplayHost() {
+  default_host_ = NULL;
+}
+
+// LoginDisplayHost implementation ---------------------------------------------
+
+void BaseLoginDisplayHost::OnSessionStart() {
+  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void BaseLoginDisplayHost::StartWizard(
+    const std::string& first_screen_name,
+    const chromeos::StartupCustomizationDocument* manifest,
+    const GURL& start_url) {
+  DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
+  // Create and show the wizard.
+  wizard_controller_.reset(new WizardController(this, background_bounds_));
+  wizard_controller_->SetCustomization(manifest);
+  wizard_controller_->set_start_url(start_url);
+  ShowBackground();
+  if (!WizardController::IsDeviceRegistered())
+    SetOobeProgressBarVisible(true);
+  wizard_controller_->Init(first_screen_name);
+}
+
+void BaseLoginDisplayHost::StartSignInScreen() {
+  DVLOG(1) << "Starting sign in screen";
+  std::vector<chromeos::UserManager::User> users =
+      chromeos::UserManager::Get()->GetUsers();
+
+  // Fix for users who updated device and thus never passed register screen.
+  // If we already have users, we assume that it is not a second part of
+  // OOBE. See http://crosbug.com/6289
+  if (!WizardController::IsDeviceRegistered() && !users.empty()) {
+    VLOG(1) << "Mark device registered because there are remembered users: "
+            << users.size();
+    WizardController::MarkDeviceRegistered();
+  }
+
+  sign_in_controller_.reset(new chromeos::ExistingUserController(this));
+  ShowBackground();
+  SetShutdownButtonEnabled(true);
+  sign_in_controller_->Init(users);
+
+  // Initiate services customization.
+  chromeos::ApplyServicesCustomization::StartIfNeeded();
+}
+
+// BaseLoginDisplayHost --------------------------------------------------------
+
+void BaseLoginDisplayHost::Observe(NotificationType type,
+                                   const NotificationSource& source,
+                                   const NotificationDetails& details) {
+  CHECK(type == NotificationType::APP_TERMINATING);
+
+  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+  MessageLoop::current()->Quit();
+  registrar_.Remove(this,
+                    NotificationType::APP_TERMINATING,
+                    NotificationService::AllSources());
+}
+
+}  // namespace chromeos
+
+// browser::ShowLoginWizard implementation -------------------------------------
+
+namespace browser {
+
+// Declared in browser_dialogs.h so that others don't need to depend on our .h.
+// TODO(nkostylev): Split this into a smaller functions.
+void ShowLoginWizard(const std::string& first_screen_name,
+                     const gfx::Size& size) {
+  VLOG(1) << "Showing login screen: " << first_screen_name;
+
+  // The login screen will enable alternate keyboard layouts, but we don't want
+  // to start the IME process unless one is selected.
+  chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
+      SetDeferImeStartup(true);
+  // Tell the window manager that the user isn't logged in.
+  chromeos::WmIpc::instance()->SetLoggedInProperty(false);
+
+  // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
+  // and US dvorak keyboard layouts.
+  if (g_browser_process && g_browser_process->local_state()) {
+    const std::string locale = g_browser_process->GetApplicationLocale();
+    // If the preferred keyboard for the login screen has been saved, use it.
+    const std::string initial_input_method_id =
+        g_browser_process->local_state()->GetString(
+            chromeos::language_prefs::kPreferredKeyboardLayout);
+    chromeos::input_method::EnableInputMethods(
+        locale, chromeos::input_method::kKeyboardLayoutsOnly,
+        initial_input_method_id);
+  }
+
+  gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size));
+
+  // Check whether we need to execute OOBE process.
+  bool oobe_complete = WizardController::IsOobeCompleted();
+  bool show_login_screen =
+      (first_screen_name.empty() && oobe_complete) ||
+      first_screen_name == WizardController::kLoginScreenName;
+
+  // TODO(nkostylev) Create LoginDisplayHost instance based on flag.
+  chromeos::LoginDisplayHost* display_host =
+      new chromeos::ViewsLoginDisplayHost(screen_bounds);
+
+  if (show_login_screen && chromeos::CrosLibrary::Get()->EnsureLoaded()) {
+    display_host->StartSignInScreen();
+    return;
+  }
+
+  // Load startup manifest.
+  const chromeos::StartupCustomizationDocument* startup_manifest =
+      chromeos::LoadStartupManifest();
+
+  std::string locale;
+  if (startup_manifest) {
+    // Switch to initial locale if specified by customization
+    // and has not been set yet. We cannot call
+    // chromeos::LanguageSwitchMenu::SwitchLanguage here before
+    // EmitLoginPromptReady.
+    const std::string current_locale =
+        g_browser_process->local_state()->GetString(prefs::kApplicationLocale);
+    VLOG(1) << "Current locale: " << current_locale;
+    if (current_locale.empty()) {
+      locale = startup_manifest->initial_locale();
+      std::string layout = startup_manifest->keyboard_layout();
+      VLOG(1) << "Initial locale: " << locale
+              << "keyboard layout " << layout;
+      if (!locale.empty()) {
+        // Determine keyboard layout from OEM customization (if provided) or
+        // initial locale and save it in preferences.
+        DetermineAndSaveHardwareKeyboard(locale, layout);
+        // Then, enable the hardware keyboard.
+        chromeos::input_method::EnableInputMethods(
+            locale,
+            chromeos::input_method::kKeyboardLayoutsOnly,
+            chromeos::input_method::GetHardwareInputMethodId());
+        // Reloading resource bundle causes us to do blocking IO on UI thread.
+        // Temporarily allow it until we fix http://crosbug.com/11102
+        base::ThreadRestrictions::ScopedAllowIO allow_io;
+        const std::string loaded_locale =
+            ResourceBundle::ReloadSharedInstance(locale);
+        CHECK(!loaded_locale.empty()) << "Locale could not be found for "
+                                      << locale;
+        // Set the application locale here so that the language switch
+        // menu works properly with the newly loaded locale.
+        g_browser_process->SetApplicationLocale(loaded_locale);
+      }
+    }
+  }
+
+  display_host->StartWizard(first_screen_name, startup_manifest, GURL());
+
+  chromeos::LoginUtils::Get()->PrewarmAuthentication();
+  if (chromeos::CrosLibrary::Get()->EnsureLoaded())
+    chromeos::CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
+
+  if (startup_manifest) {
+    // Set initial timezone if specified by customization.
+    const std::string timezone_name = startup_manifest->initial_timezone();
+    VLOG(1) << "Initial time zone: " << timezone_name;
+    // Apply locale customizations only once so preserve whatever locale
+    // user has changed to during OOBE.
+    if (!timezone_name.empty()) {
+      icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
+          icu::UnicodeString::fromUTF8(timezone_name));
+      chromeos::CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
+    }
+  }
+}
+
+}  // namespace browser
diff --git a/chrome/browser/chromeos/login/base_login_display_host.h b/chrome/browser/chromeos/login/base_login_display_host.h
new file mode 100644
index 0000000..b4443ac
--- /dev/null
+++ b/chrome/browser/chromeos/login/base_login_display_host.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_BASE_LOGIN_DISPLAY_HOST_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_BASE_LOGIN_DISPLAY_HOST_H_
+#pragma once
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/login_display.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+#include "ui/gfx/rect.h"
+
+class WizardController;
+
+namespace views {
+class Widget;
+}
+
+namespace chromeos {
+
+class ExistingUserController;
+
+// An abstract base class that defines OOBE/login screen host.
+// It encapsulates controllers, background integration and flow.
+class BaseLoginDisplayHost : public LoginDisplayHost,
+                             public NotificationObserver {
+ public:
+  explicit BaseLoginDisplayHost(const gfx::Rect& background_bounds);
+  virtual ~BaseLoginDisplayHost();
+
+  // Returns the default LoginDispalyHost instance if it has been created.
+  static LoginDisplayHost* default_host() {
+    return default_host_;
+  }
+
+  // LoginDisplayHost implementation:
+  virtual void OnSessionStart();
+  virtual void StartWizard(
+      const std::string& first_screen_name,
+      const chromeos::StartupCustomizationDocument* manifest,
+      const GURL& start_url);
+  virtual void StartSignInScreen();
+
+  const gfx::Rect& background_bounds() const { return background_bounds_; }
+
+ private:
+  // NotificationObserver implementation:
+  virtual void Observe(NotificationType type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details);
+
+  // Used to calculate position of the screens and background.
+  gfx::Rect background_bounds_;
+
+  NotificationRegistrar registrar_;
+
+  // Default LoginDisplayHost.
+  static LoginDisplayHost* default_host_;
+
+  // Sign in screen controller.
+  scoped_ptr<ExistingUserController> sign_in_controller_;
+
+  // OOBE and some screens (camera, recovery) controller.
+  scoped_ptr<WizardController> wizard_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaseLoginDisplayHost);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_BASE_LOGIN_DISPLAY_HOST_H_
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 04697db..20b0518e 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -14,8 +14,8 @@
 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
 #include "chrome/browser/chromeos/cros/login_library.h"
 #include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/chromeos/login/background_view.h"
 #include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/views_login_display.h"
 #include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
@@ -56,25 +56,19 @@
 }  // namespace
 
 // static
-ExistingUserController*
-  ExistingUserController::current_controller_ = NULL;
+ExistingUserController* ExistingUserController::current_controller_ = NULL;
 
 ////////////////////////////////////////////////////////////////////////////////
 // ExistingUserController, public:
 
-ExistingUserController::ExistingUserController(
-    const gfx::Rect& background_bounds)
-    : background_bounds_(background_bounds),
-      background_window_(NULL),
-      background_view_(NULL),
+ExistingUserController::ExistingUserController(LoginDisplayHost* host)
+    : host_(host),
       num_login_attempts_(0),
       user_settings_(new UserCrosSettingsProvider),
       method_factory_(this) {
-  if (current_controller_)
-    current_controller_->Delete();
   current_controller_ = this;
 
-  login_display_.reset(CreateLoginDisplay(this, background_bounds));
+  login_display_.reset(host_->CreateLoginDisplay(this));
 
   registrar_.Add(this,
                  NotificationType::LOGIN_USER_IMAGE_CHANGED,
@@ -98,20 +92,6 @@
       }
     }
   }
-  if (!background_window_) {
-    background_window_ = BackgroundView::CreateWindowContainingView(
-        background_bounds_,
-        GURL(),
-        &background_view_);
-    background_view_->EnableShutdownButton(true);
-
-    if (!WizardController::IsDeviceRegistered()) {
-      background_view_->SetOobeProgressBarVisible(true);
-      background_view_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
-    }
-
-    background_window_->Show();
-  }
 
   UserVector filtered_users;
   if (UserCrosSettingsProvider::cached_show_users_on_signin()) {
@@ -140,14 +120,6 @@
   }
 }
 
-void ExistingUserController::OwnBackground(
-    views::Widget* background_widget,
-    chromeos::BackgroundView* background_view) {
-  DCHECK(!background_window_);
-  background_window_ = background_widget;
-  background_view_ = background_view;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // ExistingUserController, NotificationObserver implementation:
 //
@@ -166,9 +138,6 @@
 // ExistingUserController, private:
 
 ExistingUserController::~ExistingUserController() {
-  if (background_window_)
-    background_window_->Close();
-
   DCHECK(current_controller_ != NULL);
   current_controller_ = NULL;
 }
@@ -375,7 +344,7 @@
                                      pending_requests);
 
     // Delay deletion as we're on the stack.
-    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+    host_->OnSessionStart();
   }
 }
 
@@ -450,42 +419,19 @@
 // ExistingUserController, private:
 
 void ExistingUserController::ActivateWizard(const std::string& screen_name) {
-  // WizardController takes care of deleting itself when done.
-  WizardController* controller = new WizardController();
-
-  // Give the background window to the controller.
-  controller->OwnBackground(background_window_, background_view_);
-  background_window_ = NULL;
-
+  GURL start_url;
   if (chromeos::UserManager::Get()->IsLoggedInAsGuest())
-    controller->set_start_url(guest_mode_url_);
-
-  controller->Init(screen_name, background_bounds_);
-
+    start_url = guest_mode_url_;
+  host_->StartWizard(screen_name, NULL, start_url);
   login_display_->OnFadeOut();
-
-  delete_timer_.Start(base::TimeDelta::FromSeconds(1), this,
-                      &ExistingUserController::Delete);
-}
-
-LoginDisplay* ExistingUserController::CreateLoginDisplay(
-    LoginDisplay::Delegate* delegate, const gfx::Rect& background_bounds) {
-  // TODO(rharrison): Create Web UI implementation too. http://crosbug.com/6398.
-  return new ViewsLoginDisplay(delegate, background_bounds);
-}
-
-void ExistingUserController::Delete() {
-  delete this;
 }
 
 gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
-  return background_view_->GetNativeWindow();
+  return host_->GetNativeWindow();
 }
 
 void ExistingUserController::SetStatusAreaEnabled(bool enable) {
-  if (background_view_) {
-    background_view_->SetStatusAreaEnabled(enable);
-  }
+  host_->SetStatusAreaEnabled(enable);
 }
 
 void ExistingUserController::ShowError(int error_id,
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 581f42f..586ad08 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -12,7 +12,6 @@
 #include "base/string16.h"
 #include "base/task.h"
 #include "base/timer.h"
-#include "chrome/browser/chromeos/login/background_view.h"
 #include "chrome/browser/chromeos/login/captcha_view.h"
 #include "chrome/browser/chromeos/login/login_display.h"
 #include "chrome/browser/chromeos/login/login_performer.h"
@@ -27,6 +26,7 @@
 
 namespace chromeos {
 
+class LoginDisplayHost;
 class UserCrosSettingsProvider;
 
 // ExistingUserController is used to handle login when someone has
@@ -43,8 +43,8 @@
                                public PasswordChangedView::Delegate {
  public:
   // All UI initialization is deferred till Init() call.
-  // |background_bounds| determines the bounds of background view.
-  explicit ExistingUserController(const gfx::Rect& background_bounds);
+  explicit ExistingUserController(LoginDisplayHost* host);
+  ~ExistingUserController();
 
   // Returns the current existing user controller if it has been created.
   static ExistingUserController* current_controller() {
@@ -52,16 +52,12 @@
   }
 
   void set_initial_start_page(const std::string& url) {
-      initial_start_page_ = url;
+    initial_start_page_ = url;
   }
 
   // Creates and shows login UI for known users.
   void Init(const UserVector& users);
 
-  // Takes ownership of the specified background widget and view.
-  void OwnBackground(views::Widget* background_widget,
-                     chromeos::BackgroundView* background_view);
-
   // LoginDisplay::Delegate: implementation
   virtual void CreateAccount();
   virtual string16 GetConnectedNetworkName();
@@ -77,11 +73,9 @@
                        const NotificationDetails& details);
 
  private:
-  friend class DeleteTask<ExistingUserController>;
+  friend class ExistingUserControllerTest;
   friend class MockLoginPerformerDelegate;
 
-  ~ExistingUserController();
-
   // LoginPerformer::Delegate implementation:
   virtual void OnLoginFailure(const LoginFailure& error);
   virtual void OnLoginSuccess(
@@ -104,13 +98,6 @@
   // Starts WizardController with the specified screen.
   void ActivateWizard(const std::string& screen_name);
 
-  // Creates LoginDisplay instance based on command line options.
-  LoginDisplay* CreateLoginDisplay(LoginDisplay::Delegate* delegate,
-                                   const gfx::Rect& background_bounds);
-
-  // Wrapper for invoking the destructor. Used by delete_timer_.
-  void Delete();
-
   // Returns corresponding native window.
   gfx::NativeWindow GetNativeWindow() const;
 
@@ -126,13 +113,6 @@
     login_performer_delegate_.reset(d);
   }
 
-  // Bounds of the background window.
-  const gfx::Rect background_bounds_;
-
-  // Background window/view.
-  views::Widget* background_window_;
-  BackgroundView* background_view_;
-
   // Used to execute login operations.
   scoped_ptr<LoginPerformer> login_performer_;
 
@@ -146,14 +126,13 @@
   // Username of the last login attempt.
   std::string last_login_attempt_username_;
 
+  // OOBE/login display host.
+  LoginDisplayHost* host_;
+
   // Number of login attempts. Used to show help link when > 1 unsuccessful
   // logins for the same user.
   size_t num_login_attempts_;
 
-  // Timer which is used to defer deleting and gave abitility to WM to smoothly
-  // hide the windows.
-  base::OneShotTimer<ExistingUserController> delete_timer_;
-
   // Pointer to the current instance of the controller to be used by
   // automation tests.
   static ExistingUserController* current_controller_;
@@ -174,7 +153,6 @@
   ScopedRunnableMethodFactory<ExistingUserController> method_factory_;
 
   FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, NewUserLogin);
-  FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, CreateAccount);
 
   DISALLOW_COPY_AND_ASSIGN(ExistingUserController);
 };
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 5636b3a..3f9fd050 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -3,17 +3,20 @@
 // found in the LICENSE file.
 
 #include "base/message_loop.h"
+#include "base/scoped_ptr.h"
 #include "chrome/browser/chromeos/cros/cros_mock.h"
+#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
 #include "chrome/browser/chromeos/cros/mock_login_library.h"
 #include "chrome/browser/chromeos/cros/mock_network_library.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/login_display.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
 #include "chrome/browser/chromeos/login/login_performer.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/mock_authenticator.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
 #include "grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,10 +27,52 @@
 using ::testing::AnyNumber;
 using ::testing::InvokeWithoutArgs;
 using ::testing::Return;
+using ::testing::ReturnNull;
 
 const char kUsername[] = "[email protected]";
 const char kPassword[] = "test_password";
 
+class MockLoginDisplay : public LoginDisplay {
+ public:
+  MockLoginDisplay()
+      : LoginDisplay(NULL, gfx::Rect()) {
+  }
+
+  MOCK_METHOD3(Init, void(const UserVector&, bool, bool));
+  MOCK_METHOD1(OnUserImageChanged, void(UserManager::User*));
+  MOCK_METHOD0(OnFadeOut, void(void));
+  MOCK_METHOD1(SetUIEnabled, void(bool));
+  MOCK_METHOD3(ShowError, void(int, int, HelpAppLauncher::HelpTopic));
+  MOCK_METHOD1(OnBeforeUserRemoved, void(const std::string&));
+  MOCK_METHOD1(OnUserRemoved, void(const std::string&));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockLoginDisplay);
+};
+
+class MockLoginDisplayHost : public LoginDisplayHost {
+ public:
+  MockLoginDisplayHost() {
+  }
+
+  MOCK_METHOD1(CreateLoginDisplay, LoginDisplay*(LoginDisplay::Delegate*));
+  MOCK_CONST_METHOD0(GetNativeWindow, gfx::NativeWindow(void));
+  MOCK_METHOD0(OnSessionStart, void(void));
+  MOCK_METHOD1(SetOobeProgress, void(BackgroundView::LoginStep));
+  MOCK_METHOD1(SetOobeProgressBarVisible, void(bool));
+  MOCK_METHOD1(SetShutdownButtonEnabled, void(bool));
+  MOCK_METHOD1(SetStatusAreaEnabled, void(bool));
+  MOCK_METHOD1(SetStatusAreaVisible, void(bool));
+  MOCK_METHOD0(ShowBackground, void(void));
+  MOCK_METHOD3(StartWizard, void(const std::string&,
+                                 const chromeos::StartupCustomizationDocument*,
+                                 const GURL&));
+  MOCK_METHOD0(StartSignInScreen, void(void));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockLoginDisplayHost);
+};
+
 class MockLoginPerformerDelegate : public LoginPerformer::Delegate {
  public:
   explicit MockLoginPerformerDelegate(ExistingUserController* controller)
@@ -41,7 +86,6 @@
     LoginPerformer* login_performer = controller_->login_performer_.release();
     login_performer = NULL;
     controller_->ActivateWizard(WizardController::kUserImageScreenName);
-    delete WizardController::default_controller();
   }
 
   MOCK_METHOD1(OnLoginFailure, void(const LoginFailure&));
@@ -53,21 +97,14 @@
   DISALLOW_COPY_AND_ASSIGN(MockLoginPerformerDelegate);
 };
 
-class ExistingUserControllerTest : public WizardInProcessBrowserTest {
+class ExistingUserControllerTest : public CrosInProcessBrowserTest {
  protected:
   ExistingUserControllerTest()
-      : chromeos::WizardInProcessBrowserTest(""),
-        mock_cryptohome_library_(NULL),
+      : mock_cryptohome_library_(NULL),
         mock_login_library_(NULL),
-        mock_network_library_(NULL) {
-  }
-
-  virtual void SetUpWizard() {
-    gfx::Rect background_bounds(login::kWizardScreenWidth,
-                                login::kWizardScreenHeight);
-    ExistingUserController* controller =
-        new ExistingUserController(background_bounds);
-    controller->Init(UserVector());
+        mock_network_library_(NULL),
+        mock_login_display_(NULL),
+        mock_login_display_host_(NULL) {
   }
 
   ExistingUserController* existing_user_controller() {
@@ -75,12 +112,11 @@
   }
 
   virtual void SetUpInProcessBrowserTestFixture() {
-    WizardInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
     cros_mock_->InitStatusAreaMocks();
     cros_mock_->SetStatusAreaMocksExpectations();
 
     mock_network_library_ = cros_mock_->mock_network_library();
-
     mock_login_library_ = new MockLoginLibrary();
     EXPECT_CALL(*mock_login_library_, EmitLoginPromptReady())
         .Times(1);
@@ -99,26 +135,58 @@
         .Times(1)
         .WillOnce(Return(true));
     LoginUtils::Set(new MockLoginUtils(kUsername, kPassword));
+
+    mock_login_display_.reset(new MockLoginDisplay());
+    mock_login_display_host_.reset(new MockLoginDisplayHost());
+
+    EXPECT_CALL(*mock_login_display_host_.get(), CreateLoginDisplay(_))
+        .Times(1)
+        .WillOnce(Return(mock_login_display_.get()));
+    EXPECT_CALL(*mock_login_display_host_.get(), GetNativeWindow())
+        .Times(1)
+        .WillOnce(ReturnNull());
+    EXPECT_CALL(*mock_login_display_.get(), Init(_, false, true))
+        .Times(1);
+  }
+
+  virtual void SetUpOnMainThread() {
+    ExistingUserController* controller =
+        new ExistingUserController(mock_login_display_host_.get());
+    controller->Init(UserVector());
+    MockLoginPerformerDelegate* mock_delegate =
+          new MockLoginPerformerDelegate(controller);
+    existing_user_controller()->set_login_performer_delegate(mock_delegate);
   }
 
   virtual void TearDownInProcessBrowserTestFixture() {
-    WizardInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+    CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
     cros_mock_->test_api()->SetLoginLibrary(NULL, false);
   }
 
+  // These mocks are owned by CrosLibrary class.
   MockCryptohomeLibrary* mock_cryptohome_library_;
   MockLoginLibrary* mock_login_library_;
   MockNetworkLibrary* mock_network_library_;
 
+  scoped_ptr<MockLoginDisplay> mock_login_display_;
+  scoped_ptr<MockLoginDisplayHost> mock_login_display_host_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ExistingUserControllerTest);
 };
 
 IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest, NewUserLogin) {
-  MockLoginPerformerDelegate* mock_delegate =
-      new MockLoginPerformerDelegate(existing_user_controller());
-  existing_user_controller()->set_login_performer_delegate(mock_delegate);
-
+  EXPECT_CALL(*mock_login_display_host_, SetStatusAreaEnabled(false))
+      .Times(1);
+  EXPECT_CALL(*mock_login_display_, SetUIEnabled(false))
+      .Times(1);
+  EXPECT_CALL(*mock_login_display_host_,
+              StartWizard(WizardController::kUserImageScreenName,
+                          NULL,
+                          GURL()))
+      .Times(1);
+  EXPECT_CALL(*mock_login_display_, OnFadeOut())
+      .Times(1);
   existing_user_controller()->Login(kUsername, kPassword);
 }
 
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index d8bab93..c7ea662 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/chromeos/login/helper.h"
 
+#include "base/file_util.h"
 #include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/customization_document.h"
 #include "chrome/browser/google/google_util.h"
 #include "googleurl/src/gurl.h"
 #include "grit/generated_resources.h"
@@ -39,6 +41,10 @@
 const char kAccountRecoveryHelpUrl[] =
     "http://www.google.com/support/accounts/bin/answer.py?answer=48598";
 
+// Path to OEM partner startup customization manifest.
+const char kStartupCustomizationManifestPath[] =
+    "/opt/oem/etc/startup_manifest.json";
+
 class BackgroundPainter : public views::Painter {
  public:
   BackgroundPainter() {}
@@ -210,6 +216,27 @@
   }
 }
 
+const chromeos::StartupCustomizationDocument* LoadStartupManifest() {
+  // Loading manifest causes us to do blocking IO on UI thread.
+  // Temporarily allow it until we fix http://crosbug.com/11103
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  FilePath startup_manifest_path(kStartupCustomizationManifestPath);
+  if (file_util::PathExists(startup_manifest_path)) {
+    scoped_ptr<chromeos::StartupCustomizationDocument> customization(
+        new chromeos::StartupCustomizationDocument());
+    bool manifest_loaded = customization->LoadManifestFromFile(
+        startup_manifest_path);
+    if (manifest_loaded) {
+      VLOG(1) << "Startup manifest loaded successfully";
+      return customization.release();
+    }
+    LOG(ERROR) << "Error loading startup manifest: "
+               << kStartupCustomizationManifestPath;
+  }
+
+  return NULL;
+}
+
 namespace login {
 
 gfx::Size WideButton::GetPreferredSize() {
diff --git a/chrome/browser/chromeos/login/helper.h b/chrome/browser/chromeos/login/helper.h
index bb7c7ac..a3710879 100644
--- a/chrome/browser/chromeos/login/helper.h
+++ b/chrome/browser/chromeos/login/helper.h
@@ -33,6 +33,7 @@
 
 namespace chromeos {
 
+class StartupCustomizationDocument;
 class NetworkLibrary;
 
 // View that provides interface for start/stop throbber above the view.
@@ -104,6 +105,10 @@
 // Ethernet > WiFi > Cellular. Same for connecting network.
 string16 GetCurrentNetworkName(NetworkLibrary* network_library);
 
+// Load OEM partner startup customization manifest
+// containing locale, timezone, EULA, etc.
+const chromeos::StartupCustomizationDocument* LoadStartupManifest();
+
 // Define the constants in |login| namespace to avoid potential
 // conflict with other chromeos components.
 namespace login {
diff --git a/chrome/browser/chromeos/login/login_display.cc b/chrome/browser/chromeos/login/login_display.cc
new file mode 100644
index 0000000..932654f
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_display.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/login_display.h"
+
+namespace chromeos {
+
+LoginDisplay::Delegate::~Delegate() {}
+
+LoginDisplay::LoginDisplay(Delegate* delegate,
+                           const gfx::Rect& background_bounds)
+    : delegate_(delegate),
+      parent_window_(NULL),
+      background_bounds_(background_bounds) {
+}
+
+LoginDisplay::~LoginDisplay() {}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_display.h b/chrome/browser/chromeos/login/login_display.h
index a705cdb..c6aedcdc 100644
--- a/chrome/browser/chromeos/login/login_display.h
+++ b/chrome/browser/chromeos/login/login_display.h
@@ -27,6 +27,7 @@
   virtual void OnUserRemoved(const std::string& username) = 0;
 };
 
+// TODO(nkostylev): Extract interface, create a BaseLoginDisplay class.
 // An abstract class that defines login UI implementation.
 class LoginDisplay : public RemoveUserDelegate {
  public:
@@ -52,15 +53,12 @@
     // Called when existing user pod is selected in the UI.
     virtual void OnUserSelected(const std::string& username) = 0;
    protected:
-    virtual ~Delegate() {}
+    virtual ~Delegate();
   };
 
   // |background_bounds| determines the bounds of login UI background.
-  LoginDisplay(Delegate* delegate, const gfx::Rect& background_bounds)
-      : delegate_(delegate),
-        parent_window_(NULL),
-        background_bounds_(background_bounds) {}
-  virtual ~LoginDisplay() {}
+  LoginDisplay(Delegate* delegate, const gfx::Rect& background_bounds);
+  virtual ~LoginDisplay();
 
   // Initializes login UI with the user pods based on list of known users and
   // guest, new user pods if those are enabled.
diff --git a/chrome/browser/chromeos/login/login_display_host.h b/chrome/browser/chromeos/login/login_display_host.h
new file mode 100644
index 0000000..9820d67
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_display_host.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_DISPLAY_HOST_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_DISPLAY_HOST_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/customization_document.h"
+#include "chrome/browser/chromeos/login/login_display.h"
+#include "googleurl/src/gurl.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace chromeos {
+
+// An interface that defines OOBE/login screen host.
+// Host encapsulates implementation specific background window (views/WebUI),
+// OOBE/login controllers, views/WebUI UI implementation (such as LoginDisplay).
+class LoginDisplayHost {
+ public:
+  virtual ~LoginDisplayHost() {}
+
+  // Creates UI implementation specific login display instance (views/WebUI).
+  virtual LoginDisplay* CreateLoginDisplay(
+      LoginDisplay::Delegate* delegate) = 0;
+
+  // Returns corresponding native window.
+  // TODO(nkostylev): Might be refactored, move to views-specific code.
+  virtual gfx::NativeWindow GetNativeWindow() const = 0;
+
+  // Called when browsing session starts so
+  // LoginDisplayHost instance may delete itself.
+  virtual void OnSessionStart() = 0;
+
+  // TODO(nkostylev): Refactor enum.
+  // Sets current step on OOBE progress bar.
+  virtual void SetOobeProgress(BackgroundView::LoginStep step) = 0;
+
+  // Toggles OOBE progress bar visibility, the bar is hidden by default.
+  virtual void SetOobeProgressBarVisible(bool visible) = 0;
+
+  // Enable/disable shutdown button.
+  virtual void SetShutdownButtonEnabled(bool enable) = 0;
+
+  // Toggles whether status area is enabled.
+  virtual void SetStatusAreaEnabled(bool enable) = 0;
+
+  // Toggles status area visibility.
+  virtual void SetStatusAreaVisible(bool visible) = 0;
+
+  // Creates and shows a background window.
+  virtual void ShowBackground() = 0;
+
+  // Starts out-of-box-experience flow or shows other screen handled by
+  // Wizard controller i.e. camera, recovery.
+  // One could specify start screen with |first_screen_name|.
+  virtual void StartWizard(
+      const std::string& first_screen_name,
+      const chromeos::StartupCustomizationDocument* manifest,
+      const GURL& start_url) = 0;
+
+  // Starts sign in screen.
+  virtual void StartSignInScreen() = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_DISPLAY_HOST_H_
diff --git a/chrome/browser/chromeos/login/views_login_display_host.cc b/chrome/browser/chromeos/login/views_login_display_host.cc
new file mode 100644
index 0000000..f3a763a3
--- /dev/null
+++ b/chrome/browser/chromeos/login/views_login_display_host.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/views_login_display_host.h"
+
+#include "chrome/browser/chromeos/login/views_login_display.h"
+
+namespace chromeos {
+
+// ViewsLoginDisplayHost -------------------------------------------------------
+
+ViewsLoginDisplayHost::ViewsLoginDisplayHost(const gfx::Rect& background_bounds)
+    : BaseLoginDisplayHost(background_bounds),
+      background_view_(NULL),
+      background_window_(NULL) {
+}
+
+ViewsLoginDisplayHost::~ViewsLoginDisplayHost() {
+  if (background_window_)
+    background_window_->Close();
+}
+
+// LoginDisplayHost implementation -----------------------------------------
+
+LoginDisplay* ViewsLoginDisplayHost::CreateLoginDisplay(
+    LoginDisplay::Delegate* delegate) {
+  return new ViewsLoginDisplay(delegate, background_bounds());
+}
+
+gfx::NativeWindow ViewsLoginDisplayHost::GetNativeWindow() const {
+  if (background_view_)
+    return background_view_->GetNativeWindow();
+  else
+    return NULL;
+}
+
+void ViewsLoginDisplayHost::SetOobeProgress(BackgroundView::LoginStep step) {
+  if (background_view_)
+    background_view_->SetOobeProgress(step);
+}
+
+void ViewsLoginDisplayHost::SetOobeProgressBarVisible(bool visible) {
+  if (background_view_)
+    background_view_->SetOobeProgressBarVisible(visible);
+}
+
+void ViewsLoginDisplayHost::SetShutdownButtonEnabled(bool enable) {
+  if (background_view_)
+    background_view_->EnableShutdownButton(enable);
+}
+
+void ViewsLoginDisplayHost::SetStatusAreaEnabled(bool enable) {
+  if (background_view_)
+    background_view_->SetStatusAreaEnabled(enable);
+}
+
+void ViewsLoginDisplayHost::SetStatusAreaVisible(bool visible) {
+  if (background_view_)
+    background_view_->SetStatusAreaVisible(visible);
+}
+
+void ViewsLoginDisplayHost::ShowBackground() {
+  if (background_window_) {
+    background_window_->Show();
+    return;
+  }
+  background_window_ =
+      BackgroundView::CreateWindowContainingView(background_bounds(),
+                                                 GURL(),
+                                                 &background_view_);
+  background_window_->Show();
+}
+
+}  // namespace chromeos
+
diff --git a/chrome/browser/chromeos/login/views_login_display_host.h b/chrome/browser/chromeos/login/views_login_display_host.h
new file mode 100644
index 0000000..976db90
--- /dev/null
+++ b/chrome/browser/chromeos/login/views_login_display_host.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_VIEWS_LOGIN_DISPLAY_HOST_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_VIEWS_LOGIN_DISPLAY_HOST_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/login/base_login_display_host.h"
+#include "ui/gfx/rect.h"
+
+namespace chromeos {
+
+// Views-specific implementation of the OOBE/login screen host.
+// Uses ViewsLoginDisplay as the login screen UI implementation,
+// BackgroundView as the background UI implementation.
+// In its current implementation BackgroundView encapsulates StatusAreaView.
+class ViewsLoginDisplayHost : public chromeos::BaseLoginDisplayHost {
+ public:
+  explicit ViewsLoginDisplayHost(const gfx::Rect& background_bounds);
+  virtual ~ViewsLoginDisplayHost();
+
+  // LoginDisplayHost implementation:
+  virtual LoginDisplay* CreateLoginDisplay(LoginDisplay::Delegate* delegate);
+  virtual gfx::NativeWindow GetNativeWindow() const;
+  virtual void SetOobeProgress(BackgroundView::LoginStep step);
+  virtual void SetOobeProgressBarVisible(bool visible);
+  virtual void SetShutdownButtonEnabled(bool enable);
+  virtual void SetStatusAreaEnabled(bool enable);
+  virtual void SetStatusAreaVisible(bool visible);
+  virtual void ShowBackground();
+
+ private:
+  // Background view/window.
+  BackgroundView* background_view_;
+  views::Widget* background_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewsLoginDisplayHost);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_VIEWS_LOGIN_DISPLAY_HOST_H_
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index b936eac6..e09dcf2 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -18,40 +18,28 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/cros/cros_library.h"
 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
-#include "chrome/browser/chromeos/cros/input_method_library.h"
-#include "chrome/browser/chromeos/cros/login_library.h"
-#include "chrome/browser/chromeos/cros/system_library.h"
 #include "chrome/browser/chromeos/customization_document.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/login/account_screen.h"
 #include "chrome/browser/chromeos/login/apply_services_customization.h"
-#include "chrome/browser/chromeos/login/background_view.h"
 #include "chrome/browser/chromeos/login/eula_view.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/html_page_screen.h"
-#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/network_screen.h"
 #include "chrome/browser/chromeos/login/registration_screen.h"
-#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
 #include "chrome/browser/chromeos/login/update_screen.h"
 #include "chrome/browser/chromeos/login/user_image_screen.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
-#include "chrome/browser/chromeos/wm_ipc.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/common/notification_service.h"
 #include "content/common/notification_type.h"
-#include "third_party/cros/chromeos_wm_ipc_enums.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "unicode/timezone.h"
 #include "views/accelerator.h"
-#include "views/painter.h"
 #include "views/view.h"
 #include "views/widget/widget_gtk.h"
 
@@ -66,10 +54,6 @@
 // A boolean pref of the device registered flag (second part after first login).
 const char kDeviceRegistered[] = "DeviceRegistered";
 
-// Path to OEM partner startup customization manifest.
-const char kStartupCustomizationManifestPath[] =
-    "/opt/oem/etc/startup_manifest.json";
-
 // Path to flag file indicating that both parts of OOBE were completed.
 const char kOobeCompleteFlagFilePath[] = "/home/chronos/.oobe_completed";
 
@@ -167,8 +151,6 @@
   }
 
  private:
-  scoped_ptr<views::Painter> painter_;
-
 #if !defined(OFFICIAL_BUILD)
   views::Accelerator accel_account_screen_;
   views::Accelerator accel_login_screen_;
@@ -184,38 +166,6 @@
   DISALLOW_COPY_AND_ASSIGN(ContentView);
 };
 
-void DeleteWizardControllerAndLaunchBrowser(WizardController* controller) {
-  delete controller;
-  // Launch browser after controller is deleted and its windows are closed.
-  chromeos::LoginUtils::Get()->EnableBrowserLaunch(true);
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      NewRunnableFunction(&chromeos::LoginUtils::DoBrowserLaunch,
-                          ProfileManager::GetDefaultProfile()));
-}
-
-const chromeos::StartupCustomizationDocument* LoadStartupManifest() {
-  // Loading manifest causes us to do blocking IO on UI thread.
-  // Temporarily allow it until we fix http://crosbug.com/11103
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-  FilePath startup_manifest_path(kStartupCustomizationManifestPath);
-  if (file_util::PathExists(startup_manifest_path)) {
-    scoped_ptr<chromeos::StartupCustomizationDocument> customization(
-        new chromeos::StartupCustomizationDocument());
-    bool manifest_loaded = customization->LoadManifestFromFile(
-        startup_manifest_path);
-    if (manifest_loaded) {
-      VLOG(1) << "Startup manifest loaded successfully";
-      return customization.release();
-    }
-    LOG(ERROR) << "Error loading startup manifest: "
-               << kStartupCustomizationManifestPath;
-  }
-
-  return NULL;
-}
-
 // Returns true if startup manifest defines valid registration URL.
 bool IsRegistrationScreenValid(
     const chromeos::StartupCustomizationDocument* startup_manifest) {
@@ -237,40 +187,6 @@
   prefs->SavePersistentPrefs();
 }
 
-// Determines the hardware keyboard from the given locale code
-// and the OEM layout information, and saves it to "Locale State".
-// The information will be used in input_method::GetHardwareInputMethodId().
-void DetermineAndSaveHardwareKeyboard(const std::string& locale,
-                                      const std::string& oem_layout) {
-  std::string layout;
-  if (!oem_layout.empty()) {
-    // If the OEM layout information is provided, use it.
-    layout = oem_layout;
-  } else {
-    // Otherwise, determine the hardware keyboard from the locale.
-    std::vector<std::string> input_method_ids;
-    if (chromeos::input_method::GetInputMethodIdsFromLanguageCode(
-            locale,
-            chromeos::input_method::kKeyboardLayoutsOnly,
-            &input_method_ids)) {
-      // The output list |input_method_ids| is sorted by popularity, hence
-      // input_method_ids[0] now contains the most popular keyboard layout
-      // for the given locale.
-      layout = input_method_ids[0];
-    }
-  }
-
-  if (!layout.empty()) {
-    PrefService* prefs = g_browser_process->local_state();
-    prefs->SetString(prefs::kHardwareKeyboardLayout, layout);
-    // This asks the file thread to save the prefs (i.e. doesn't block).
-    // The latest values of Local State reside in memory so we can safely
-    // get the value of kHardwareKeyboardLayout even if the data is not
-    // yet saved to disk.
-    prefs->SavePersistentPrefs();
-  }
-}
-
 }  // namespace
 
 const char WizardController::kNetworkScreenName[] = "network";
@@ -295,43 +211,38 @@
 ///////////////////////////////////////////////////////////////////////////////
 // WizardController, public:
 
-WizardController::WizardController()
+WizardController::WizardController(chromeos::LoginDisplayHost* host,
+                                   const gfx::Rect& screen_bounds)
     : widget_(NULL),
-      background_widget_(NULL),
-      background_view_(NULL),
       contents_(NULL),
+      screen_bounds_(screen_bounds),
       current_screen_(NULL),
       initial_show_(true),
+      is_active_(true),
 #if defined(OFFICIAL_BUILD)
       is_official_build_(true),
 #else
       is_official_build_(false),
 #endif
       is_out_of_box_(false),
+      host_(host),
       observer_(NULL) {
   DCHECK(default_controller_ == NULL);
   default_controller_ = this;
-  registrar_.Add(
-      this,
-      NotificationType::APP_TERMINATING,
-      NotificationService::AllSources());
 }
 
 WizardController::~WizardController() {
-  // Close ends up deleting the widget.
-  if (background_widget_)
-    background_widget_->Close();
-
-  if (widget_)
+  if (widget_) {
     widget_->Close();
+    widget_ = NULL;
+  }
 
   default_controller_ = NULL;
   chromeos::WizardAccessibilityHelper::GetInstance()->
       UnregisterNotifications();
 }
 
-void WizardController::Init(const std::string& first_screen_name,
-                            const gfx::Rect& screen_bounds) {
+void WizardController::Init(const std::string& first_screen_name) {
   VLOG(1) << "Starting OOBE wizard with screen: " << first_screen_name;
   DCHECK(!contents_);
   first_screen_name_ = first_screen_name;
@@ -340,9 +251,8 @@
   // In case of OOBE (network-EULA-update) manifest has been loaded in
   // ShowLoginWizard().
   if (IsOobeCompleted() && !IsDeviceRegistered())
-    SetCustomization(LoadStartupManifest());
+    SetCustomization(chromeos::LoadStartupManifest());
 
-  screen_bounds_ = screen_bounds;
   contents_ = new ContentView();
 
   bool oobe_complete = IsOobeCompleted();
@@ -353,24 +263,6 @@
   ShowFirstScreen(first_screen_name);
 }
 
-void WizardController::ShowBackground(const gfx::Rect& bounds) {
-  DCHECK(!background_widget_);
-  background_widget_ =
-      chromeos::BackgroundView::CreateWindowContainingView(bounds,
-                                                           GURL(),
-                                                           &background_view_);
-  background_view_->SetOobeProgressBarVisible(true);
-  background_widget_->Show();
-}
-
-void WizardController::OwnBackground(
-    views::Widget* background_widget,
-    chromeos::BackgroundView* background_view) {
-  DCHECK(!background_widget_);
-  background_widget_ = background_widget;
-  background_view_ = background_view;
-}
-
 void WizardController::CancelOOBEUpdate() {
   if (update_screen_.get() &&
       update_screen_.get() == current_screen_) {
@@ -436,32 +328,17 @@
 void WizardController::ShowNetworkScreen() {
   SetStatusAreaVisible(false);
   SetCurrentScreen(GetNetworkScreen());
-  background_view_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
+  host_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
 }
 
-chromeos::ExistingUserController* WizardController::ShowLoginScreen() {
+void WizardController::ShowLoginScreen() {
   SetStatusAreaVisible(true);
-  background_view_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
-
-  // Initiate services customization.
-  chromeos::ApplyServicesCustomization::StartIfNeeded();
-
-  std::vector<chromeos::UserManager::User> users;
-  if (chromeos::CrosLibrary::Get()->EnsureLoaded())
-    users = chromeos::UserManager::Get()->GetUsers();
-
-  // ExistingUserController deletes itself.
-  gfx::Rect screen_bounds = background_widget_->GetWindowScreenBounds();
-  chromeos::ExistingUserController* controller =
-      new chromeos::ExistingUserController(screen_bounds);
-  controller->OwnBackground(background_widget_, background_view_);
-  controller->Init(users);
-  background_widget_ = NULL;
-  background_view_ = NULL;
-
-  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-
-  return controller;
+  host_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
+  host_->StartSignInScreen();
+  smooth_show_timer_.Stop();
+  widget_->Close();
+  widget_ = NULL;
+  is_active_ = false;
 }
 
 void WizardController::ShowAccountScreen() {
@@ -476,9 +353,9 @@
   SetCurrentScreen(GetUpdateScreen());
   // There is no special step for update.
 #if defined(OFFICIAL_BUILD)
-  background_view_->SetOobeProgress(chromeos::BackgroundView::EULA);
+  host_->SetOobeProgress(chromeos::BackgroundView::EULA);
 #else
-  background_view_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
+  host_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
 #endif
 }
 
@@ -486,8 +363,8 @@
   VLOG(1) << "Showing user image screen.";
   SetStatusAreaVisible(false);
   SetCurrentScreen(GetUserImageScreen());
-  background_view_->SetOobeProgress(chromeos::BackgroundView::PICTURE);
-  background_view_->EnableShutdownButton(false);
+  host_->SetOobeProgress(chromeos::BackgroundView::PICTURE);
+  host_->SetShutdownButtonEnabled(false);
 }
 
 void WizardController::ShowEulaScreen() {
@@ -495,7 +372,7 @@
   SetStatusAreaVisible(false);
   SetCurrentScreen(GetEulaScreen());
 #if defined(OFFICIAL_BUILD)
-  background_view_->SetOobeProgress(chromeos::BackgroundView::EULA);
+  host_->SetOobeProgress(chromeos::BackgroundView::EULA);
 #endif
 }
 
@@ -510,14 +387,14 @@
   SetStatusAreaVisible(true);
   SetCurrentScreen(GetRegistrationScreen());
 #if defined(OFFICIAL_BUILD)
-  background_view_->SetOobeProgress(chromeos::BackgroundView::REGISTRATION);
+  host_->SetOobeProgress(chromeos::BackgroundView::REGISTRATION);
 #endif
 }
 
 void WizardController::ShowHTMLPageScreen() {
   VLOG(1) << "Showing HTML page screen.";
   SetStatusAreaVisible(true);
-  background_view_->SetOobeProgressBarVisible(false);
+  host_->SetOobeProgressBarVisible(false);
   SetCurrentScreen(GetHTMLPageScreen());
 }
 
@@ -538,18 +415,6 @@
     LOG(ERROR) << "Registration screen is not active.";
 }
 
-void WizardController::Observe(NotificationType type,
-                               const NotificationSource& source,
-                               const NotificationDetails& details) {
-  CHECK(type == NotificationType::APP_TERMINATING);
-
-  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-  MessageLoop::current()->Quit();
-  registrar_.Remove(this,
-                    NotificationType::APP_TERMINATING,
-                    NotificationService::AllSources());
-}
-
 // static
 void WizardController::RegisterPrefs(PrefService* local_state) {
   local_state->RegisterBooleanPref(kOobeComplete, false);
@@ -591,9 +456,7 @@
 }
 
 void WizardController::OnAccountCreated() {
-  chromeos::ExistingUserController* controller = ShowLoginScreen();
-  DCHECK(controller);
-  controller->Login(username_, password_);
+  ShowLoginScreen();
   // TODO(dpolukhin): clear password memory for real. Now it is not
   // a problem because we can't extract password from the form.
   password_.clear();
@@ -637,14 +500,16 @@
 }
 
 void WizardController::OnUserImageSelected() {
-  // We're on the stack, so don't try and delete us now.
-  // We should launch browser only after we delete the controller and close
-  // its windows.
+  // Notify host that we're about to launch browser session.
+  // Host will mark itself (and all controllers/windows) for deletion.
+  host_->OnSessionStart();
+  // Launch browser after controller is deleted and its windows are closed.
+  chromeos::LoginUtils::Get()->EnableBrowserLaunch(true);
   BrowserThread::PostTask(
       BrowserThread::UI,
       FROM_HERE,
-      NewRunnableFunction(&DeleteWizardControllerAndLaunchBrowser,
-                          this));
+      NewRunnableFunction(&chromeos::LoginUtils::DoBrowserLaunch,
+                          ProfileManager::GetDefaultProfile()));
   // TODO(avayvod): Sync image with Google Sync.
 }
 
@@ -717,6 +582,11 @@
 }
 
 void WizardController::ShowCurrentScreen() {
+  // ShowCurrentScreen may get called by smooth_show_timer_ even after
+  // flow has been switched to sign in screen (ExistingUserController).
+  if (!is_active_)
+    return;
+
   smooth_show_timer_.Stop();
 
   bool force_widget_show = false;
@@ -773,11 +643,7 @@
 }
 
 void WizardController::SetStatusAreaVisible(bool visible) {
-  // When ExistingUserController passes background ownership
-  // to WizardController it happens after screen is shown.
-  if (background_view_) {
-    background_view_->SetStatusAreaVisible(visible);
-  }
+  host_->SetStatusAreaVisible(visible);
 }
 
 void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
@@ -883,7 +749,7 @@
   if (default_controller())
     manifest = default_controller()->GetCustomization();
   else
-    manifest = LoadStartupManifest();
+    manifest = chromeos::LoadStartupManifest();
   return IsRegistrationScreenValid(manifest);
 }
 
@@ -959,127 +825,3 @@
 void WizardController::SetZeroDelays() {
   kShowDelayMs = 0;
 }
-
-namespace browser {
-
-// Declared in browser_dialogs.h so that others don't need to depend on our .h.
-void ShowLoginWizard(const std::string& first_screen_name,
-                     const gfx::Size& size) {
-  VLOG(1) << "Showing login screen: " << first_screen_name;
-
-  // The login screen will enable alternate keyboard layouts, but we don't want
-  // to start the IME process unless one is selected.
-  chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
-      SetDeferImeStartup(true);
-  // Tell the window manager that the user isn't logged in.
-  chromeos::WmIpc::instance()->SetLoggedInProperty(false);
-
-  // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
-  // and US dvorak keyboard layouts.
-  if (g_browser_process && g_browser_process->local_state()) {
-    const std::string locale = g_browser_process->GetApplicationLocale();
-    // If the preferred keyboard for the login screen has been saved, use it.
-    const std::string initial_input_method_id =
-        g_browser_process->local_state()->GetString(
-            chromeos::language_prefs::kPreferredKeyboardLayout);
-    chromeos::input_method::EnableInputMethods(
-        locale, chromeos::input_method::kKeyboardLayoutsOnly,
-        initial_input_method_id);
-  }
-
-  gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size));
-
-  // Check whether we need to execute OOBE process.
-  bool oobe_complete = WizardController::IsOobeCompleted();
-  bool show_login_screen =
-      (first_screen_name.empty() && oobe_complete) ||
-      first_screen_name == WizardController::kLoginScreenName;
-
-  if (show_login_screen && chromeos::CrosLibrary::Get()->EnsureLoaded()) {
-    std::vector<chromeos::UserManager::User> users =
-        chromeos::UserManager::Get()->GetUsers();
-
-    // Fix for users who updated device and thus never passed register screen.
-    // If we already have users, we assume that it is not a second part of
-    // OOBE. See http://crosbug.com/6289
-    if (!WizardController::IsDeviceRegistered() && !users.empty()) {
-      VLOG(1) << "Mark device registered because there are remembered users: "
-              << users.size();
-      WizardController::MarkDeviceRegistered();
-    }
-
-    // ExistingUserController deletes itself.
-    (new chromeos::ExistingUserController(screen_bounds))->Init(users);
-
-    // Initiate services customization.
-    chromeos::ApplyServicesCustomization::StartIfNeeded();
-
-    return;
-  }
-
-  // Create and show the wizard.
-  WizardController* controller = new WizardController();
-
-  // Load startup manifest.
-  controller->SetCustomization(LoadStartupManifest());
-
-  std::string locale;
-  if (controller->GetCustomization()) {
-    // Switch to initial locale if specified by customization
-    // and has not been set yet. We cannot call
-    // chromeos::LanguageSwitchMenu::SwitchLanguage here before
-    // EmitLoginPromptReady.
-    const std::string current_locale =
-        g_browser_process->local_state()->GetString(prefs::kApplicationLocale);
-    VLOG(1) << "Current locale: " << current_locale;
-    if (current_locale.empty()) {
-      locale = controller->GetCustomization()->initial_locale();
-      std::string layout = controller->GetCustomization()->keyboard_layout();
-      VLOG(1) << "Initial locale: " << locale
-              << "keyboard layout " << layout;
-      if (!locale.empty()) {
-        // Determine keyboard layout from OEM customization (if provided) or
-        // initial locale and save it in preferences.
-        DetermineAndSaveHardwareKeyboard(locale, layout);
-        // Then, enable the hardware keyboard.
-        chromeos::input_method::EnableInputMethods(
-            locale,
-            chromeos::input_method::kKeyboardLayoutsOnly,
-            chromeos::input_method::GetHardwareInputMethodId());
-        // Reloading resource bundle causes us to do blocking IO on UI thread.
-        // Temporarily allow it until we fix http://crosbug.com/11102
-        base::ThreadRestrictions::ScopedAllowIO allow_io;
-        const std::string loaded_locale =
-            ResourceBundle::ReloadSharedInstance(locale);
-        CHECK(!loaded_locale.empty()) << "Locale could not be found for "
-                                      << locale;
-        // Set the application locale here so that the language switch
-        // menu works properly with the newly loaded locale.
-        g_browser_process->SetApplicationLocale(loaded_locale);
-      }
-    }
-  }
-
-  controller->ShowBackground(screen_bounds);
-  controller->Init(first_screen_name, screen_bounds);
-
-  chromeos::LoginUtils::Get()->PrewarmAuthentication();
-  if (chromeos::CrosLibrary::Get()->EnsureLoaded())
-    chromeos::CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
-
-  if (controller->GetCustomization()) {
-    // Set initial timezone if specified by customization.
-    const std::string timezone_name =
-        controller->GetCustomization()->initial_timezone();
-    VLOG(1) << "Initial time zone: " << timezone_name;
-    // Apply locale customizations only once so preserve whatever locale
-    // user has changed to during OOBE.
-    if (!timezone_name.empty()) {
-      icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
-          icu::UnicodeString::fromUTF8(timezone_name));
-      chromeos::CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
-    }
-  }
-}
-
-}  // namespace browser
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index a7fc3fd..551f659 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -14,8 +14,6 @@
 #include "chrome/browser/chromeos/login/screen_observer.h"
 #include "chrome/browser/chromeos/login/view_screen.h"
 #include "chrome/browser/chromeos/login/wizard_screen.h"
-#include "content/common/notification_observer.h"
-#include "content/common/notification_registrar.h"
 #include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 #include "ui/gfx/rect.h"
@@ -26,10 +24,10 @@
 
 namespace chromeos {
 class AccountScreen;
-class BackgroundView;
 class EulaScreen;
 class ExistingUserController;
 class HTMLPageScreen;
+class LoginDisplayHost;
 class NetworkScreen;
 class RegistrationScreen;
 class StartupCustomizationDocument;
@@ -51,10 +49,10 @@
 // Class that manages control flow between wizard screens. Wizard controller
 // interacts with screen controllers to move the user between screens.
 class WizardController : public chromeos::ScreenObserver,
-                         public WizardScreenDelegate,
-                         public NotificationObserver {
+                         public WizardScreenDelegate {
  public:
-  WizardController();
+  explicit WizardController(chromeos::LoginDisplayHost* host,
+                            const gfx::Rect& screen_bounds);
   ~WizardController();
 
   // Returns the default wizard controller if it has been created.
@@ -86,19 +84,11 @@
   // Shows the first screen defined by |first_screen_name| or by default
   // if the parameter is empty. |screen_bounds| are used to calculate position
   // of the wizard screen.
-  void Init(const std::string& first_screen_name,
-            const gfx::Rect& screen_bounds);
+  void Init(const std::string& first_screen_name);
 
   // Returns the view that contains all the other views.
   views::View* contents() { return contents_; }
 
-  // Creates and shows a background window.
-  void ShowBackground(const gfx::Rect& bounds);
-
-  // Takes ownership of the specified background widget and view.
-  void OwnBackground(views::Widget* background_widget,
-                     chromeos::BackgroundView* background_view);
-
   // Skips OOBE update screen if it's currently shown.
   void CancelOOBEUpdate();
 
@@ -119,9 +109,9 @@
   void ShowEulaScreen();
   void ShowRegistrationScreen();
   void ShowHTMLPageScreen();
-  // Shows images login screen and returns the corresponding controller
-  // instance for optional tweaking.
-  chromeos::ExistingUserController* ShowLoginScreen();
+
+  // Shows images login screen.
+  void ShowLoginScreen();
 
   // Returns a pointer to the current screen or NULL if there's no such
   // screen.
@@ -158,11 +148,6 @@
   static const char kEulaScreenName[];
   static const char kHTMLPageScreenName[];
 
-  // NotificationObserver implementation:
-  virtual void Observe(NotificationType type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details);
-
  private:
   // Exit handlers:
   void OnNetworkConnected();
@@ -226,10 +211,6 @@
   // Widget we're showing in.
   views::Widget* widget_;
 
-  // Used to render the background.
-  views::Widget* background_widget_;
-  chromeos::BackgroundView* background_view_;
-
   // Contents view.
   views::View* contents_;
 
@@ -254,6 +235,9 @@
   std::string username_;
   std::string password_;
 
+  // True if controller is active and should proceed things like Timer.
+  bool is_active_;
+
   // True if running official BUILD.
   bool is_official_build_;
 
@@ -263,6 +247,9 @@
   // Value of the screen name that WizardController was started with.
   std::string first_screen_name_;
 
+  // OOBE/login display host.
+  chromeos::LoginDisplayHost* host_;
+
   // NULL by default - controller itself is observer. Mock could be assigned.
   ScreenObserver* observer_;
 
@@ -275,8 +262,6 @@
   // URL to open on browser launch.
   GURL start_url_;
 
-  NotificationRegistrar registrar_;
-
   base::OneShotTimer<WizardController> smooth_show_timer_;
 
   FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, ControlFlowErrorNetwork);
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index ff15ac7..ece6d7c9 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -69,9 +69,7 @@
   DISALLOW_COPY_AND_ASSIGN(WizardControllerTest);
 };
 
-// TODO(zelidrag): Need to revisit this once translation for fr and ar is
-// complete.  See http://crosbug.com/8974
-IN_PROC_BROWSER_TEST_F(WizardControllerTest, FAILS_SwitchLanguage) {
+IN_PROC_BROWSER_TEST_F(WizardControllerTest, SwitchLanguage) {
   WizardController* const wizard = controller();
   ASSERT_TRUE(wizard != NULL);
   wizard->ShowFirstScreen(WizardController::kNetworkScreenName);
@@ -149,6 +147,8 @@
   EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
   controller()->OnExit(chromeos::ScreenObserver::EULA_ACCEPTED);
+  // Let update screen smooth time process (time = 0ms).
+  ui_test_utils::RunAllPendingInMessageLoop();
 
   EXPECT_EQ(controller()->GetUpdateScreen(), controller()->current_screen());
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(0);
@@ -172,6 +172,8 @@
   EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
   controller()->OnExit(chromeos::ScreenObserver::EULA_ACCEPTED);
+  // Let update screen smooth time process (time = 0ms).
+  ui_test_utils::RunAllPendingInMessageLoop();
 
   EXPECT_EQ(controller()->GetUpdateScreen(), controller()->current_screen());
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(0);
diff --git a/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc b/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
index 2eafab4..f203df9 100644
--- a/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
+++ b/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
 
 #include "base/message_loop.h"
+#include "chrome/browser/chromeos/login/base_login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/browser_dialogs.h"
@@ -14,7 +15,8 @@
 
 WizardInProcessBrowserTest::WizardInProcessBrowserTest(const char* screen_name)
     : screen_name_(screen_name),
-      controller_(NULL) {
+      controller_(NULL),
+      host_(NULL) {
 }
 
 Browser* WizardInProcessBrowserTest::CreateBrowser(Profile* profile) {
@@ -25,12 +27,14 @@
   if (!screen_name_.empty()) {
     browser::ShowLoginWizard(screen_name_.c_str(), gfx::Size(1024, 600));
     controller_ = WizardController::default_controller();
+    host_ = BaseLoginDisplayHost::default_host();
   }
   return NULL;
 }
 
 void WizardInProcessBrowserTest::CleanUpOnMainThread() {
-  delete controller_;
+  // LoginDisplayHost owns controllers and all windows.
+  delete host_;
 
   // Observers and what not are notified after the views are deleted, which
   // happens after a delay (because they are contained in a WidgetGtk which
diff --git a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
index 488da4e1..831b39b 100644
--- a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
+++ b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
@@ -16,6 +16,8 @@
 
 namespace chromeos {
 
+class LoginDisplayHost;
+
 // Base class for test related to login wizard and its screens.
 // Instead of creating Chrome browser window it creates login wizard window
 // with specified parameters and allows to customize environment at the
@@ -41,6 +43,7 @@
  private:
   std::string screen_name_;
   WizardController* controller_;
+  LoginDisplayHost* host_;
 
   DISALLOW_COPY_AND_ASSIGN(WizardInProcessBrowserTest);
 };
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 37397d5d..730ebab 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -448,6 +448,8 @@
         'browser/chromeos/login/authenticator.h',
         'browser/chromeos/login/background_view.cc',
         'browser/chromeos/login/background_view.h',
+        'browser/chromeos/login/base_login_display_host.cc',
+        'browser/chromeos/login/base_login_display_host.h',
         'browser/chromeos/login/camera.cc',
         'browser/chromeos/login/camera.h',
         'browser/chromeos/login/captcha_view.cc',
@@ -485,6 +487,8 @@
         'browser/chromeos/login/language_switch_menu.cc',
         'browser/chromeos/login/language_switch_menu.h',
         'browser/chromeos/login/login_display.h',
+        'browser/chromeos/login/login_display.cc',
+        'browser/chromeos/login/login_display_host.h',
         'browser/chromeos/login/login_html_dialog.cc',
         'browser/chromeos/login/login_html_dialog.h',
         'browser/chromeos/login/login_performer.cc',
@@ -561,6 +565,9 @@
         'browser/chromeos/login/view_screen.h',
         'browser/chromeos/login/views_login_display.cc',
         'browser/chromeos/login/views_login_display.h',
+        'browser/chromeos/login/views_login_display_host.cc',
+        'browser/chromeos/login/views_login_display_host.h',
+        'browser/chromeos/login/base_login_display_host.h',
         'browser/chromeos/login/web_page_screen.cc',
         'browser/chromeos/login/web_page_screen.h',
         'browser/chromeos/login/web_page_view.cc',