Skip to content

Commit

Permalink
[Input View] Makes the input view window support window.resizeTo() an…
Browse files Browse the repository at this point in the history
…d w3c visibility API in its web contents.

BUG=chromium:316524
TEST=Locally verified in sandbox.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240323 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
shuchen@chromium.org committed Dec 12, 2013
1 parent 23f67ba commit 647b484
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 64 deletions.
51 changes: 13 additions & 38 deletions ash/root_window_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_event_handler.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tracker.h"
#include "ui/keyboard/keyboard_controller_proxy.h"
#include "ui/keyboard/keyboard_switches.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/widget/widget.h"
Expand Down Expand Up @@ -85,36 +87,6 @@ class DeleteOnBlurDelegate : public aura::test::TestWindowDelegate,
DISALLOW_COPY_AND_ASSIGN(DeleteOnBlurDelegate);
};

class ClickTestWindow : public views::WidgetDelegateView {
public:
ClickTestWindow() : mouse_presses_(0) {}
virtual ~ClickTestWindow() {}

// Overridden from views::WidgetDelegate:
virtual views::View* GetContentsView() OVERRIDE {
return this;
}

aura::Window* CreateTestWindowWithParent(aura::Window* parent) {
DCHECK(parent);
views::Widget* widget = Widget::CreateWindowWithParent(this, parent);
return widget->GetNativeView();
}

// Overridden from views::View:
virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
mouse_presses_++;
return false;
}

int mouse_presses() const { return mouse_presses_; }

private:
int mouse_presses_;

DISALLOW_COPY_AND_ASSIGN(ClickTestWindow);
};

} // namespace

namespace test {
Expand Down Expand Up @@ -646,24 +618,27 @@ TEST_F(VirtualKeyboardRootWindowControllerTest,
ASSERT_TRUE(keyboard_container);
keyboard_container->Show();

ClickTestWindow* main_delegate = new ClickTestWindow();
scoped_ptr<aura::Window> keyboard_window(
main_delegate->CreateTestWindowWithParent(keyboard_container));
keyboard_container->layout_manager()->OnWindowResized();
aura::Window* keyboard_window = Shell::GetInstance()->keyboard_controller()->
proxy()->GetKeyboardWindow();
keyboard_container->AddChild(keyboard_window);
keyboard_window->SetBounds(gfx::Rect());
keyboard_window->Show();
aura::test::EventGenerator event_generator(root_window,
keyboard_window.get());

aura::test::TestEventHandler* handler = new aura::test::TestEventHandler;
root_window->SetEventFilter(handler);

aura::test::EventGenerator event_generator(root_window, keyboard_window);
event_generator.ClickLeftButton();
int expected_mouse_presses = 1;
EXPECT_EQ(expected_mouse_presses, main_delegate->mouse_presses());
EXPECT_EQ(expected_mouse_presses, handler->num_mouse_events() / 2);

for (int block_reason = FIRST_BLOCK_REASON;
block_reason < NUMBER_OF_BLOCK_REASONS;
++block_reason) {
BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
event_generator.ClickLeftButton();
expected_mouse_presses++;
EXPECT_EQ(expected_mouse_presses, main_delegate->mouse_presses());
EXPECT_EQ(expected_mouse_presses, handler->num_mouse_events() / 2);
UnblockUserSession();
}
}
Expand Down
8 changes: 5 additions & 3 deletions ash/shell/keyboard_controller_proxy_stub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ KeyboardControllerProxyStub::~KeyboardControllerProxyStub() {
}

aura::Window* KeyboardControllerProxyStub::GetKeyboardWindow() {
aura::Window* window = new aura::Window(&delegate_);
window->Init(ui::LAYER_NOT_DRAWN);
return window;
if (!keyboard_) {
keyboard_.reset(new aura::Window(&delegate_));
keyboard_->Init(ui::LAYER_NOT_DRAWN);
}
return keyboard_.get();
}

BrowserContext* KeyboardControllerProxyStub::GetBrowserContext() {
Expand Down
2 changes: 2 additions & 0 deletions ash/shell/keyboard_controller_proxy_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class KeyboardControllerProxyStub : public keyboard::KeyboardControllerProxy {
const content::MediaResponseCallback& callback) OVERRIDE;

aura::test::TestWindowDelegate delegate_;
scoped_ptr<aura::Window> keyboard_;

DISALLOW_COPY_AND_ASSIGN(KeyboardControllerProxyStub);
};

Expand Down
69 changes: 47 additions & 22 deletions ui/keyboard/keyboard_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds) {
// The delegate deletes itself when the window is destroyed.
class KeyboardWindowDelegate : public aura::WindowDelegate {
public:
KeyboardWindowDelegate() {}
explicit KeyboardWindowDelegate(keyboard::KeyboardControllerProxy* proxy)
: proxy_(proxy) {}
virtual ~KeyboardWindowDelegate() {}

private:
Expand Down Expand Up @@ -73,13 +74,16 @@ class KeyboardWindowDelegate : public aura::WindowDelegate {
virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
virtual bool HasHitTestMask() const OVERRIDE { return true; }
virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {
gfx::Rect keyboard_bounds = KeyboardBoundsFromWindowBounds(bounds_);
gfx::Rect keyboard_bounds = proxy_ ? proxy_->GetKeyboardWindow()->bounds() :
KeyboardBoundsFromWindowBounds(bounds_);
mask->addRect(RectToSkRect(keyboard_bounds));
}
virtual void DidRecreateLayer(ui::Layer* old_layer,
ui::Layer* new_layer) OVERRIDE {}

gfx::Rect bounds_;
keyboard::KeyboardControllerProxy* proxy_;

DISALLOW_COPY_AND_ASSIGN(KeyboardWindowDelegate);
};

Expand All @@ -92,33 +96,44 @@ namespace keyboard {
// owner window.
class KeyboardLayoutManager : public aura::LayoutManager {
public:
KeyboardLayoutManager(aura::Window* container)
: container_(container), keyboard_(NULL) {
CHECK(container_);
explicit KeyboardLayoutManager(KeyboardController* controller)
: controller_(controller), keyboard_(NULL) {
}

// Overridden from aura::LayoutManager
virtual void OnWindowResized() OVERRIDE {
if (!keyboard_)
return;
SetChildBoundsDirect(keyboard_,
KeyboardBoundsFromWindowBounds(container_->bounds()));
if (keyboard_ && !controller_->proxy()->resizing_from_contents())
ResizeKeyboardToDefault(keyboard_);
}
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
DCHECK(!keyboard_);
keyboard_ = child;
ResizeKeyboardToDefault(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.
// SetChildBounds can be invoked by resizing from the container or by
// resizing from the contents (through window.resizeTo call in JS).
// The flag resizing_from_contents() is used to determine the keyboard is
// resizing from which.
if (controller_->proxy()->resizing_from_contents()) {
controller_->NotifyKeyboardBoundsChanging(requested_bounds);
SetChildBoundsDirect(child, requested_bounds);
}
}

private:
aura::Window* container_;
void ResizeKeyboardToDefault(aura::Window* child) {
gfx::Rect keyboard_bounds = KeyboardBoundsFromWindowBounds(
controller_->GetContainerWindow()->bounds());
SetChildBoundsDirect(child, keyboard_bounds);
}

KeyboardController* controller_;
aura::Window* keyboard_;

DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
Expand All @@ -135,24 +150,39 @@ KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
}

KeyboardController::~KeyboardController() {
if (container_.get())
if (container_) {
container_->RemoveObserver(this);
// Remove the keyboard window from the children because the keyboard window
// is owned by proxy and it should be destroyed by proxy.
if (container_->Contains(proxy_->GetKeyboardWindow()))
container_->RemoveChild(proxy_->GetKeyboardWindow());
}
if (input_method_)
input_method_->RemoveObserver(this);
}

aura::Window* KeyboardController::GetContainerWindow() {
if (!container_.get()) {
container_.reset(new aura::Window(new KeyboardWindowDelegate()));
container_.reset(new aura::Window(
new KeyboardWindowDelegate(proxy_.get())));
container_->SetName("KeyboardContainer");
container_->set_owned_by_parent(false);
container_->Init(ui::LAYER_NOT_DRAWN);
container_->AddObserver(this);
container_->SetLayoutManager(new KeyboardLayoutManager(container_.get()));
container_->SetLayoutManager(new KeyboardLayoutManager(this));
}
return container_.get();
}

void KeyboardController::NotifyKeyboardBoundsChanging(
const gfx::Rect& new_bounds) {
if (proxy_->GetKeyboardWindow()->IsVisible()) {
FOR_EACH_OBSERVER(KeyboardControllerObserver,
observer_list_,
OnKeyboardBoundsChanging(new_bounds));
}
}

void KeyboardController::HideKeyboard(HideReason reason) {
keyboard_visible_ = false;

Expand All @@ -161,9 +191,7 @@ void KeyboardController::HideKeyboard(HideReason reason) {
keyboard::KEYBOARD_CONTROL_HIDE_AUTO :
keyboard::KEYBOARD_CONTROL_HIDE_USER);

FOR_EACH_OBSERVER(KeyboardControllerObserver,
observer_list_,
OnKeyboardBoundsChanging(gfx::Rect()));
NotifyKeyboardBoundsChanging(gfx::Rect());

proxy_->HideKeyboardContainer(container_.get());
}
Expand Down Expand Up @@ -204,7 +232,6 @@ void KeyboardController::OnTextInputStateChanged(
aura::Window* keyboard = proxy_->GetKeyboardWindow();
keyboard->Show();
container_->AddChild(keyboard);
container_->layout_manager()->OnWindowResized();
}
if (type != ui::TEXT_INPUT_TYPE_NONE)
proxy_->SetUpdateInputType(type);
Expand All @@ -225,10 +252,8 @@ void KeyboardController::OnTextInputStateChanged(
if (container_->IsVisible())
return;

FOR_EACH_OBSERVER(
KeyboardControllerObserver,
observer_list_,
OnKeyboardBoundsChanging(container_->children()[0]->bounds()));
NotifyKeyboardBoundsChanging(container_->children()[0]->bounds());

proxy_->ShowKeyboardContainer(container_.get());
} else {
// Set the visibility state here so that any queries for visibility
Expand Down
5 changes: 5 additions & 0 deletions ui/keyboard/keyboard_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// call is made by the system rather than initiated by the user.
void HideKeyboard(HideReason reason);

// Notifies the keyboard observer for keyboard bounds changed.
void NotifyKeyboardBoundsChanging(const gfx::Rect& new_bounds);

// Management of the observer list.
virtual void AddObserver(KeyboardControllerObserver* observer);
virtual void RemoveObserver(KeyboardControllerObserver* observer);

KeyboardControllerProxy* proxy() { return proxy_.get(); }

private:
// For access to Observer methods for simulation.
friend class KeyboardControllerTest;
Expand Down
21 changes: 20 additions & 1 deletion ui/keyboard/keyboard_controller_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ class KeyboardContentsDelegate : public content::WebContentsDelegate,
return source;
}

virtual bool IsPopupOrPanel(
const content::WebContents* source) const OVERRIDE {
return true;
}

virtual void MoveContents(content::WebContents* source,
const gfx::Rect& pos) OVERRIDE {
aura::Window* keyboard = proxy_->GetKeyboardWindow();
gfx::Rect bounds = keyboard->bounds();
int new_height = pos.height();
bounds.set_y(bounds.y() + bounds.height() - new_height);
bounds.set_height(new_height);
proxy_->set_resizing_from_contents(true);
keyboard->SetBounds(bounds);
proxy_->set_resizing_from_contents(false);
}

// Overridden from content::WebContentsDelegate:
virtual void RequestMediaAccessPermission(content::WebContents* web_contents,
const content::MediaStreamRequest& request,
Expand All @@ -94,7 +111,7 @@ class KeyboardContentsDelegate : public content::WebContentsDelegate,
namespace keyboard {

KeyboardControllerProxy::KeyboardControllerProxy()
: default_url_(kKeyboardWebUIURL) {
: default_url_(kKeyboardWebUIURL), resizing_from_contents_(false) {
}

KeyboardControllerProxy::~KeyboardControllerProxy() {
Expand Down Expand Up @@ -139,11 +156,13 @@ aura::Window* KeyboardControllerProxy::GetKeyboardWindow() {
}

void KeyboardControllerProxy::ShowKeyboardContainer(aura::Window* container) {
GetKeyboardWindow()->Show();
container->Show();
}

void KeyboardControllerProxy::HideKeyboardContainer(aura::Window* container) {
container->Hide();
GetKeyboardWindow()->Hide();
}

void KeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) {
Expand Down
12 changes: 12 additions & 0 deletions ui/keyboard/keyboard_controller_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ class KEYBOARD_EXPORT KeyboardControllerProxy {
// Sets the override content url.
void SetOverrideContentUrl(const GURL& url);

// Whether the keyboard window is resizing from its web contents.
bool resizing_from_contents() const { return resizing_from_contents_; }

// Sets the flag of whether the keyboard window is resizing from
// its web contents.
void set_resizing_from_contents(bool resizing) {
resizing_from_contents_ = resizing;
}

// Gets the InputMethod that will provide notifications about changes in the
// text input context.
virtual ui::InputMethod* GetInputMethod() = 0;
Expand Down Expand Up @@ -88,6 +97,9 @@ class KEYBOARD_EXPORT KeyboardControllerProxy {

scoped_ptr<content::WebContents> keyboard_contents_;

// Whether the current keyboard window is resizing from its web content.
bool resizing_from_contents_;

DISALLOW_COPY_AND_ASSIGN(KeyboardControllerProxy);
};

Expand Down
29 changes: 29 additions & 0 deletions ui/keyboard/keyboard_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_helper.h"
#include "ui/aura/test/event_generator.h"
Expand Down Expand Up @@ -334,6 +335,34 @@ TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
EXPECT_TRUE(keyboard_container->IsVisible());
}

TEST_F(KeyboardControllerTest, KeyboardResizingFromContents) {
aura::Window* keyboard_container = controller()->GetContainerWindow();
aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
keyboard_container->SetBounds(gfx::Rect(800, 600));
keyboard_container->AddChild(keyboard_window);

// Default keyboard size.
EXPECT_EQ(180, keyboard_window->bounds().height());

// Resizes from contents when flag is unset.
keyboard_window->SetBounds(gfx::Rect(100, 80));
EXPECT_EQ(180, keyboard_window->bounds().height());

// Resizes from contents when flag is set.
proxy()->set_resizing_from_contents(true);
keyboard_window->SetBounds(gfx::Rect(100, 80));
EXPECT_EQ(80, keyboard_window->bounds().height());

// Resizes from container when flag is set.
keyboard_container->SetBounds(gfx::Rect(400, 300));
EXPECT_EQ(80, keyboard_window->bounds().height());

// Resizes from container when flag is unset.
proxy()->set_resizing_from_contents(false);
keyboard_container->SetBounds(gfx::Rect(800, 600));
EXPECT_EQ(180, keyboard_window->bounds().height());
}

class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
public:
KeyboardControllerUsabilityTest() {}
Expand Down

0 comments on commit 647b484

Please sign in to comment.