1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/scoped_ptr.h"
6 #include "base/message_loop.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/aura/client/focus_client.h"
9 #include "ui/aura/root_window.h"
10 #include "ui/aura/test/aura_test_helper.h"
11 #include "ui/aura/test/event_generator.h"
12 #include "ui/aura/test/test_window_delegate.h"
13 #include "ui/aura/window.h"
14 #include "ui/base/ime/input_method.h"
15 #include "ui/base/ime/input_method_factory.h"
16 #include "ui/base/ime/text_input_client.h"
17 #include "ui/compositor/layer_type.h"
18 #include "ui/gfx/rect.h"
19 #include "ui/keyboard/keyboard_controller.h"
20 #include "ui/keyboard/keyboard_controller_proxy.h"
25 // An event handler that focuses a window when it is clicked/touched on. This is
26 // used to match the focus manger behaviour in ash and views.
27 class TestFocusController
: public ui::EventHandler
{
29 explicit TestFocusController(aura::RootWindow
* root
)
31 root_
->AddPreTargetHandler(this);
34 virtual ~TestFocusController() {
35 root_
->RemovePreTargetHandler(this);
39 // Overridden from ui::EventHandler:
40 virtual void OnEvent(ui::Event
* event
) OVERRIDE
{
41 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
42 if (event
->type() == ui::ET_MOUSE_PRESSED
||
43 event
->type() == ui::ET_TOUCH_PRESSED
) {
44 aura::client::GetFocusClient(target
)->FocusWindow(target
);
49 DISALLOW_COPY_AND_ASSIGN(TestFocusController
);
52 class KeyboardControllerTest
: public testing::Test
{
54 KeyboardControllerTest() {}
55 virtual ~KeyboardControllerTest() {}
57 virtual void SetUp() OVERRIDE
{
58 aura_test_helper_
.reset(new aura::test::AuraTestHelper(&message_loop_
));
59 aura_test_helper_
->SetUp();
60 ui::SetUpInputMethodFactoryForTesting();
61 focus_controller_
.reset(new TestFocusController(root_window()));
64 virtual void TearDown() OVERRIDE
{
65 aura_test_helper_
->TearDown();
68 aura::RootWindow
* root_window() { return aura_test_helper_
->root_window(); }
71 base::MessageLoopForUI message_loop_
;
72 scoped_ptr
<aura::test::AuraTestHelper
> aura_test_helper_
;
73 scoped_ptr
<TestFocusController
> focus_controller_
;
76 DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest
);
79 class TestKeyboardControllerProxy
: public KeyboardControllerProxy
{
81 TestKeyboardControllerProxy()
82 : window_(new aura::Window(&delegate_
)),
83 input_method_(ui::CreateInputMethod(NULL
,
84 gfx::kNullAcceleratedWidget
)) {
85 window_
->Init(ui::LAYER_NOT_DRAWN
);
86 window_
->set_owned_by_parent(false);
89 virtual ~TestKeyboardControllerProxy() {
90 // Destroy the window before the delegate.
94 // Overridden from KeyboardControllerProxy:
95 virtual aura::Window
* GetKeyboardWindow() OVERRIDE
{ return window_
.get(); }
96 virtual ui::InputMethod
* GetInputMethod() OVERRIDE
{
97 return input_method_
.get();
101 scoped_ptr
<aura::Window
> window_
;
102 aura::test::TestWindowDelegate delegate_
;
103 scoped_ptr
<ui::InputMethod
> input_method_
;
105 DISALLOW_COPY_AND_ASSIGN(TestKeyboardControllerProxy
);
108 // Keeps a count of all the events a window receives.
109 class EventObserver
: public ui::EventHandler
{
112 virtual ~EventObserver() {}
114 int GetEventCount(ui::EventType type
) {
115 return event_counts_
[type
];
119 // Overridden from ui::EventHandler:
120 virtual void OnEvent(ui::Event
* event
) OVERRIDE
{
121 ui::EventHandler::OnEvent(event
);
122 event_counts_
[event
->type()]++;
125 std::map
<ui::EventType
, int> event_counts_
;
126 DISALLOW_COPY_AND_ASSIGN(EventObserver
);
129 class TestTextInputClient
: public ui::TextInputClient
{
131 explicit TestTextInputClient(ui::TextInputType type
)
133 virtual ~TestTextInputClient() {}
136 // Overridden from ui::TextInputClient:
137 virtual void SetCompositionText(
138 const ui::CompositionText
& composition
) OVERRIDE
{}
139 virtual void ConfirmCompositionText() OVERRIDE
{}
140 virtual void ClearCompositionText() OVERRIDE
{}
141 virtual void InsertText(const string16
& text
) OVERRIDE
{}
142 virtual void InsertChar(char16 ch
, int flags
) OVERRIDE
{}
143 virtual ui::TextInputType
GetTextInputType() const OVERRIDE
{
146 virtual bool CanComposeInline() const OVERRIDE
{ return false; }
147 virtual gfx::Rect
GetCaretBounds() OVERRIDE
{ return gfx::Rect(); }
149 virtual bool GetCompositionCharacterBounds(uint32 index
,
150 gfx::Rect
* rect
) OVERRIDE
{
153 virtual bool HasCompositionText() OVERRIDE
{ return false; }
154 virtual bool GetTextRange(ui::Range
* range
) OVERRIDE
{ return false; }
155 virtual bool GetCompositionTextRange(ui::Range
* range
) OVERRIDE
{
158 virtual bool GetSelectionRange(ui::Range
* range
) OVERRIDE
{ return false; }
159 virtual bool SetSelectionRange(const ui::Range
& range
) OVERRIDE
{
162 virtual bool DeleteRange(const ui::Range
& range
) OVERRIDE
{ return false; }
163 virtual bool GetTextFromRange(const ui::Range
& range
,
164 string16
* text
) OVERRIDE
{
167 virtual void OnInputMethodChanged() OVERRIDE
{}
168 virtual bool ChangeTextDirectionAndLayoutAlignment(
169 base::i18n::TextDirection direction
) OVERRIDE
{ return false; }
170 virtual void ExtendSelectionAndDelete(size_t before
, size_t after
) OVERRIDE
{}
172 ui::TextInputType type_
;
174 DISALLOW_COPY_AND_ASSIGN(TestTextInputClient
);
179 TEST_F(KeyboardControllerTest
, KeyboardSize
) {
180 KeyboardControllerProxy
* proxy
= new TestKeyboardControllerProxy();
181 KeyboardController
controller(proxy
);
183 scoped_ptr
<aura::Window
> container(controller
.GetContainerWindow());
184 gfx::Rect
bounds(0, 0, 100, 100);
185 container
->SetBounds(bounds
);
187 const gfx::Rect
& before_bounds
= proxy
->GetKeyboardWindow()->bounds();
188 gfx::Rect
new_bounds(
189 before_bounds
.x(), before_bounds
.y(),
190 before_bounds
.width() / 2, before_bounds
.height() / 2);
192 // The KeyboardController's LayoutManager shouldn't let this happen
193 proxy
->GetKeyboardWindow()->SetBounds(new_bounds
);
194 ASSERT_EQ(before_bounds
, proxy
->GetKeyboardWindow()->bounds());
197 // Tests that tapping/clicking inside the keyboard does not give it focus.
198 TEST_F(KeyboardControllerTest
, ClickDoesNotFocusKeyboard
) {
199 const gfx::Rect
& root_bounds
= root_window()->bounds();
200 aura::test::EventCountDelegate delegate
;
201 scoped_ptr
<aura::Window
> window(new aura::Window(&delegate
));
202 window
->Init(ui::LAYER_NOT_DRAWN
);
203 window
->SetBounds(root_bounds
);
204 root_window()->AddChild(window
.get());
208 KeyboardControllerProxy
* proxy
= new TestKeyboardControllerProxy();
209 KeyboardController
controller(proxy
);
211 scoped_ptr
<aura::Window
> keyboard_container(controller
.GetContainerWindow());
212 keyboard_container
->SetBounds(root_bounds
);
214 root_window()->AddChild(keyboard_container
.get());
215 keyboard_container
->Show();
217 root_window()->StackChildAtTop(keyboard_container
.get());
218 EXPECT_TRUE(window
->IsVisible());
219 EXPECT_TRUE(keyboard_container
->IsVisible());
220 EXPECT_TRUE(window
->HasFocus());
221 EXPECT_FALSE(keyboard_container
->HasFocus());
223 // Click on the keyboard. Make sure the keyboard receives the event, but does
225 EventObserver observer
;
226 keyboard_container
->AddPreTargetHandler(&observer
);
228 aura::test::EventGenerator
generator(root_window());
229 generator
.MoveMouseTo(proxy
->GetKeyboardWindow()->bounds().CenterPoint());
230 generator
.ClickLeftButton();
231 EXPECT_TRUE(window
->HasFocus());
232 EXPECT_FALSE(keyboard_container
->HasFocus());
233 EXPECT_EQ("0 0", delegate
.GetMouseButtonCountsAndReset());
234 EXPECT_EQ(1, observer
.GetEventCount(ui::ET_MOUSE_PRESSED
));
235 EXPECT_EQ(1, observer
.GetEventCount(ui::ET_MOUSE_RELEASED
));
237 // Click outside of the keyboard. It should reach the window behind.
238 generator
.MoveMouseTo(gfx::Point());
239 generator
.ClickLeftButton();
240 EXPECT_EQ("1 1", delegate
.GetMouseButtonCountsAndReset());
243 TEST_F(KeyboardControllerTest
, VisibilityChangeWithTextInputTypeChange
) {
244 const gfx::Rect
& root_bounds
= root_window()->bounds();
245 aura::test::EventCountDelegate delegate
;
246 scoped_ptr
<aura::Window
> window(new aura::Window(&delegate
));
247 window
->Init(ui::LAYER_NOT_DRAWN
);
248 window
->SetBounds(root_bounds
);
249 root_window()->AddChild(window
.get());
253 KeyboardControllerProxy
* proxy
= new TestKeyboardControllerProxy();
254 ui::InputMethod
* input_method
= proxy
->GetInputMethod();
255 TestTextInputClient
input_client(ui::TEXT_INPUT_TYPE_TEXT
);
256 TestTextInputClient
no_input_client(ui::TEXT_INPUT_TYPE_NONE
);
257 input_method
->SetFocusedTextInputClient(&input_client
);
259 KeyboardController
controller(proxy
);
261 scoped_ptr
<aura::Window
> keyboard_container(controller
.GetContainerWindow());
262 keyboard_container
->SetBounds(root_bounds
);
263 root_window()->AddChild(keyboard_container
.get());
265 EXPECT_TRUE(keyboard_container
->IsVisible());
267 input_method
->SetFocusedTextInputClient(&no_input_client
);
268 EXPECT_FALSE(keyboard_container
->IsVisible());
270 input_method
->SetFocusedTextInputClient(&input_client
);
271 EXPECT_TRUE(keyboard_container
->IsVisible());
274 } // namespace keyboard