98e08957b22d3899c2db9a47e5740b27d08da4b9
[platform/framework/web/crosswalk.git] / src / ui / keyboard / keyboard_controller_unittest.cc
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.
4
5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/aura/client/focus_client.h"
11 #include "ui/aura/layout_manager.h"
12 #include "ui/aura/root_window.h"
13 #include "ui/aura/test/aura_test_helper.h"
14 #include "ui/aura/test/event_generator.h"
15 #include "ui/aura/test/test_window_delegate.h"
16 #include "ui/aura/window.h"
17 #include "ui/base/ime/input_method.h"
18 #include "ui/base/ime/input_method_factory.h"
19 #include "ui/base/ime/text_input_client.h"
20 #include "ui/compositor/layer_type.h"
21 #include "ui/gfx/rect.h"
22 #include "ui/keyboard/keyboard_controller.h"
23 #include "ui/keyboard/keyboard_controller_proxy.h"
24 #include "ui/keyboard/keyboard_switches.h"
25
26 namespace keyboard {
27 namespace {
28
29 // An event handler that focuses a window when it is clicked/touched on. This is
30 // used to match the focus manger behaviour in ash and views.
31 class TestFocusController : public ui::EventHandler {
32  public:
33   explicit TestFocusController(aura::Window* root)
34       : root_(root) {
35     root_->AddPreTargetHandler(this);
36   }
37
38   virtual ~TestFocusController() {
39     root_->RemovePreTargetHandler(this);
40   }
41
42  private:
43   // Overridden from ui::EventHandler:
44   virtual void OnEvent(ui::Event* event) OVERRIDE {
45     aura::Window* target = static_cast<aura::Window*>(event->target());
46     if (event->type() == ui::ET_MOUSE_PRESSED ||
47         event->type() == ui::ET_TOUCH_PRESSED) {
48       aura::client::GetFocusClient(target)->FocusWindow(target);
49     }
50   }
51
52   aura::Window* root_;
53   DISALLOW_COPY_AND_ASSIGN(TestFocusController);
54 };
55
56 class TestKeyboardControllerProxy : public KeyboardControllerProxy {
57  public:
58   TestKeyboardControllerProxy()
59       : window_(new aura::Window(&delegate_)),
60         input_method_(ui::CreateInputMethod(NULL,
61                                             gfx::kNullAcceleratedWidget)) {
62     window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
63     window_->set_owned_by_parent(false);
64   }
65
66   virtual ~TestKeyboardControllerProxy() {
67     // Destroy the window before the delegate.
68     window_.reset();
69   }
70
71   // Overridden from KeyboardControllerProxy:
72   virtual aura::Window* GetKeyboardWindow() OVERRIDE { return window_.get(); }
73   virtual content::BrowserContext* GetBrowserContext() OVERRIDE { return NULL; }
74   virtual ui::InputMethod* GetInputMethod() OVERRIDE {
75     return input_method_.get();
76   }
77   virtual void RequestAudioInput(content::WebContents* web_contents,
78       const content::MediaStreamRequest& request,
79       const content::MediaResponseCallback& callback) OVERRIDE { return; }
80
81  private:
82   scoped_ptr<aura::Window> window_;
83   aura::test::TestWindowDelegate delegate_;
84   scoped_ptr<ui::InputMethod> input_method_;
85
86   DISALLOW_COPY_AND_ASSIGN(TestKeyboardControllerProxy);
87 };
88
89 // Keeps a count of all the events a window receives.
90 class EventObserver : public ui::EventHandler {
91  public:
92   EventObserver() {}
93   virtual ~EventObserver() {}
94
95   int GetEventCount(ui::EventType type) {
96     return event_counts_[type];
97   }
98
99  private:
100   // Overridden from ui::EventHandler:
101   virtual void OnEvent(ui::Event* event) OVERRIDE {
102     ui::EventHandler::OnEvent(event);
103     event_counts_[event->type()]++;
104   }
105
106   std::map<ui::EventType, int> event_counts_;
107   DISALLOW_COPY_AND_ASSIGN(EventObserver);
108 };
109
110 class TestTextInputClient : public ui::TextInputClient {
111  public:
112   explicit TestTextInputClient(ui::TextInputType type)
113       : type_(type) {}
114   virtual ~TestTextInputClient() {}
115
116  private:
117   // Overridden from ui::TextInputClient:
118   virtual void SetCompositionText(
119       const ui::CompositionText& composition) OVERRIDE {}
120   virtual void ConfirmCompositionText() OVERRIDE {}
121   virtual void ClearCompositionText() OVERRIDE {}
122   virtual void InsertText(const base::string16& text) OVERRIDE {}
123   virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {}
124   virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
125     return static_cast<gfx::NativeWindow>(NULL);
126   }
127   virtual ui::TextInputType GetTextInputType() const OVERRIDE {
128     return type_;
129   }
130   virtual ui::TextInputMode GetTextInputMode() const OVERRIDE {
131     return ui::TEXT_INPUT_MODE_DEFAULT;
132   }
133   virtual bool CanComposeInline() const OVERRIDE { return false; }
134   virtual gfx::Rect GetCaretBounds() const OVERRIDE { return gfx::Rect(); }
135
136   virtual bool GetCompositionCharacterBounds(
137       uint32 index,
138       gfx::Rect* rect) const OVERRIDE {
139     return false;
140   }
141   virtual bool HasCompositionText() const OVERRIDE { return false; }
142   virtual bool GetTextRange(gfx::Range* range) const OVERRIDE { return false; }
143   virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE {
144     return false;
145   }
146   virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE {
147     return false;
148   }
149   virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE {
150     return false;
151   }
152   virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; }
153   virtual bool GetTextFromRange(const gfx::Range& range,
154                                 base::string16* text) const OVERRIDE {
155     return false;
156   }
157   virtual void OnInputMethodChanged() OVERRIDE {}
158   virtual bool ChangeTextDirectionAndLayoutAlignment(
159       base::i18n::TextDirection direction) OVERRIDE { return false; }
160   virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE {}
161   virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {}
162   virtual void OnCandidateWindowShown() OVERRIDE {}
163   virtual void OnCandidateWindowUpdated() OVERRIDE {}
164   virtual void OnCandidateWindowHidden() OVERRIDE {}
165
166   ui::TextInputType type_;
167
168   DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
169 };
170
171 class KeyboardContainerObserver : public aura::WindowObserver {
172  public:
173   explicit KeyboardContainerObserver(aura::Window* window) : window_(window) {
174     window_->AddObserver(this);
175   }
176   virtual ~KeyboardContainerObserver() {
177     window_->RemoveObserver(this);
178   }
179
180  private:
181   virtual void OnWindowVisibilityChanged(aura::Window* window,
182                                          bool visible) OVERRIDE {
183     if (!visible)
184       base::MessageLoop::current()->Quit();
185   }
186
187   aura::Window* window_;
188
189   DISALLOW_COPY_AND_ASSIGN(KeyboardContainerObserver);
190 };
191
192 }  // namespace
193
194 class KeyboardControllerTest : public testing::Test {
195  public:
196   KeyboardControllerTest() {}
197   virtual ~KeyboardControllerTest() {}
198
199   virtual void SetUp() OVERRIDE {
200     aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
201     bool allow_test_contexts = true;
202     aura_test_helper_->SetUp(allow_test_contexts);
203     ui::SetUpInputMethodFactoryForTesting();
204     focus_controller_.reset(new TestFocusController(root_window()));
205     proxy_ = new TestKeyboardControllerProxy();
206     controller_.reset(new KeyboardController(proxy_));
207   }
208
209   virtual void TearDown() OVERRIDE {
210     controller_.reset();
211     focus_controller_.reset();
212     aura_test_helper_->TearDown();
213   }
214
215   aura::Window* root_window() { return aura_test_helper_->root_window(); }
216   KeyboardControllerProxy* proxy() { return proxy_; }
217   KeyboardController* controller() { return controller_.get(); }
218
219   void ShowKeyboard() {
220     TestTextInputClient test_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
221     SetFocus(&test_text_input_client);
222   }
223
224  protected:
225   void SetFocus(ui::TextInputClient* client) {
226     ui::InputMethod* input_method = proxy()->GetInputMethod();
227     input_method->SetFocusedTextInputClient(client);
228     if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
229       input_method->ShowImeIfNeeded();
230   }
231
232   bool WillHideKeyboard() {
233     return controller_->WillHideKeyboard();
234   }
235
236   base::MessageLoopForUI message_loop_;
237   scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
238   scoped_ptr<TestFocusController> focus_controller_;
239
240  private:
241   KeyboardControllerProxy* proxy_;
242   scoped_ptr<KeyboardController> controller_;
243
244   DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
245 };
246
247 TEST_F(KeyboardControllerTest, KeyboardSize) {
248   aura::Window* container(controller()->GetContainerWindow());
249   gfx::Rect bounds(0, 0, 100, 100);
250   container->SetBounds(bounds);
251
252   const gfx::Rect& before_bounds = proxy()->GetKeyboardWindow()->bounds();
253   gfx::Rect new_bounds(
254       before_bounds.x(), before_bounds.y(),
255       before_bounds.width() / 2, before_bounds.height() / 2);
256
257   // The KeyboardController's LayoutManager shouldn't let this happen
258   proxy()->GetKeyboardWindow()->SetBounds(new_bounds);
259   ASSERT_EQ(before_bounds, proxy()->GetKeyboardWindow()->bounds());
260 }
261
262 // Tests that tapping/clicking inside the keyboard does not give it focus.
263 TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
264   const gfx::Rect& root_bounds = root_window()->bounds();
265   aura::test::EventCountDelegate delegate;
266   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
267   window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
268   window->SetBounds(root_bounds);
269   root_window()->AddChild(window.get());
270   window->Show();
271   window->Focus();
272
273   aura::Window* keyboard_container(controller()->GetContainerWindow());
274   keyboard_container->SetBounds(root_bounds);
275
276   root_window()->AddChild(keyboard_container);
277   keyboard_container->Show();
278
279   ShowKeyboard();
280
281   EXPECT_TRUE(window->IsVisible());
282   EXPECT_TRUE(keyboard_container->IsVisible());
283   EXPECT_TRUE(window->HasFocus());
284   EXPECT_FALSE(keyboard_container->HasFocus());
285
286   // Click on the keyboard. Make sure the keyboard receives the event, but does
287   // not get focus.
288   EventObserver observer;
289   keyboard_container->AddPreTargetHandler(&observer);
290
291   aura::test::EventGenerator generator(root_window());
292   generator.MoveMouseTo(proxy()->GetKeyboardWindow()->bounds().CenterPoint());
293   generator.ClickLeftButton();
294   EXPECT_TRUE(window->HasFocus());
295   EXPECT_FALSE(keyboard_container->HasFocus());
296   EXPECT_EQ("0 0", delegate.GetMouseButtonCountsAndReset());
297   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_PRESSED));
298   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_RELEASED));
299
300   // Click outside of the keyboard. It should reach the window behind.
301   generator.MoveMouseTo(gfx::Point());
302   generator.ClickLeftButton();
303   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
304   keyboard_container->RemovePreTargetHandler(&observer);
305 }
306
307 TEST_F(KeyboardControllerTest, EventHitTestingInContainer) {
308   const gfx::Rect& root_bounds = root_window()->bounds();
309   aura::test::EventCountDelegate delegate;
310   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
311   window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
312   window->SetBounds(root_bounds);
313   root_window()->AddChild(window.get());
314   window->Show();
315   window->Focus();
316
317   aura::Window* keyboard_container(controller()->GetContainerWindow());
318   keyboard_container->SetBounds(root_bounds);
319
320   root_window()->AddChild(keyboard_container);
321   keyboard_container->Show();
322
323   ShowKeyboard();
324
325   EXPECT_TRUE(window->IsVisible());
326   EXPECT_TRUE(keyboard_container->IsVisible());
327   EXPECT_TRUE(window->HasFocus());
328   EXPECT_FALSE(keyboard_container->HasFocus());
329
330   // Make sure hit testing works correctly while the keyboard is visible.
331   aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
332   ui::EventTarget* root = root_window();
333   ui::EventTargeter* targeter = root->GetEventTargeter();
334   gfx::Point location = keyboard_window->bounds().CenterPoint();
335   ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, location, location, ui::EF_NONE,
336                         ui::EF_NONE);
337   EXPECT_EQ(keyboard_window, targeter->FindTargetForEvent(root, &mouse1));
338
339
340   location.set_y(keyboard_window->bounds().y() - 5);
341   ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, location, location, ui::EF_NONE,
342                         ui::EF_NONE);
343   EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse2));
344 }
345
346 TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
347   const gfx::Rect& root_bounds = root_window()->bounds();
348
349   TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
350   TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
351   TestTextInputClient input_client_2(ui::TEXT_INPUT_TYPE_TEXT);
352   TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
353   TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
354
355   aura::Window* keyboard_container(controller()->GetContainerWindow());
356   scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
357       new KeyboardContainerObserver(keyboard_container));
358   keyboard_container->SetBounds(root_bounds);
359   root_window()->AddChild(keyboard_container);
360
361   SetFocus(&input_client_0);
362
363   EXPECT_TRUE(keyboard_container->IsVisible());
364
365   SetFocus(&no_input_client_0);
366   // Keyboard should not immediately hide itself. It is delayed to avoid layout
367   // flicker when the focus of input field quickly change.
368   EXPECT_TRUE(keyboard_container->IsVisible());
369   EXPECT_TRUE(WillHideKeyboard());
370   // Wait for hide keyboard to finish.
371   base::MessageLoop::current()->Run();
372   EXPECT_FALSE(keyboard_container->IsVisible());
373
374   SetFocus(&input_client_1);
375   EXPECT_TRUE(keyboard_container->IsVisible());
376
377   // Schedule to hide keyboard.
378   SetFocus(&no_input_client_1);
379   EXPECT_TRUE(WillHideKeyboard());
380   // Cancel keyboard hide.
381   SetFocus(&input_client_2);
382
383   EXPECT_FALSE(WillHideKeyboard());
384   EXPECT_TRUE(keyboard_container->IsVisible());
385 }
386
387 TEST_F(KeyboardControllerTest, AlwaysVisibleWhenLocked) {
388   const gfx::Rect& root_bounds = root_window()->bounds();
389
390   TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
391   TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
392   TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
393   TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
394
395   aura::Window* keyboard_container(controller()->GetContainerWindow());
396   scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
397       new KeyboardContainerObserver(keyboard_container));
398   keyboard_container->SetBounds(root_bounds);
399   root_window()->AddChild(keyboard_container);
400
401   SetFocus(&input_client_0);
402
403   EXPECT_TRUE(keyboard_container->IsVisible());
404
405   // Lock keyboard.
406   controller()->set_lock_keyboard(true);
407
408   SetFocus(&no_input_client_0);
409   // Keyboard should not try to hide itself as it is locked.
410   EXPECT_TRUE(keyboard_container->IsVisible());
411   EXPECT_FALSE(WillHideKeyboard());
412
413   SetFocus(&input_client_1);
414   EXPECT_TRUE(keyboard_container->IsVisible());
415
416   // Unlock keyboard.
417   controller()->set_lock_keyboard(false);
418
419   // Keyboard should hide when focus on no input client.
420   SetFocus(&no_input_client_1);
421   EXPECT_TRUE(WillHideKeyboard());
422
423   // Wait for hide keyboard to finish.
424   base::MessageLoop::current()->Run();
425   EXPECT_FALSE(keyboard_container->IsVisible());
426 }
427
428 TEST_F(KeyboardControllerTest, KeyboardResizingFromContents) {
429   aura::Window* keyboard_container = controller()->GetContainerWindow();
430   aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
431   keyboard_container->SetBounds(gfx::Rect(800, 600));
432   keyboard_container->AddChild(keyboard_window);
433
434   // Default keyboard size.
435   EXPECT_EQ(180, keyboard_window->bounds().height());
436
437   // Resizes from contents when flag is unset.
438   keyboard_window->SetBounds(gfx::Rect(100, 80));
439   EXPECT_EQ(180, keyboard_window->bounds().height());
440
441   // Resizes from contents when flag is set.
442   proxy()->set_resizing_from_contents(true);
443   keyboard_window->SetBounds(gfx::Rect(100, 80));
444   EXPECT_EQ(80, keyboard_window->bounds().height());
445
446   // Resizes from container when flag is set.
447   keyboard_container->SetBounds(gfx::Rect(400, 300));
448   EXPECT_EQ(80, keyboard_window->bounds().height());
449
450   // Resizes from container when flag is unset.
451   proxy()->set_resizing_from_contents(false);
452   keyboard_container->SetBounds(gfx::Rect(800, 600));
453   EXPECT_EQ(180, keyboard_window->bounds().height());
454 }
455
456 class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
457  public:
458   KeyboardControllerUsabilityTest() {}
459   virtual ~KeyboardControllerUsabilityTest() {}
460
461   virtual void SetUp() OVERRIDE {
462     CommandLine::ForCurrentProcess()->AppendSwitch(
463         switches::kKeyboardUsabilityExperiment);
464     KeyboardControllerTest::SetUp();
465   }
466
467  private:
468   DISALLOW_COPY_AND_ASSIGN(KeyboardControllerUsabilityTest);
469 };
470
471 TEST_F(KeyboardControllerUsabilityTest, KeyboardAlwaysVisibleInUsabilityTest) {
472   const gfx::Rect& root_bounds = root_window()->bounds();
473
474   TestTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
475   TestTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
476
477   aura::Window* keyboard_container(controller()->GetContainerWindow());
478   keyboard_container->SetBounds(root_bounds);
479   root_window()->AddChild(keyboard_container);
480
481   SetFocus(&input_client);
482   EXPECT_TRUE(keyboard_container->IsVisible());
483
484   SetFocus(&no_input_client);
485   // Keyboard should not hide itself after lost focus.
486   EXPECT_TRUE(keyboard_container->IsVisible());
487   EXPECT_FALSE(WillHideKeyboard());
488 }
489
490 }  // namespace keyboard