Home | History | Annotate | Download | only in keyboard
      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(ui::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     aura_test_helper_->SetUp();
    202     ui::SetUpInputMethodFactoryForTesting();
    203     focus_controller_.reset(new TestFocusController(root_window()));
    204     proxy_ = new TestKeyboardControllerProxy();
    205     controller_.reset(new KeyboardController(proxy_));
    206   }
    207 
    208   virtual void TearDown() OVERRIDE {
    209     focus_controller_.reset();
    210     aura_test_helper_->TearDown();
    211   }
    212 
    213   aura::Window* root_window() { return aura_test_helper_->root_window(); }
    214   KeyboardControllerProxy* proxy() { return proxy_; }
    215   KeyboardController* controller() { return controller_.get(); }
    216 
    217   void ShowKeyboard() {
    218     TestTextInputClient test_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
    219     controller_->OnTextInputStateChanged(&test_text_input_client);
    220   }
    221 
    222  protected:
    223   bool WillHideKeyboard() {
    224     return controller_->WillHideKeyboard();
    225   }
    226 
    227   base::MessageLoopForUI message_loop_;
    228   scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
    229   scoped_ptr<TestFocusController> focus_controller_;
    230 
    231  private:
    232   KeyboardControllerProxy* proxy_;
    233   scoped_ptr<KeyboardController> controller_;
    234 
    235   DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
    236 };
    237 
    238 TEST_F(KeyboardControllerTest, KeyboardSize) {
    239   aura::Window* container(controller()->GetContainerWindow());
    240   gfx::Rect bounds(0, 0, 100, 100);
    241   container->SetBounds(bounds);
    242 
    243   const gfx::Rect& before_bounds = proxy()->GetKeyboardWindow()->bounds();
    244   gfx::Rect new_bounds(
    245       before_bounds.x(), before_bounds.y(),
    246       before_bounds.width() / 2, before_bounds.height() / 2);
    247 
    248   // The KeyboardController's LayoutManager shouldn't let this happen
    249   proxy()->GetKeyboardWindow()->SetBounds(new_bounds);
    250   ASSERT_EQ(before_bounds, proxy()->GetKeyboardWindow()->bounds());
    251 }
    252 
    253 // Tests that tapping/clicking inside the keyboard does not give it focus.
    254 TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
    255   const gfx::Rect& root_bounds = root_window()->bounds();
    256   aura::test::EventCountDelegate delegate;
    257   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
    258   window->Init(ui::LAYER_NOT_DRAWN);
    259   window->SetBounds(root_bounds);
    260   root_window()->AddChild(window.get());
    261   window->Show();
    262   window->Focus();
    263 
    264   aura::Window* keyboard_container(controller()->GetContainerWindow());
    265   keyboard_container->SetBounds(root_bounds);
    266 
    267   root_window()->AddChild(keyboard_container);
    268   keyboard_container->Show();
    269 
    270   ShowKeyboard();
    271 
    272   EXPECT_TRUE(window->IsVisible());
    273   EXPECT_TRUE(keyboard_container->IsVisible());
    274   EXPECT_TRUE(window->HasFocus());
    275   EXPECT_FALSE(keyboard_container->HasFocus());
    276 
    277   // Click on the keyboard. Make sure the keyboard receives the event, but does
    278   // not get focus.
    279   EventObserver observer;
    280   keyboard_container->AddPreTargetHandler(&observer);
    281 
    282   aura::test::EventGenerator generator(root_window());
    283   generator.MoveMouseTo(proxy()->GetKeyboardWindow()->bounds().CenterPoint());
    284   generator.ClickLeftButton();
    285   EXPECT_TRUE(window->HasFocus());
    286   EXPECT_FALSE(keyboard_container->HasFocus());
    287   EXPECT_EQ("0 0", delegate.GetMouseButtonCountsAndReset());
    288   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_PRESSED));
    289   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_RELEASED));
    290 
    291   // Click outside of the keyboard. It should reach the window behind.
    292   generator.MoveMouseTo(gfx::Point());
    293   generator.ClickLeftButton();
    294   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
    295 }
    296 
    297 TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
    298   const gfx::Rect& root_bounds = root_window()->bounds();
    299 
    300   ui::InputMethod* input_method = proxy()->GetInputMethod();
    301   TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
    302   TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
    303   TestTextInputClient input_client_2(ui::TEXT_INPUT_TYPE_TEXT);
    304   TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
    305   TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
    306   input_method->SetFocusedTextInputClient(&input_client_0);
    307 
    308   aura::Window* keyboard_container(controller()->GetContainerWindow());
    309   scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
    310       new KeyboardContainerObserver(keyboard_container));
    311   keyboard_container->SetBounds(root_bounds);
    312   root_window()->AddChild(keyboard_container);
    313 
    314   EXPECT_TRUE(keyboard_container->IsVisible());
    315 
    316   input_method->SetFocusedTextInputClient(&no_input_client_0);
    317   // Keyboard should not immediately hide itself. It is delayed to avoid layout
    318   // flicker when the focus of input field quickly change.
    319   EXPECT_TRUE(keyboard_container->IsVisible());
    320   EXPECT_TRUE(WillHideKeyboard());
    321   // Wait for hide keyboard to finish.
    322   base::MessageLoop::current()->Run();
    323   EXPECT_FALSE(keyboard_container->IsVisible());
    324 
    325   input_method->SetFocusedTextInputClient(&input_client_1);
    326   EXPECT_TRUE(keyboard_container->IsVisible());
    327 
    328   // Schedule to hide keyboard.
    329   input_method->SetFocusedTextInputClient(&no_input_client_1);
    330   EXPECT_TRUE(WillHideKeyboard());
    331   // Cancel keyboard hide.
    332   input_method->SetFocusedTextInputClient(&input_client_2);
    333 
    334   EXPECT_FALSE(WillHideKeyboard());
    335   EXPECT_TRUE(keyboard_container->IsVisible());
    336 }
    337 
    338 TEST_F(KeyboardControllerTest, AlwaysVisibleWhenLocked) {
    339   const gfx::Rect& root_bounds = root_window()->bounds();
    340 
    341   ui::InputMethod* input_method = proxy()->GetInputMethod();
    342   TestTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT);
    343   TestTextInputClient input_client_1(ui::TEXT_INPUT_TYPE_TEXT);
    344   TestTextInputClient no_input_client_0(ui::TEXT_INPUT_TYPE_NONE);
    345   TestTextInputClient no_input_client_1(ui::TEXT_INPUT_TYPE_NONE);
    346   input_method->SetFocusedTextInputClient(&input_client_0);
    347 
    348   aura::Window* keyboard_container(controller()->GetContainerWindow());
    349   scoped_ptr<KeyboardContainerObserver> keyboard_container_observer(
    350       new KeyboardContainerObserver(keyboard_container));
    351   keyboard_container->SetBounds(root_bounds);
    352   root_window()->AddChild(keyboard_container);
    353 
    354   EXPECT_TRUE(keyboard_container->IsVisible());
    355 
    356   // Lock keyboard.
    357   controller()->set_lock_keyboard(true);
    358 
    359   input_method->SetFocusedTextInputClient(&no_input_client_0);
    360   // Keyboard should not try to hide itself as it is locked.
    361   EXPECT_TRUE(keyboard_container->IsVisible());
    362   EXPECT_FALSE(WillHideKeyboard());
    363 
    364   input_method->SetFocusedTextInputClient(&input_client_1);
    365   EXPECT_TRUE(keyboard_container->IsVisible());
    366 
    367   // Unlock keyboard.
    368   controller()->set_lock_keyboard(false);
    369 
    370   // Keyboard should hide when focus on no input client.
    371   input_method->SetFocusedTextInputClient(&no_input_client_1);
    372   EXPECT_TRUE(WillHideKeyboard());
    373 
    374   // Wait for hide keyboard to finish.
    375   base::MessageLoop::current()->Run();
    376   EXPECT_FALSE(keyboard_container->IsVisible());
    377 }
    378 
    379 TEST_F(KeyboardControllerTest, KeyboardResizingFromContents) {
    380   aura::Window* keyboard_container = controller()->GetContainerWindow();
    381   aura::Window* keyboard_window = proxy()->GetKeyboardWindow();
    382   keyboard_container->SetBounds(gfx::Rect(800, 600));
    383   keyboard_container->AddChild(keyboard_window);
    384 
    385   // Default keyboard size.
    386   EXPECT_EQ(180, keyboard_window->bounds().height());
    387 
    388   // Resizes from contents when flag is unset.
    389   keyboard_window->SetBounds(gfx::Rect(100, 80));
    390   EXPECT_EQ(180, keyboard_window->bounds().height());
    391 
    392   // Resizes from contents when flag is set.
    393   proxy()->set_resizing_from_contents(true);
    394   keyboard_window->SetBounds(gfx::Rect(100, 80));
    395   EXPECT_EQ(80, keyboard_window->bounds().height());
    396 
    397   // Resizes from container when flag is set.
    398   keyboard_container->SetBounds(gfx::Rect(400, 300));
    399   EXPECT_EQ(80, keyboard_window->bounds().height());
    400 
    401   // Resizes from container when flag is unset.
    402   proxy()->set_resizing_from_contents(false);
    403   keyboard_container->SetBounds(gfx::Rect(800, 600));
    404   EXPECT_EQ(180, keyboard_window->bounds().height());
    405 }
    406 
    407 class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
    408  public:
    409   KeyboardControllerUsabilityTest() {}
    410   virtual ~KeyboardControllerUsabilityTest() {}
    411 
    412   virtual void SetUp() OVERRIDE {
    413     CommandLine::ForCurrentProcess()->AppendSwitch(
    414         switches::kKeyboardUsabilityExperiment);
    415     KeyboardControllerTest::SetUp();
    416   }
    417 
    418  private:
    419   DISALLOW_COPY_AND_ASSIGN(KeyboardControllerUsabilityTest);
    420 };
    421 
    422 TEST_F(KeyboardControllerUsabilityTest, KeyboardAlwaysVisibleInUsabilityTest) {
    423   const gfx::Rect& root_bounds = root_window()->bounds();
    424 
    425   ui::InputMethod* input_method = proxy()->GetInputMethod();
    426   TestTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
    427   TestTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
    428   input_method->SetFocusedTextInputClient(&input_client);
    429 
    430   aura::Window* keyboard_container(controller()->GetContainerWindow());
    431   keyboard_container->SetBounds(root_bounds);
    432   root_window()->AddChild(keyboard_container);
    433 
    434   EXPECT_TRUE(keyboard_container->IsVisible());
    435 
    436   input_method->SetFocusedTextInputClient(&no_input_client);
    437   // Keyboard should not hide itself after lost focus.
    438   EXPECT_TRUE(keyboard_container->IsVisible());
    439   EXPECT_FALSE(WillHideKeyboard());
    440 }
    441 
    442 }  // namespace keyboard
    443