Commit e0f71136 authored by bryeung@chromium.org's avatar bryeung@chromium.org

Delayed loading of the virtual keyboard.

Don't create the virtual keyboard until it is first shown.  This helps
prevent some start-up races.

Also clean-up some of the object ownership between KeyboardController
and KeyboardLayoutManager.  Each pointer exists in only one or the
other object now.

BUG=none

Review URL: https://codereview.chromium.org/13932030

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194580 0039d316-1c4b-4281-b951-d872f2087c98
parent a8126e8c
......@@ -512,6 +512,7 @@ void RootWindowController::InitKeyboard() {
aura::Window* keyboard_container =
keyboard_controller_->GetContainerWindow();
parent->AddChild(keyboard_container);
keyboard_container->SetBounds(parent->bounds());
}
}
......
......@@ -78,6 +78,10 @@ void TextInputTestHelper::OnTextInputTypeChanged(
MessageLoop::current()->Quit();
}
void TextInputTestHelper::OnInputMethodDestroyed(
const ui::InputMethod* input_method) {
}
void TextInputTestHelper::OnFocus() {
focus_state_ = true;
if (waiting_type_ == WAIT_ON_FOCUS)
......
......@@ -78,6 +78,8 @@ class TextInputTestHelper : public ui::MockInputMethod::Observer {
virtual void OnCaretBoundsChanged(const ui::TextInputClient* client) OVERRIDE;
virtual void OnTextInputStateChanged(
const ui::TextInputClient* client) OVERRIDE;
virtual void OnInputMethodDestroyed(
const ui::InputMethod* input_method) OVERRIDE;
// Represents waiting type of text input event.
WaitImeEventType waiting_type_;
......
......@@ -18,6 +18,9 @@ InputMethodBase::InputMethodBase()
}
InputMethodBase::~InputMethodBase() {
FOR_EACH_OBSERVER(InputMethodObserver,
observer_list_,
OnInputMethodDestroyed(this));
}
void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) {
......
......@@ -9,6 +9,7 @@
namespace ui {
class InputMethod;
class TextInputClient;
class UI_EXPORT InputMethodObserver {
......@@ -19,6 +20,9 @@ class UI_EXPORT InputMethodObserver {
// - the TextInputClient is changed (e.g. by a change of focus)
// - the TextInputType of the TextInputClient changes
virtual void OnTextInputStateChanged(const TextInputClient* client) = 0;
// Called when the observed InputMethod is being destroyed.
virtual void OnInputMethodDestroyed(const InputMethod* input_method) = 0;
};
} // namespace ui
......
......@@ -34,6 +34,7 @@ class UI_EXPORT MockInputMethod : NON_EXPORTED_BASE(public InputMethod) {
// InputMethodObserver overrides
virtual void OnTextInputStateChanged(const TextInputClient* client) = 0;
virtual void OnInputMethodDestroyed(const InputMethod* input_method) = 0;
};
explicit MockInputMethod(internal::InputMethodDelegate* delegate);
virtual ~MockInputMethod();
......
......@@ -9,7 +9,6 @@
#include "ui/aura/window_delegate.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/path.h"
......@@ -28,38 +27,6 @@ gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds) {
window_bounds.height() * kKeyboardHeightRatio);
}
// LayoutManager for the virtual keyboard container. Manages a single window
// (the virtual keyboard) and keeps it positioned at the bottom of the
// container window.
class KeyboardLayoutManager : public aura::LayoutManager {
public:
KeyboardLayoutManager(aura::Window* owner, aura::Window* keyboard)
: owner_(owner), keyboard_(keyboard) {}
// Overridden from aura::LayoutManager
virtual void OnWindowResized() OVERRIDE {
SetChildBoundsDirect(keyboard_,
KeyboardBoundsFromWindowBounds(owner_->bounds()));
}
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
CHECK(child == keyboard_);
}
virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
virtual void OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) OVERRIDE {}
virtual void SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) OVERRIDE {
// Drop these: the size should only be set in OnWindowResized.
}
private:
aura::Window* owner_;
aura::Window* keyboard_;
DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
};
// The KeyboardWindowDelegate makes sure the keyboard-window does not get focus.
// This is necessary to make sure that the synthetic key-events reach the target
// window.
......@@ -110,16 +77,57 @@ class KeyboardWindowDelegate : public aura::WindowDelegate {
namespace keyboard {
// LayoutManager for the virtual keyboard container. Manages a single window
// (the virtual keyboard) and keeps it positioned at the bottom of the
// owner window.
class KeyboardLayoutManager : public aura::LayoutManager {
public:
KeyboardLayoutManager(aura::Window* container)
: container_(container), keyboard_(NULL) {
CHECK(container_);
}
// Overridden from aura::LayoutManager
virtual void OnWindowResized() OVERRIDE {
if (!keyboard_)
return;
SetChildBoundsDirect(keyboard_,
KeyboardBoundsFromWindowBounds(container_->bounds()));
}
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
DCHECK(!keyboard_);
keyboard_ = child;
}
virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
virtual void OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) OVERRIDE {}
virtual void SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) OVERRIDE {
// Drop these: the size should only be set in OnWindowResized.
}
private:
aura::Window* container_;
aura::Window* keyboard_;
DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
};
KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
: proxy_(proxy), container_(NULL) {
: proxy_(proxy),
container_(NULL),
input_method_(NULL) {
CHECK(proxy);
proxy_->GetInputMethod()->AddObserver(this);
input_method_ = proxy_->GetInputMethod();
input_method_->AddObserver(this);
}
KeyboardController::~KeyboardController() {
if (container_)
container_->RemoveObserver(this);
proxy_->GetInputMethod()->RemoveObserver(this);
if (input_method_)
input_method_->RemoveObserver(this);
}
aura::Window* KeyboardController::GetContainerWindow() {
......@@ -128,17 +136,21 @@ aura::Window* KeyboardController::GetContainerWindow() {
container_->SetName("KeyboardContainer");
container_->Init(ui::LAYER_NOT_DRAWN);
container_->AddObserver(this);
aura::Window* keyboard = proxy_->GetKeyboardWindow();
keyboard->Show();
container_->SetLayoutManager(
new KeyboardLayoutManager(container_, keyboard));
container_->AddChild(keyboard);
container_->SetLayoutManager(new KeyboardLayoutManager(container_));
}
return container_;
}
void KeyboardController::OnWindowParentChanged(aura::Window* window,
aura::Window* parent) {
OnTextInputStateChanged(proxy_->GetInputMethod()->GetTextInputClient());
}
void KeyboardController::OnWindowDestroying(aura::Window* window) {
DCHECK_EQ(container_, window);
container_ = NULL;
}
void KeyboardController::OnTextInputStateChanged(
const ui::TextInputClient* client) {
if (!container_)
......@@ -147,23 +159,24 @@ void KeyboardController::OnTextInputStateChanged(
if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) {
container_->Hide();
} else {
if (container_->children().empty()) {
aura::Window* keyboard = proxy_->GetKeyboardWindow();
keyboard->Show();
container_->AddChild(keyboard);
container_->layout_manager()->OnWindowResized();
}
container_->parent()->StackChildAtTop(container_);
container_->Show();
}
// TODO(bryeung): whenever the TextInputClient changes we need to notify the
// keyboard (with the TextInputType) so that it can reset it's state (e.g.
// abandon compositions in progress)
}
void KeyboardController::OnWindowParentChanged(aura::Window* window,
aura::Window* parent) {
OnTextInputStateChanged(proxy_->GetInputMethod()->GetTextInputClient());
}
void KeyboardController::OnWindowDestroying(aura::Window* window) {
DCHECK_EQ(container_, window);
container_ = NULL;
void KeyboardController::OnInputMethodDestroyed(
const ui::InputMethod* input_method) {
DCHECK_EQ(input_method_, input_method);
input_method_ = NULL;
}
} // namespace keyboard
......@@ -16,15 +16,17 @@ class Window;
}
namespace ui {
class InputMethod;
class TextInputClient;
}
namespace keyboard {
class KeyboardControllerProxy;
class KeyboardLayoutManager;
// Provides control of the virtual keyboard, including providing a container,
// managing object lifetimes and controlling visibility.
// Provides control of the virtual keyboard, including providing a container
// and controlling visibility.
class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
public aura::WindowObserver {
public:
......@@ -36,18 +38,24 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// It is the responsibility of the caller to Show() the returned window.
aura::Window* GetContainerWindow();
// InputMethodObserver overrides
virtual void OnTextInputStateChanged(
const ui::TextInputClient* client) OVERRIDE;
private:
// For access to Observer methods for simulation.
friend class KeyboardControllerTest;
// aura::WindowObserver overrides
virtual void OnWindowParentChanged(aura::Window* window,
aura::Window* parent) OVERRIDE;
virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
// InputMethodObserver overrides
virtual void OnTextInputStateChanged(
const ui::TextInputClient* client) OVERRIDE;
virtual void OnInputMethodDestroyed(
const ui::InputMethod* input_method) OVERRIDE;
scoped_ptr<KeyboardControllerProxy> proxy_;
aura::Window* container_;
ui::InputMethod* input_method_;
DISALLOW_COPY_AND_ASSIGN(KeyboardController);
};
......
......@@ -49,33 +49,6 @@ class TestFocusController : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(TestFocusController);
};
class KeyboardControllerTest : public testing::Test {
public:
KeyboardControllerTest() {}
virtual ~KeyboardControllerTest() {}
virtual void SetUp() OVERRIDE {
aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
aura_test_helper_->SetUp();
ui::SetUpInputMethodFactoryForTesting();
focus_controller_.reset(new TestFocusController(root_window()));
}
virtual void TearDown() OVERRIDE {
aura_test_helper_->TearDown();
}
aura::RootWindow* root_window() { return aura_test_helper_->root_window(); }
protected:
base::MessageLoopForUI message_loop_;
scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
scoped_ptr<TestFocusController> focus_controller_;
private:
DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
};
class TestKeyboardControllerProxy : public KeyboardControllerProxy {
public:
TestKeyboardControllerProxy()
......@@ -176,6 +149,38 @@ class TestTextInputClient : public ui::TextInputClient {
} // namespace
class KeyboardControllerTest : public testing::Test {
public:
KeyboardControllerTest() {}
virtual ~KeyboardControllerTest() {}
virtual void SetUp() OVERRIDE {
aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
aura_test_helper_->SetUp();
ui::SetUpInputMethodFactoryForTesting();
focus_controller_.reset(new TestFocusController(root_window()));
}
virtual void TearDown() OVERRIDE {
aura_test_helper_->TearDown();
}
aura::RootWindow* root_window() { return aura_test_helper_->root_window(); }
void ShowKeyboard(KeyboardController* controller) {
TestTextInputClient test_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
controller->OnTextInputStateChanged(&test_text_input_client);
}
protected:
base::MessageLoopForUI message_loop_;
scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
scoped_ptr<TestFocusController> focus_controller_;
private:
DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
};
TEST_F(KeyboardControllerTest, KeyboardSize) {
KeyboardControllerProxy* proxy = new TestKeyboardControllerProxy();
KeyboardController controller(proxy);
......@@ -214,7 +219,8 @@ TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
root_window()->AddChild(keyboard_container.get());
keyboard_container->Show();
root_window()->StackChildAtTop(keyboard_container.get());
ShowKeyboard(&controller);
EXPECT_TRUE(window->IsVisible());
EXPECT_TRUE(keyboard_container->IsVisible());
EXPECT_TRUE(window->HasFocus());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment