A keyboard widget that manages itself (the animation and all that).

At the moment, the keyboard widget manages itself pretty well. But external components can still control its visibility (and it is necessary at the moment too); the usage is simple: ShowKeyboardForWidget and Hide. The widget currently does its own animation, but eventually, perhaps the window-manager will take care of it.

BUG=None
TEST=None

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97740 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chromeos/login/touch_login_view.cc b/chrome/browser/chromeos/login/touch_login_view.cc
deleted file mode 100644
index e8572de8..0000000
--- a/chrome/browser/chromeos/login/touch_login_view.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// 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/touch_login_view.h"
-
-#include "chrome/browser/chromeos/status/status_area_view.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
-#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
-#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
-#include "chrome/browser/ui/views/dom_view.h"
-#include "chrome/common/chrome_notification_types.h"
-#include "content/browser/tab_contents/tab_contents.h"
-#include "content/common/notification_service.h"
-#include "googleurl/src/gurl.h"
-#include "ui/base/animation/slide_animation.h"
-#include "ui/gfx/transform.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/widget/widget.h"
-
-namespace {
-
-const char kViewClassName[] = "browser/chromeos/login/TouchLoginView";
-const int kDefaultKeyboardHeight = 300;
-const int kKeyboardSlideDuration = 300;  // In milliseconds
-
-PropertyAccessor<bool>* GetFocusedStateAccessor() {
-  static PropertyAccessor<bool> state;
-  return &state;
-}
-
-bool TabContentsHasFocus(const TabContents* contents) {
-  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
-  return view->Contains(view->GetFocusManager()->GetFocusedView());
-}
-
-}  // namespace
-
-namespace chromeos {
-
-// TouchLoginView public: ------------------------------------------------------
-
-TouchLoginView::TouchLoginView()
-    : WebUILoginView(),
-      keyboard_showing_(false),
-      keyboard_height_(kDefaultKeyboardHeight),
-      focus_listener_added_(false),
-      keyboard_(NULL) {
-}
-
-TouchLoginView::~TouchLoginView() {
-}
-
-void TouchLoginView::Init() {
-  WebUILoginView::Init();
-  InitStatusArea();
-  InitVirtualKeyboard();
-
-
-  Source<TabContents> tab_contents(webui_login_->tab_contents());
-  registrar_.Add(this,
-                 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                 tab_contents);
-  registrar_.Add(this,
-                 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
-                 tab_contents);
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
-                 NotificationService::AllSources());
-}
-
-std::string TouchLoginView::GetClassName() const {
-  return kViewClassName;
-}
-
-void TouchLoginView::FocusWillChange(views::View* focused_before,
-                                     views::View* focused_now) {
-  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
-  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
-  if (before != now) {
-    // TODO(varunjain): support other types of keyboard.
-    UpdateKeyboardAndLayout(now == GENERIC);
-  }
-}
-
-void TouchLoginView::OnWindowCreated() {
-}
-
-// TouchLoginView protected: ---------------------------------------------------
-
-void TouchLoginView::Layout() {
-  WebUILoginView::Layout();
-  DCHECK(status_area_);
-
-  // Layout the Status Area up in the right corner. This should always be done.
-  gfx::Size status_area_size = status_area_->GetPreferredSize();
-  status_area_->SetBounds(
-      width() - status_area_size.width() -
-          WebUILoginView::kStatusAreaCornerPadding,
-      WebUILoginView::kStatusAreaCornerPadding,
-      status_area_size.width(),
-      status_area_size.height());
-
-  if (!keyboard_)
-    return;
-
-  // We are not resizing the DOMView here, so the keyboard is going to occlude
-  // the login screen partially. It is the responsibility of the UX layer to
-  // handle this.
-
-  // Lastly layout the keyboard
-  bool display_keyboard = (keyboard_showing_ || animation_->is_animating());
-  keyboard_->SetVisible(display_keyboard);
-  gfx::Rect keyboard_bounds = bounds();
-  int keyboard_height = display_keyboard ? keyboard_height_ : 0;
-  keyboard_bounds.set_y(keyboard_bounds.height() - keyboard_height);
-  keyboard_bounds.set_height(keyboard_height);
-  keyboard_->SetBoundsRect(keyboard_bounds);
-}
-
-void TouchLoginView::InitStatusArea() {
-  if (status_area_)
-    return;
-  status_area_ = new StatusAreaView(this);
-  status_area_->Init();
-  AddChildView(status_area_);
-}
-
-// TouchLoginView private: -----------------------------------------------------
-
-void TouchLoginView::InitVirtualKeyboard() {
-  // TODO(yusukes): Support non-US virtual keyboard on the login screen.
-  keyboard_ = new KeyboardContainerView(profile_, NULL, GURL());
-
-  keyboard_->SetVisible(false);
-  AddChildView(keyboard_);
-
-  animation_.reset(new ui::SlideAnimation(this));
-  animation_->SetTweenType(ui::Tween::LINEAR);
-  animation_->SetSlideDuration(kKeyboardSlideDuration);
-}
-
-void TouchLoginView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
-  DCHECK(keyboard_);
-  if (should_show_keyboard == keyboard_showing_)
-    return;
-  keyboard_showing_ = should_show_keyboard;
-  if (keyboard_showing_) {
-    ui::Transform transform;
-    transform.SetTranslateY(-keyboard_height_);
-    keyboard_->SetTransform(transform);
-    Layout();
-    animation_->Show();
-  } else {
-    ui::Transform transform;
-    keyboard_->SetTransform(transform);
-    animation_->Hide();
-    Layout();
-  }
-}
-
-TouchLoginView::VirtualKeyboardType
-    TouchLoginView::DecideKeyboardStateForView(views::View* view) {
-  if (!view)
-    return NONE;
-
-  std::string cname = view->GetClassName();
-  if (cname == views::Textfield::kViewClassName) {
-    return GENERIC;
-  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
-    TabContents* contents = webui_login_->tab_contents();
-    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
-        contents->property_bag()) : NULL;
-    if (editable && *editable)
-      return GENERIC;
-  }
-  return NONE;
-}
-
-void TouchLoginView::Observe(int type,
-                             const NotificationSource& source,
-                             const NotificationDetails& details) {
-  if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) {
-    // Only modify the keyboard state if the currently active tab sent the
-    // notification.
-    const TabContents* current_tab = webui_login_->tab_contents();
-    TabContents* source_tab = Source<TabContents>(source).ptr();
-    const bool editable = *Details<const bool>(details).ptr();
-
-    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
-      UpdateKeyboardAndLayout(editable);
-
-    // Save the state of the focused field so that the keyboard visibility
-    // can be determined after tab switching.
-    GetFocusedStateAccessor()->SetProperty(
-        source_tab->property_bag(), editable);
-  } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) {
-    GetFocusedStateAccessor()->DeleteProperty(
-        Source<TabContents>(source).ptr()->property_bag());
-  } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) {
-    UpdateKeyboardAndLayout(false);
-  } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) {
-    // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
-    // instead of using Notification.
-    int height = *(Details<int>(details).ptr());
-    if (height != keyboard_height_) {
-      DCHECK_GE(height, 0) << "Height of the keyboard is less than 0.";
-      DCHECK_LE(height, View::height()) << "Height of the keyboard is greater "
-          "than the height of containing view.";
-      keyboard_height_ = height;
-      Layout();
-    }
-  }
-}
-
-// ui::AnimationDelegate implementation ----------------------------------------
-
-void TouchLoginView::AnimationProgressed(const ui::Animation* anim) {
-  ui::Transform transform;
-  transform.SetTranslateY(
-      ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0));
-  keyboard_->SetTransform(transform);
-}
-
-void TouchLoginView::AnimationEnded(const ui::Animation* animation) {
-  if (keyboard_showing_) {
-    Layout();
-  } else {
-    // Notify the keyboard that it is hidden now.
-    keyboard_->SetVisible(false);
-  }
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/touch_login_view.h b/chrome/browser/chromeos/login/touch_login_view.h
deleted file mode 100644
index e447f962..0000000
--- a/chrome/browser/chromeos/login/touch_login_view.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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_TOUCH_LOGIN_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_TOUCH_LOGIN_VIEW_H_
-#pragma once
-
-#include "chrome/browser/chromeos/login/webui_login_view.h"
-#include "content/common/notification_observer.h"
-#include "content/common/notification_registrar.h"
-#include "ui/base/animation/animation_delegate.h"
-#include "views/focus/focus_manager.h"
-
-class KeyboardContainerView;
-class NotificationDetails;
-class NotificationSource;
-
-namespace ui {
-class SlideAnimation;
-}
-
-namespace chromeos {
-
-// Subclass of the WebUILoginView. This view adds in support for a virtual
-// keyboard, which appears and disappears depending if text areas have
-// focus. This is only build in TOUCH_UI enabled builds.
-class TouchLoginView : public WebUILoginView,
-                       public views::FocusChangeListener,
-                       public NotificationObserver,
-                       public ui::AnimationDelegate {
- public:
-  enum VirtualKeyboardType {
-    NONE,
-    GENERIC,
-    URL,
-  };
-
-  TouchLoginView();
-  virtual ~TouchLoginView();
-
-  // Overriden from WebUILoginView:
-  virtual void Init() OVERRIDE;
-
-  // Overriden from views::Views:
-  virtual std::string GetClassName() const OVERRIDE;
-
-  // Overridden from views::FocusChangeListener:
-  virtual void FocusWillChange(views::View* focused_before,
-                               views::View* focused_now) OVERRIDE;
-
-  // Overridden from chromeos::WebUILoginView:
-  virtual void OnWindowCreated() OVERRIDE;
-
- protected:
-  // Overridden from views::View:
-  virtual void Layout() OVERRIDE;
-
-  // Overridden from chromeos::WebUILoginView:
-  virtual void InitStatusArea() OVERRIDE;
-
- private:
-  void InitVirtualKeyboard();
-  void UpdateKeyboardAndLayout(bool should_show_keyboard);
-  VirtualKeyboardType DecideKeyboardStateForView(views::View* view);
-
-  // Overridden from NotificationObserver.
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  // Overridden from ui::AnimationDelegate:
-  virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
-  virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
-
-  bool keyboard_showing_;
-  int keyboard_height_;
-  bool focus_listener_added_;
-  KeyboardContainerView* keyboard_;
-  NotificationRegistrar registrar_;
-
-  scoped_ptr<ui::SlideAnimation> animation_;
-
-  DISALLOW_COPY_AND_ASSIGN(TouchLoginView);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_TOUCH_LOGIN_VIEW_H_
diff --git a/chrome/browser/chromeos/login/webui_login_display_host.cc b/chrome/browser/chromeos/login/webui_login_display_host.cc
index ba3b1e0..1506ecc 100644
--- a/chrome/browser/chromeos/login/webui_login_display_host.cc
+++ b/chrome/browser/chromeos/login/webui_login_display_host.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/chromeos/login/oobe_display.h"
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 #include "chrome/browser/chromeos/login/webui_login_view.h"
-#include "chrome/browser/chromeos/login/touch_login_view.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "views/widget/widget.h"
@@ -119,11 +118,7 @@
 
     login_window_ = new views::Widget;
     login_window_->Init(params);
-#if defined(TOUCH_UI)
-    login_view_ = new TouchLoginView();
-#else
     login_view_ = new WebUILoginView();
-#endif
 
     login_view_->Init();
     login_window_->SetContentsView(login_view_);
diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc
index 86174ea..ada0eaea 100644
--- a/chrome/browser/chromeos/login/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/webui_login_view.cc
@@ -20,6 +20,10 @@
 #include "views/widget/native_widget_gtk.h"
 #include "views/widget/widget.h"
 
+#if defined(TOUCH_UI)
+#include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
+#endif
+
 namespace {
 
 const char kViewClassName[] = "browser/chromeos/login/WebUILoginView";
@@ -43,6 +47,10 @@
       webui_login_(NULL),
       status_window_(NULL),
       host_window_frozen_(false) {
+#if defined(TOUCH_UI)
+  // Make sure the singleton KeyboardManager object is created.
+  KeyboardManager::GetInstance();
+#endif
   accel_map_[views::Accelerator(ui::VKEY_Z, false, true, true)] =
       kAccelNameAccessibility;
   accel_map_[views::Accelerator(ui::VKEY_E, false, true, true)] =
diff --git a/chrome/browser/ui/touch/frame/keyboard_container_view.cc b/chrome/browser/ui/touch/frame/keyboard_container_view.cc
deleted file mode 100644
index 5af9ed2..0000000
--- a/chrome/browser/ui/touch/frame/keyboard_container_view.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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/ui/touch/frame/keyboard_container_view.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/views/dom_view.h"
-#include "chrome/common/url_constants.h"
-#include "content/browser/site_instance.h"
-#include "content/browser/tab_contents/tab_contents.h"
-
-namespace {
-
-// Make the provided view and all of its descendents unfocusable.
-void MakeViewHierarchyUnfocusable(views::View* view) {
-  view->set_focusable(false);
-  for (int i = 0; i < view->child_count(); ++i) {
-    MakeViewHierarchyUnfocusable(view->child_at(i));
-  }
-}
-
-}  // namepsace
-
-// static
-const char KeyboardContainerView::kViewClassName[] =
-    "browser/ui/touch/frame/KeyboardContainerView";
-
-///////////////////////////////////////////////////////////////////////////////
-// KeyboardContainerView, public:
-
-KeyboardContainerView::KeyboardContainerView(
-    Profile* profile, Browser* browser, const GURL& url)
-    : dom_view_(new DOMView),
-      ALLOW_THIS_IN_INITIALIZER_LIST(
-          extension_function_dispatcher_(profile, this)),
-      browser_(browser) {
-  const GURL keyboard_url(
-      url.is_valid() ? url : GURL(chrome::kChromeUIKeyboardURL));
-  dom_view_->Init(profile,
-      SiteInstance::CreateSiteInstanceForURL(profile, keyboard_url));
-  dom_view_->LoadURL(keyboard_url);
-
-  dom_view_->SetVisible(true);
-  AddChildView(dom_view_);
-
-  // We have Inited the dom_view. So we must have a tab contents.
-  Observe(dom_view_->tab_contents());
-}
-
-KeyboardContainerView::~KeyboardContainerView() {
-}
-
-std::string KeyboardContainerView::GetClassName() const {
-  return kViewClassName;
-}
-
-void KeyboardContainerView::Layout() {
-  // TODO(bryeung): include a border between the keyboard and the client view
-  dom_view_->SetBounds(0, 0, width(), height());
-}
-
-void KeyboardContainerView::LoadURL(const GURL& keyboard_url) {
-  dom_view_->LoadURL(keyboard_url);
-}
-
-Browser* KeyboardContainerView::GetBrowser() {
-  return browser_;
-}
-
-gfx::NativeView KeyboardContainerView::GetNativeViewOfHost() {
-  return dom_view_->native_view();
-}
-
-TabContents* KeyboardContainerView::GetAssociatedTabContents() const {
-  return dom_view_->tab_contents();
-}
-
-void KeyboardContainerView::ViewHierarchyChanged(bool is_add,
-                                                 View* parent,
-                                                 View* child) {
-  if (is_add && Contains(child))
-    MakeViewHierarchyUnfocusable(child);
-}
-
-bool KeyboardContainerView::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(KeyboardContainerView, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void KeyboardContainerView::OnRequest(
-    const ExtensionHostMsg_Request_Params& request) {
-  extension_function_dispatcher_.Dispatch(request,
-      dom_view_->tab_contents()->render_view_host());
-}
diff --git a/chrome/browser/ui/touch/frame/keyboard_container_view.h b/chrome/browser/ui/touch/frame/keyboard_container_view.h
deleted file mode 100644
index d3d0735b..0000000
--- a/chrome/browser/ui/touch/frame/keyboard_container_view.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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_UI_TOUCH_FRAME_KEYBOARD_CONTAINER_VIEW_H_
-#define CHROME_BROWSER_UI_TOUCH_FRAME_KEYBOARD_CONTAINER_VIEW_H_
-#pragma once
-
-#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/common/extensions/extension_messages.h"
-#include "content/browser/tab_contents/tab_contents_observer.h"
-#include "views/view.h"
-
-namespace IPC {
-class Message;
-}
-
-class Browser;
-class DOMView;
-class GURL;
-class Profile;
-
-// A class that contains and decorates the virtual keyboard.
-//
-// This class is also responsible for managing focus of all views related to
-// the keyboard to prevent them from interfering with the ClientView.
-class KeyboardContainerView : public views::View,
-                              public TabContentsObserver,
-                              public ExtensionFunctionDispatcher::Delegate {
- public:
-  // Internal class name.
-  static const char kViewClassName[];
-
-  KeyboardContainerView(Profile* profile, Browser* browser, const GURL& url);
-  virtual ~KeyboardContainerView();
-
-  // Overridden from views::View
-  virtual std::string GetClassName() const OVERRIDE;
-  virtual void Layout();
-
-  // ExtensionFunctionDispatcher::Delegate implementation
-  virtual Browser* GetBrowser();
-  virtual gfx::NativeView GetNativeViewOfHost();
-  virtual TabContents* GetAssociatedTabContents() const;
-
-  // Shows |keyboard_url|. The URL should look something like
-  // http://id_of_the_vk_extension/index.html#layout_name_to_show
-  void LoadURL(const GURL& keyboard_url);
-
- protected:
-  // Overridden from views::View
-  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
-
-  // Overridden from TabContentsObserver
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
-  DOMView* dom_view_;
-  ExtensionFunctionDispatcher extension_function_dispatcher_;
-  Browser* browser_;
-
-  DISALLOW_COPY_AND_ASSIGN(KeyboardContainerView);
-};
-
-#endif  // CHROME_BROWSER_UI_TOUCH_FRAME_KEYBOARD_CONTAINER_VIEW_H_
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
index 25c0713..654cadc9 100644
--- a/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
@@ -4,51 +4,14 @@
 
 #include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"
 
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
-#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
-#include "chrome/common/chrome_notification_types.h"
-#include "content/browser/renderer_host/render_view_host.h"
-#include "content/browser/tab_contents/navigation_controller.h"
-#include "content/browser/tab_contents/tab_contents.h"
-#include "content/browser/tab_contents/tab_contents_view.h"
-#include "content/common/content_notification_types.h"
-#include "content/common/notification_service.h"
-#include "content/common/view_messages.h"
-#include "ui/base/animation/slide_animation.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/transform.h"
+#include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
+#include "ui/base/ime/text_input_type.h"
 #include "views/controls/button/image_button.h"
 #include "views/controls/textfield/textfield.h"
 #include "views/focus/focus_manager.h"
+#include "views/ime/text_input_client.h"
 #include "views/window/hit_test.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h"
-#endif
-
-namespace {
-
-const int kDefaultKeyboardHeight = 300;
-const int kKeyboardSlideDuration = 300;  // In milliseconds
-
-PropertyAccessor<bool>* GetFocusedStateAccessor() {
-  static PropertyAccessor<bool> state;
-  return &state;
-}
-
-bool TabContentsHasFocus(const TabContents* contents) {
-  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
-  return view->Contains(view->GetFocusManager()->GetFocusedView());
-}
-
-}  // namespace
-
 // static
 const char TouchBrowserFrameView::kViewClassName[] =
     "browser/ui/touch/frame/TouchBrowserFrameView";
@@ -59,92 +22,37 @@
 TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
                                              BrowserView* browser_view)
     : OpaqueBrowserFrameView(frame, browser_view),
-      keyboard_showing_(false),
-      keyboard_height_(kDefaultKeyboardHeight),
-      focus_listener_added_(false),
-      keyboard_(NULL) {
-  registrar_.Add(this,
-                 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
-                 NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED,
-                 NotificationService::AllSources());
-
-  browser_view->browser()->tabstrip_model()->AddObserver(this);
-
-  animation_.reset(new ui::SlideAnimation(this));
-  animation_->SetTweenType(ui::Tween::LINEAR);
-  animation_->SetSlideDuration(kKeyboardSlideDuration);
-
-#if defined(OS_CHROMEOS)
-  chromeos::input_method::InputMethodManager* manager =
-      chromeos::input_method::InputMethodManager::GetInstance();
-  manager->AddVirtualKeyboardObserver(this);
-#endif
+      focus_listener_added_(false) {
+  // Make sure the singleton KeyboardManager object is initialized.
+  KeyboardManager::GetInstance();
 }
 
 TouchBrowserFrameView::~TouchBrowserFrameView() {
-  browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
 }
 
-int TouchBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
-  if (keyboard_ && keyboard_->GetMirroredBounds().Contains(point))
-    return HTCLIENT;
-  return OpaqueBrowserFrameView::NonClientHitTest(point);
+///////////////////////////////////////////////////////////////////////////////
+// TouchBrowserFrameView, private:
+
+void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
+                                            views::View* focused_now) {
+  views::Widget* widget = focused_now ? focused_now->GetWidget() : NULL;
+  if (!widget || !widget->IsActive())
+    return;
+
+  views::TextInputClient* input =
+      focused_now ? focused_now->GetTextInputClient() : NULL;
+  // Show the keyboard if the focused view supports text-input.
+  KeyboardManager* keyboard = KeyboardManager::GetInstance();
+  if (input && input->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
+    keyboard->ShowKeyboardForWidget(focused_now->GetWidget());
+  else
+    keyboard->Hide();
 }
 
 std::string TouchBrowserFrameView::GetClassName() const {
   return kViewClassName;
 }
 
-void TouchBrowserFrameView::Layout() {
-  OpaqueBrowserFrameView::Layout();
-
-  if (!keyboard_)
-    return;
-
-  keyboard_->SetVisible(keyboard_showing_ || animation_->is_animating());
-  gfx::Rect bounds = GetBoundsForReservedArea();
-  if (animation_->is_animating() && !keyboard_showing_) {
-    // The keyboard is in the process of hiding. So pretend it still has the
-    // same bounds as when the keyboard is visible. But
-    // |GetBoundsForReservedArea| should not take this into account so that the
-    // render view gets the entire area to relayout itself.
-    bounds.set_y(bounds.y() - keyboard_height_);
-    bounds.set_height(keyboard_height_);
-  }
-  keyboard_->SetBoundsRect(bounds);
-}
-
-void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
-                                            views::View* focused_now) {
-  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
-  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
-  if (before != now) {
-    // TODO(varunjain): support other types of keyboard.
-    UpdateKeyboardAndLayout(now == GENERIC);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TouchBrowserFrameView, protected:
-
-int TouchBrowserFrameView::GetReservedHeight() const {
-  return keyboard_showing_ ? keyboard_height_ : 0;
-}
-
 void TouchBrowserFrameView::ViewHierarchyChanged(bool is_add,
                                                  View* parent,
                                                  View* child) {
@@ -163,71 +71,6 @@
   }
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// TouchBrowserFrameView, private:
-
-void TouchBrowserFrameView::InitVirtualKeyboard() {
-  if (keyboard_)
-    return;
-
-  Profile* keyboard_profile = browser_view()->browser()->profile();
-  DCHECK(keyboard_profile) << "Profile required for virtual keyboard.";
-
-  keyboard_ = new KeyboardContainerView(keyboard_profile,
-                                        browser_view()->browser(),
-                                        url_);
-  keyboard_->SetVisible(false);
-  AddChildView(keyboard_);
-}
-
-void TouchBrowserFrameView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
-  if (should_show_keyboard)
-    InitVirtualKeyboard();
-
-  if (should_show_keyboard == keyboard_showing_)
-    return;
-
-  DCHECK(keyboard_);
-
-  keyboard_showing_ = should_show_keyboard;
-  if (keyboard_showing_) {
-    // We don't re-layout the client view until the animation ends (see
-    // AnimationEnded below) because we want the client view to occupy the
-    // entire height during the animation. It is necessary to reset the
-    // transform for the keyboard first so that the contents are sized properly
-    // when layout, and then start the animation.
-    ui::Transform reset;
-    keyboard_->SetTransform(reset);
-    Layout();
-
-    animation_->Show();
-  } else {
-    animation_->Hide();
-
-    browser_view()->set_clip_y(ui::Tween::ValueBetween(
-          animation_->GetCurrentValue(), 0, keyboard_height_));
-    parent()->Layout();
-  }
-}
-
-TouchBrowserFrameView::VirtualKeyboardType
-    TouchBrowserFrameView::DecideKeyboardStateForView(views::View* view) {
-  if (!view)
-    return NONE;
-
-  std::string cname = view->GetClassName();
-  if (cname == views::Textfield::kViewClassName) {
-    return GENERIC;
-  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
-    TabContents* contents = browser_view()->browser()->GetSelectedTabContents();
-    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
-        contents->property_bag()) : NULL;
-    if (editable && *editable)
-      return GENERIC;
-  }
-  return NONE;
-}
-
 bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const {
   if (OpaqueBrowserFrameView::HitTest(point))
     return true;
@@ -247,142 +90,3 @@
 
   return false;
 }
-
-void TouchBrowserFrameView::ActiveTabChanged(TabContentsWrapper* old_contents,
-                                             TabContentsWrapper* new_contents,
-                                             int index,
-                                             bool user_gesture) {
-  TabContents* contents = new_contents->tab_contents();
-  if (!TabContentsHasFocus(contents))
-    return;
-
-  bool* editable = GetFocusedStateAccessor()->GetProperty(
-      contents->property_bag());
-  UpdateKeyboardAndLayout(editable ? *editable : false);
-}
-
-void TouchBrowserFrameView::TabStripEmpty() {
-  if (animation_->is_animating()) {
-    // Reset the delegate so the AnimationEnded callback doesn't trigger.
-    animation_->set_delegate(NULL);
-    animation_->Stop();
-  }
-}
-
-void TouchBrowserFrameView::Observe(int type,
-                                    const NotificationSource& source,
-                                    const NotificationDetails& details) {
-  Browser* browser = browser_view()->browser();
-  if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) {
-    // Only modify the keyboard state if the currently active tab sent the
-    // notification.
-    const TabContents* current_tab = browser->GetSelectedTabContents();
-    TabContents* source_tab = Source<TabContents>(source).ptr();
-    const bool editable = *Details<const bool>(details).ptr();
-
-    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
-      UpdateKeyboardAndLayout(editable);
-
-    // Save the state of the focused field so that the keyboard visibility
-    // can be determined after tab switching.
-    GetFocusedStateAccessor()->SetProperty(
-        source_tab->property_bag(), editable);
-  } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) {
-    NavigationController* controller =
-        Source<NavigationController>(source).ptr();
-    Browser* source_browser = Browser::GetBrowserForController(
-        controller, NULL);
-
-    // If the Browser for the keyboard has navigated, re-evaluate the visibility
-    // of the keyboard.
-    TouchBrowserFrameView::VirtualKeyboardType keyboard_type = NONE;
-    views::View* view = GetFocusManager()->GetFocusedView();
-    if (view) {
-      if (view->GetClassName() == views::Textfield::kViewClassName)
-        keyboard_type = GENERIC;
-      if (view->GetClassName() == RenderWidgetHostViewViews::kViewClassName) {
-        // Reset the state of the focused field in the current tab.
-        GetFocusedStateAccessor()->SetProperty(
-            controller->tab_contents()->property_bag(), false);
-      }
-    }
-    if (source_browser == browser)
-      UpdateKeyboardAndLayout(keyboard_type == GENERIC);
-  } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) {
-    GetFocusedStateAccessor()->DeleteProperty(
-        Source<TabContents>(source).ptr()->property_bag());
-  } else if (type == chrome::NOTIFICATION_PREF_CHANGED) {
-    OpaqueBrowserFrameView::Observe(type, source, details);
-  } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) {
-    TabContents* tab_contents =
-        browser_view()->browser()->GetSelectedTabContents();
-    if (tab_contents) {
-      GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
-                                             false);
-    }
-    UpdateKeyboardAndLayout(false);
-  } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) {
-    // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
-    // instead of using Notification.
-    int height = *reinterpret_cast<int*>(details.map_key());
-    if (height != keyboard_height_) {
-      DCHECK_GE(height, 0) << "Height of the keyboard is less than 0.";
-      DCHECK_LE(height, View::height()) << "Height of the keyboard is greater "
-        "than the height of frame view.";
-      keyboard_height_ = height;
-      parent()->Layout();
-    }
-  } else if (type == chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED) {
-    UpdateKeyboardAndLayout(true);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ui::AnimationDelegate implementation
-void TouchBrowserFrameView::AnimationProgressed(const ui::Animation* anim) {
-  ui::Transform transform;
-  transform.SetTranslateY(
-      ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0));
-  keyboard_->SetTransform(transform);
-  browser_view()->set_clip_y(
-      ui::Tween::ValueBetween(anim->GetCurrentValue(), 0, keyboard_height_));
-  SchedulePaint();
-}
-
-void TouchBrowserFrameView::AnimationEnded(const ui::Animation* animation) {
-  browser_view()->set_clip_y(0);
-  if (keyboard_showing_) {
-    // Because the NonClientFrameView is a sibling of the ClientView, we rely on
-    // the parent to resize the ClientView instead of resizing it directly.
-    parent()->Layout();
-
-    // The keyboard that pops up may end up hiding the text entry. So make sure
-    // the renderer scrolls when necessary to keep the textfield visible.
-    RenderViewHost* host =
-        browser_view()->browser()->GetSelectedTabContents()->render_view_host();
-    host->Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(
-        host->routing_id()));
-  } else {
-    // Notify the keyboard that it is hidden now.
-    keyboard_->SetVisible(false);
-  }
-  SchedulePaint();
-}
-
-#if defined(OS_CHROMEOS)
-void TouchBrowserFrameView::VirtualKeyboardChanged(
-    chromeos::input_method::InputMethodManager* manager,
-    const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
-    const std::string& virtual_keyboard_layout) {
-  const GURL& new_url =
-      virtual_keyboard.GetURLForLayout(virtual_keyboard_layout);
-  if (new_url == url_)
-    return;
-
-  url_ = new_url;
-  if (keyboard_)
-    keyboard_->LoadURL(url_);
-  // |keyboard_| can be NULL here. In that case, the |url_| will be used in
-  // InitVirtualKeyboard() later.
-}
-#endif
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.h b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
index 4593d70..4ac0e02 100644
--- a/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
@@ -20,30 +20,11 @@
 
 class BrowserFrame;
 class BrowserView;
-class KeyboardContainerView;
-class NotificationDetails;
-class NotificationSource;
-
-namespace ui {
-class SlideAnimation;
-}
 
 class TouchBrowserFrameView
     : public OpaqueBrowserFrameView,
-      public views::FocusChangeListener,
-      public TabStripModelObserver,
-#if defined(OS_CHROMEOS)
-      public
-      chromeos::input_method::InputMethodManager::VirtualKeyboardObserver,
-#endif
-      public ui::AnimationDelegate {
+      public views::FocusChangeListener {
  public:
-  enum VirtualKeyboardType {
-    NONE,
-    GENERIC,
-    URL,
-  };
-
   // Internal class name.
   static const char kViewClassName[];
 
@@ -51,62 +32,17 @@
   TouchBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view);
   virtual ~TouchBrowserFrameView();
 
-  // Overriden from Views.
-  virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
-  virtual std::string GetClassName() const OVERRIDE;
-
-  // Overridden from OpaqueBrowserFrameView
-  virtual void Layout();
-
+ private:
   // views::FocusChangeListener implementation
   virtual void FocusWillChange(views::View* focused_before,
                                views::View* focused_now);
 
-#if defined(OS_CHROMEOS)
-  // input_method::InputMethodManager::VirtualKeyboardObserver implementation.
-  virtual void VirtualKeyboardChanged(
-      chromeos::input_method::InputMethodManager* manager,
-      const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
-      const std::string& virtual_keyboard_layout);
-#endif
-
- protected:
-  // Overridden from OpaqueBrowserFrameView
-  virtual int GetReservedHeight() const;
-  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
-
- private:
-  virtual void InitVirtualKeyboard();
-  virtual void UpdateKeyboardAndLayout(bool should_show_keyboard);
-  virtual VirtualKeyboardType DecideKeyboardStateForView(views::View* view);
-
   // Overridden from views::View
+  virtual std::string GetClassName() const OVERRIDE;
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
   virtual bool HitTest(const gfx::Point& point) const OVERRIDE;
 
-  // Overrridden from TabStripModelObserver.
-  virtual void ActiveTabChanged(TabContentsWrapper* old_contents,
-                                TabContentsWrapper* new_contents,
-                                int index,
-                                bool user_gesture);
-  virtual void TabStripEmpty();
-
-  // Overridden from NotificationObserver.
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details);
-
-  // Overridden from ui::AnimationDelegate:
-  virtual void AnimationProgressed(const ui::Animation* animation);
-  virtual void AnimationEnded(const ui::Animation* animation);
-
-  bool keyboard_showing_;
-  int keyboard_height_;
   bool focus_listener_added_;
-  KeyboardContainerView* keyboard_;
-  NotificationRegistrar registrar_;
-  GURL url_;
-
-  scoped_ptr<ui::SlideAnimation> animation_;
 
   DISALLOW_COPY_AND_ASSIGN(TouchBrowserFrameView);
 };
diff --git a/chrome/browser/ui/touch/keyboard/keyboard_manager.cc b/chrome/browser/ui/touch/keyboard/keyboard_manager.cc
new file mode 100644
index 0000000..974642c0
--- /dev/null
+++ b/chrome/browser/ui/touch/keyboard/keyboard_manager.cc
@@ -0,0 +1,354 @@
+// 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/ui/touch/keyboard/keyboard_manager.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/views/dom_view.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/site_instance.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/notification_service.h"
+#include "ui/base/animation/slide_animation.h"
+#include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/interpolated_transform.h"
+#include "views/ime/text_input_client.h"
+#include "views/widget/widget.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/input_method/virtual_keyboard_selector.h"
+#endif
+
+namespace {
+
+const int kDefaultKeyboardHeight = 300;
+const int kKeyboardSlideDuration = 300;  // In milliseconds
+
+PropertyAccessor<bool>* GetFocusedStateAccessor() {
+  static PropertyAccessor<bool> state;
+  return &state;
+}
+
+// Returns whether the keyboard visibility should be affected by this tab.
+bool TabContentsCanAffectKeyboard(const TabContents* tab_contents) {
+  // There may not be a browser, e.g. for the login window. But if there is
+  // a browser, then |tab_contents| should be the active tab.
+  Browser* browser = Browser::GetBrowserForController(
+      &tab_contents->controller(), NULL);
+  return browser == NULL ||
+        (browser == BrowserList::GetLastActive() &&
+         browser->GetSelectedTabContents() == tab_contents);
+}
+
+}  // namespace
+
+// TODO(sad): Is the default profile always going to be the one we want?
+
+KeyboardManager::KeyboardManager()
+    : views::Widget::Widget(),
+      dom_view_(new DOMView),
+      ALLOW_THIS_IN_INITIALIZER_LIST(
+          extension_dispatcher_(ProfileManager::GetDefaultProfile(), this)),
+      target_(NULL),
+      keyboard_height_(kDefaultKeyboardHeight) {
+
+  // Initialize the widget first.
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+  params.transparent = true;
+  Init(params);
+
+  // Setup the DOM view to host the keyboard.
+  Profile* profile = ProfileManager::GetDefaultProfile();
+  GURL keyboard_url(chrome::kChromeUIKeyboardURL);
+  dom_view_->Init(profile,
+      SiteInstance::CreateSiteInstanceForURL(profile, keyboard_url));
+  dom_view_->LoadURL(keyboard_url);
+  dom_view_->SetVisible(true);
+  SetContentsView(dom_view_);
+
+  // Setup observer so the events from the keyboard can be handled.
+  TabContentsObserver::Observe(dom_view_->tab_contents());
+
+  // Initialize the animation.
+  animation_.reset(new ui::SlideAnimation(this));
+  animation_->SetTweenType(ui::Tween::LINEAR);
+  animation_->SetSlideDuration(kKeyboardSlideDuration);
+
+  // Start listening to notifications to maintain the keyboard visibility, size
+  // etc.
+  registrar_.Add(this,
+                 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED,
+                 NotificationService::AllSources());
+  registrar_.Add(this,
+                 content::NOTIFICATION_APP_EXITING,
+                 NotificationService::AllSources());
+
+#if defined(OS_CHROMEOS)
+  chromeos::input_method::InputMethodManager* manager =
+      chromeos::input_method::InputMethodManager::GetInstance();
+  manager->AddVirtualKeyboardObserver(this);
+#endif
+}
+
+KeyboardManager::~KeyboardManager() {
+#if defined(OS_CHROMEOS)
+  chromeos::input_method::InputMethodManager* manager =
+      chromeos::input_method::InputMethodManager::GetInstance();
+  manager->RemoveVirtualKeyboardObserver(this);
+#endif
+  // TODO(sad): Do anything else?
+}
+
+void KeyboardManager::ShowKeyboardForWidget(views::Widget* widget) {
+  target_ = widget;
+  // TODO(sad): There needs to be some way to:
+  //   - reset |target_| when it is destroyed
+  //   - make |target_| the parent of this Widget
+
+  gfx::Rect rect = target_->GetWindowScreenBounds();
+  rect.set_y(rect.y() + rect.height() - keyboard_height_);
+  rect.set_height(keyboard_height_);
+  SetBounds(rect);
+
+  transform_.reset(new ui::InterpolatedTranslation(
+      gfx::Point(0, keyboard_height_), gfx::Point()));
+
+  GetRootView()->SetTransform(
+      transform_->Interpolate(animation_->GetCurrentValue()));
+  animation_->Show();
+
+  MoveToTop();
+  Show();
+}
+
+void KeyboardManager::Hide() {
+  animation_->Hide();
+}
+
+bool KeyboardManager::OnKeyEvent(const views::KeyEvent& event) {
+  return target_ ? target_->OnKeyEvent(event) : false;
+}
+
+void KeyboardManager::AnimationProgressed(const ui::Animation* animation) {
+  GetRootView()->SetTransform(
+      transform_->Interpolate(animation_->GetCurrentValue()));
+}
+
+void KeyboardManager::AnimationEnded(const ui::Animation* animation) {
+  if (animation_->GetCurrentValue() < 0.01)
+    Widget::Hide();
+}
+
+void KeyboardManager::OnBrowserAdded(const Browser* browser) {
+  browser->tabstrip_model()->AddObserver(this);
+}
+
+void KeyboardManager::OnBrowserRemoved(const Browser* browser) {
+  browser->tabstrip_model()->RemoveObserver(this);
+}
+
+bool KeyboardManager::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(KeyboardManager, message)
+    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void KeyboardManager::OnRequest(
+    const ExtensionHostMsg_Request_Params& request) {
+  extension_dispatcher_.Dispatch(request,
+      dom_view_->tab_contents()->render_view_host());
+}
+
+void KeyboardManager::ActiveTabChanged(TabContentsWrapper* old_contents,
+                                       TabContentsWrapper* new_contents,
+                                       int index,
+                                       bool user_gesture) {
+  TabContents* contents = new_contents->tab_contents();
+  if (!TabContentsCanAffectKeyboard(contents))
+    return;
+
+  // If the tab contents does not have the focus, then it should not affect the
+  // keyboard visibility.
+  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
+  views::FocusManager* fmanager = view ? view->GetFocusManager() : NULL;
+  if (!fmanager || !view->Contains(fmanager->GetFocusedView()))
+    return;
+
+  bool* editable = GetFocusedStateAccessor()->GetProperty(
+      contents->property_bag());
+  if (editable && *editable)
+    ShowKeyboardForWidget(view->GetWidget());
+  else
+    Hide();
+}
+
+Browser* KeyboardManager::GetBrowser() {
+  // TODO(sad): Find a better way. Perhaps just return NULL, and fix
+  // SendKeyboardEventInputFunction::GetTopLevelWidget to somehow interact with
+  // the WM to find the top level widget?
+  return BrowserList::GetLastActive();
+}
+
+gfx::NativeView KeyboardManager::GetNativeViewOfHost() {
+  return dom_view_->native_view();
+}
+
+TabContents* KeyboardManager::GetAssociatedTabContents() const {
+  return dom_view_->tab_contents();
+}
+
+#if defined(OS_CHROMEOS)
+void KeyboardManager::VirtualKeyboardChanged(
+    chromeos::input_method::InputMethodManager* manager,
+    const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
+    const std::string& virtual_keyboard_layout) {
+  const GURL& url = virtual_keyboard.GetURLForLayout(virtual_keyboard_layout);
+  dom_view_->LoadURL(url);
+  VLOG(1) << "VirtualKeyboardChanged: Switched to " << url.spec();
+}
+#endif
+
+void KeyboardManager::Observe(int type,
+                              const NotificationSource& source,
+                              const NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
+      // When a navigation happens, we want to hide the keyboard if the focus is
+      // in the web-page. Otherwise, the keyboard visibility should not change.
+      NavigationController* controller =
+          Source<NavigationController>(source).ptr();
+      TabContents* tab_contents = controller->tab_contents();
+      GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
+                                             false);
+      if (!TabContentsCanAffectKeyboard(tab_contents))
+        break;
+
+      TabContentsViewTouch* view =
+          static_cast<TabContentsViewTouch*>(tab_contents->view());
+      views::View* focused = view->GetFocusManager()->GetFocusedView();
+      views::TextInputClient* input =
+          focused ? focused->GetTextInputClient() : NULL;
+      // Show the keyboard if the focused view supports text-input.
+      if (input && input->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
+        ShowKeyboardForWidget(focused->GetWidget());
+      else
+        Hide();
+      break;
+    }
+
+    case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
+      // If the focus in the page moved to an editable field, then the keyboard
+      // should be visible, otherwise not.
+      TabContents* tab_contents = Source<TabContents>(source).ptr();
+      const bool editable = *Details<const bool>(details).ptr();
+      GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
+          editable);
+      if (!TabContentsCanAffectKeyboard(tab_contents))
+        break;
+
+      if (editable) {
+        TabContentsViewTouch* view =
+            static_cast<TabContentsViewTouch*>(tab_contents->view());
+        ShowKeyboardForWidget(view->GetWidget());
+      } else {
+        Hide();
+      }
+
+      break;
+    }
+
+    case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: {
+      // Tab content was destroyed. Forget everything about it.
+      GetFocusedStateAccessor()->DeleteProperty(
+          Source<TabContents>(source).ptr()->property_bag());
+      break;
+    }
+
+    case chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED: {
+      // The keyboard is hiding itself.
+      Browser* browser = BrowserList::GetLastActive();
+      if (browser) {
+        TabContents* tab_contents = browser->GetSelectedTabContents();
+        if (tab_contents) {
+          GetFocusedStateAccessor()->SetProperty(tab_contents->property_bag(),
+              false);
+        }
+      }
+
+      Hide();
+      break;
+    }
+
+    case chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED: {
+      // The keyboard is resizing itself.
+
+      // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
+      // instead of using Notification.
+      int height = *Details<int>(details).ptr();
+      if (height != keyboard_height_) {
+        DCHECK_GE(height, 0) << "Keyboard height should not be negative.";
+
+        keyboard_height_ = height;
+        gfx::Size size = GetWindowScreenBounds().size();
+        size.set_height(keyboard_height_);
+        SetSize(size);
+
+        // TODO(sad): Notify the target widget that the size has changed so it
+        // can update its display accordingly if it wanted to.
+      }
+      break;
+    }
+
+    case chrome::NOTIFICATION_EDITABLE_ELEMENT_TOUCHED: {
+      // In case the keyboard hid itself and the focus is still in an editable
+      // field, and the user touches the field, then we want to show the
+      // keyboard again.
+      views::View* src = Source<views::View>(source).ptr();
+      ShowKeyboardForWidget(src->GetWidget());
+      break;
+    }
+
+    case content::NOTIFICATION_APP_EXITING: {
+      // Ideally KeyboardManager would Close itself, but that ends up destroying
+      // the singleton object, which causes a crash when all the singleton
+      // objects are destroyed from the AtExitManager. So just destroy the
+      // RootView here.
+      DestroyRootView();
+      break;
+    }
+
+    default:
+      NOTREACHED();
+  }
+}
+
+// static
+KeyboardManager* KeyboardManager::GetInstance() {
+  return Singleton<KeyboardManager>::get();
+}
diff --git a/chrome/browser/ui/touch/keyboard/keyboard_manager.h b/chrome/browser/ui/touch/keyboard/keyboard_manager.h
new file mode 100644
index 0000000..f936787
--- /dev/null
+++ b/chrome/browser/ui/touch/keyboard/keyboard_manager.h
@@ -0,0 +1,130 @@
+// 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_UI_TOUCH_KEYBOARD_KEYBOARD_MANAGER_H_
+#define CHROME_BROWSER_UI_TOUCH_KEYBOARD_KEYBOARD_MANAGER_H_
+#pragma once
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "content/browser/tab_contents/tab_contents_observer.h"
+#include "content/common/notification_observer.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "views/widget/widget.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/input_method/input_method_manager.h"
+#endif
+
+namespace IPC {
+class Message;
+}
+
+namespace ui {
+class InterpolatedTransform;
+class SlideAnimation;
+}
+
+namespace views {
+class KeyEvent;
+}
+
+class DOMView;
+class ExtensionHostMsg_Request_Params;
+
+// A singleton object to manage the virtual keyboard.
+class KeyboardManager
+    : public views::Widget,
+      public ui::AnimationDelegate,
+      public BrowserList::Observer,
+      public TabContentsObserver,
+      public TabStripModelObserver,
+      public ExtensionFunctionDispatcher::Delegate,
+#if defined(OS_CHROMEOS)
+      public chromeos::input_method::InputMethodManager::VirtualKeyboardObserver,
+#endif
+      public NotificationObserver {
+ public:
+  // Returns the singleton object.
+  static KeyboardManager* GetInstance();
+
+  // Show the keyboard for the target widget. The events from the keyboard will
+  // be sent to |widget|.
+  // TODO(sad): Allow specifying the type of keyboard to show.
+  void ShowKeyboardForWidget(views::Widget* widget);
+
+  // Overridden from views::Widget
+  void Hide() OVERRIDE;
+
+ private:
+  // Requirement for Singleton
+  friend struct DefaultSingletonTraits<KeyboardManager>;
+
+  KeyboardManager();
+  virtual ~KeyboardManager();
+
+  // Overridden from views::Widget.
+  virtual bool OnKeyEvent(const views::KeyEvent& event) OVERRIDE;
+
+  // Overridden from ui::AnimationDelegate:
+  virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
+  virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
+
+  // Overridden from BrowserList::Observer.
+  virtual void OnBrowserAdded(const Browser* browser) OVERRIDE;
+  virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE;
+
+  // Overridden from TabContentsObserver
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  void OnRequest(const ExtensionHostMsg_Request_Params& params);
+
+  // Overridden from TabStripModelObserver.
+  virtual void ActiveTabChanged(TabContentsWrapper* old_contents,
+                                TabContentsWrapper* new_contents,
+                                int index,
+                                bool user_gesture);
+
+  // ExtensionFunctionDispatcher::Delegate implementation
+  virtual Browser* GetBrowser() OVERRIDE;
+  virtual gfx::NativeView GetNativeViewOfHost() OVERRIDE;
+  virtual TabContents* GetAssociatedTabContents() const OVERRIDE;
+
+#if defined(OS_CHROMEOS)
+  // input_method::InputMethodManager::VirtualKeyboardObserver implementation.
+  virtual void VirtualKeyboardChanged(
+      chromeos::input_method::InputMethodManager* manager,
+      const chromeos::input_method::VirtualKeyboard& virtual_keyboard,
+      const std::string& virtual_keyboard_layout);
+#endif
+
+  // NotificationObserver implementation:
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  // The animation.
+  scoped_ptr<ui::SlideAnimation> animation_;
+
+  // Interpolated transform used during animation.
+  scoped_ptr<ui::InterpolatedTransform> transform_;
+
+  // The DOM view to host the keyboard.
+  DOMView* dom_view_;
+
+  ExtensionFunctionDispatcher extension_dispatcher_;
+
+  // The widget the events from the keyboard should be directed to.
+  views::Widget* target_;
+
+  // Height of the keyboard.
+  int keyboard_height_;
+
+  NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyboardManager);
+};
+
+#endif  // CHROME_BROWSER_UI_TOUCH_KEYBOARD_KEYBOARD_MANAGER_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index f8d8eeb..f41d3bb 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -590,8 +590,6 @@
         'browser/chromeos/login/test_attempt_state.h',
         'browser/chromeos/login/textfield_with_margin.cc',
         'browser/chromeos/login/textfield_with_margin.h',
-        'browser/chromeos/login/touch_login_view.cc',
-        'browser/chromeos/login/touch_login_view.h',
         'browser/chromeos/login/tpm_password_fetcher.cc',
         'browser/chromeos/login/tpm_password_fetcher.h',
         'browser/chromeos/login/update_screen.cc',
@@ -3046,10 +3044,10 @@
         'browser/ui/toolbar/wrench_menu_model.cc',
         'browser/ui/toolbar/wrench_menu_model.h',
         'browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc',
-        'browser/ui/touch/frame/keyboard_container_view.cc',
-        'browser/ui/touch/frame/keyboard_container_view.h',
         'browser/ui/touch/frame/touch_browser_frame_view.cc',
         'browser/ui/touch/frame/touch_browser_frame_view.h',
+        'browser/ui/touch/keyboard/keyboard_manager.cc',
+        'browser/ui/touch/keyboard/keyboard_manager.h',
         'browser/ui/touch/tabs/tab_strip_factory.cc',
         'browser/ui/touch/tabs/touch_tab.cc',
         'browser/ui/touch/tabs/touch_tab.h',