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/memory/scoped_ptr.h"
      6 #include "base/message_loop/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"
     21 
     22 namespace keyboard {
     23 namespace {
     24 
     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 {
     28  public:
     29   explicit TestFocusController(aura::RootWindow* root)
     30       : root_(root) {
     31     root_->AddPreTargetHandler(this);
     32   }
     33 
     34   virtual ~TestFocusController() {
     35     root_->RemovePreTargetHandler(this);
     36   }
     37 
     38  private:
     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);
     45     }
     46   }
     47 
     48   aura::Window* root_;
     49   DISALLOW_COPY_AND_ASSIGN(TestFocusController);
     50 };
     51 
     52 class TestKeyboardControllerProxy : public KeyboardControllerProxy {
     53  public:
     54   TestKeyboardControllerProxy()
     55       : window_(new aura::Window(&delegate_)),
     56         input_method_(ui::CreateInputMethod(NULL,
     57                                             gfx::kNullAcceleratedWidget)) {
     58     window_->Init(ui::LAYER_NOT_DRAWN);
     59     window_->set_owned_by_parent(false);
     60   }
     61 
     62   virtual ~TestKeyboardControllerProxy() {
     63     // Destroy the window before the delegate.
     64     window_.reset();
     65   }
     66 
     67   // Overridden from KeyboardControllerProxy:
     68   virtual aura::Window* GetKeyboardWindow() OVERRIDE { return window_.get(); }
     69   virtual content::BrowserContext* GetBrowserContext() OVERRIDE { return NULL; }
     70   virtual ui::InputMethod* GetInputMethod() OVERRIDE {
     71     return input_method_.get();
     72   }
     73   virtual void RequestAudioInput(content::WebContents* web_contents,
     74       const content::MediaStreamRequest& request,
     75       const content::MediaResponseCallback& callback) OVERRIDE { return; }
     76 
     77  private:
     78   scoped_ptr<aura::Window> window_;
     79   aura::test::TestWindowDelegate delegate_;
     80   scoped_ptr<ui::InputMethod> input_method_;
     81 
     82   DISALLOW_COPY_AND_ASSIGN(TestKeyboardControllerProxy);
     83 };
     84 
     85 // Keeps a count of all the events a window receives.
     86 class EventObserver : public ui::EventHandler {
     87  public:
     88   EventObserver() {}
     89   virtual ~EventObserver() {}
     90 
     91   int GetEventCount(ui::EventType type) {
     92     return event_counts_[type];
     93   }
     94 
     95  private:
     96   // Overridden from ui::EventHandler:
     97   virtual void OnEvent(ui::Event* event) OVERRIDE {
     98     ui::EventHandler::OnEvent(event);
     99     event_counts_[event->type()]++;
    100   }
    101 
    102   std::map<ui::EventType, int> event_counts_;
    103   DISALLOW_COPY_AND_ASSIGN(EventObserver);
    104 };
    105 
    106 class TestTextInputClient : public ui::TextInputClient {
    107  public:
    108   explicit TestTextInputClient(ui::TextInputType type)
    109       : type_(type) {}
    110   virtual ~TestTextInputClient() {}
    111 
    112  private:
    113   // Overridden from ui::TextInputClient:
    114   virtual void SetCompositionText(
    115       const ui::CompositionText& composition) OVERRIDE {}
    116   virtual void ConfirmCompositionText() OVERRIDE {}
    117   virtual void ClearCompositionText() OVERRIDE {}
    118   virtual void InsertText(const base::string16& text) OVERRIDE {}
    119   virtual void InsertChar(base::char16 ch, int flags) OVERRIDE {}
    120   virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
    121     return static_cast<gfx::NativeWindow>(NULL);
    122   }
    123   virtual ui::TextInputType GetTextInputType() const OVERRIDE {
    124     return type_;
    125   }
    126   virtual ui::TextInputMode GetTextInputMode() const OVERRIDE {
    127     return ui::TEXT_INPUT_MODE_DEFAULT;
    128   }
    129   virtual bool CanComposeInline() const OVERRIDE { return false; }
    130   virtual gfx::Rect GetCaretBounds() OVERRIDE { return gfx::Rect(); }
    131 
    132   virtual bool GetCompositionCharacterBounds(uint32 index,
    133                                              gfx::Rect* rect) OVERRIDE {
    134     return false;
    135   }
    136   virtual bool HasCompositionText() OVERRIDE { return false; }
    137   virtual bool GetTextRange(ui::Range* range) OVERRIDE { return false; }
    138   virtual bool GetCompositionTextRange(ui::Range* range) OVERRIDE {
    139     return false;
    140   }
    141   virtual bool GetSelectionRange(ui::Range* range) OVERRIDE { return false; }
    142   virtual bool SetSelectionRange(const ui::Range& range) OVERRIDE {
    143     return false;
    144   }
    145   virtual bool DeleteRange(const ui::Range& range) OVERRIDE { return false; }
    146   virtual bool GetTextFromRange(const ui::Range& range,
    147                                 base::string16* text) OVERRIDE {
    148     return false;
    149   }
    150   virtual void OnInputMethodChanged() OVERRIDE {}
    151   virtual bool ChangeTextDirectionAndLayoutAlignment(
    152       base::i18n::TextDirection direction) OVERRIDE { return false; }
    153   virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE {}
    154   virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {}
    155 
    156   ui::TextInputType type_;
    157 
    158   DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
    159 };
    160 
    161 }  // namespace
    162 
    163 class KeyboardControllerTest : public testing::Test {
    164  public:
    165   KeyboardControllerTest() {}
    166   virtual ~KeyboardControllerTest() {}
    167 
    168   virtual void SetUp() OVERRIDE {
    169     aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
    170     aura_test_helper_->SetUp();
    171     ui::SetUpInputMethodFactoryForTesting();
    172     focus_controller_.reset(new TestFocusController(root_window()));
    173   }
    174 
    175   virtual void TearDown() OVERRIDE {
    176     focus_controller_.reset();
    177     aura_test_helper_->TearDown();
    178   }
    179 
    180   aura::RootWindow* root_window() { return aura_test_helper_->root_window(); }
    181 
    182   void ShowKeyboard(KeyboardController* controller) {
    183     TestTextInputClient test_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
    184     controller->OnTextInputStateChanged(&test_text_input_client);
    185   }
    186 
    187  protected:
    188   base::MessageLoopForUI message_loop_;
    189   scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
    190   scoped_ptr<TestFocusController> focus_controller_;
    191 
    192  private:
    193   DISALLOW_COPY_AND_ASSIGN(KeyboardControllerTest);
    194 };
    195 
    196 TEST_F(KeyboardControllerTest, KeyboardSize) {
    197   KeyboardControllerProxy* proxy = new TestKeyboardControllerProxy();
    198   KeyboardController controller(proxy);
    199 
    200   scoped_ptr<aura::Window> container(controller.GetContainerWindow());
    201   gfx::Rect bounds(0, 0, 100, 100);
    202   container->SetBounds(bounds);
    203 
    204   const gfx::Rect& before_bounds = proxy->GetKeyboardWindow()->bounds();
    205   gfx::Rect new_bounds(
    206       before_bounds.x(), before_bounds.y(),
    207       before_bounds.width() / 2, before_bounds.height() / 2);
    208 
    209   // The KeyboardController's LayoutManager shouldn't let this happen
    210   proxy->GetKeyboardWindow()->SetBounds(new_bounds);
    211   ASSERT_EQ(before_bounds, proxy->GetKeyboardWindow()->bounds());
    212 }
    213 
    214 // Tests that tapping/clicking inside the keyboard does not give it focus.
    215 TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
    216   const gfx::Rect& root_bounds = root_window()->bounds();
    217   aura::test::EventCountDelegate delegate;
    218   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
    219   window->Init(ui::LAYER_NOT_DRAWN);
    220   window->SetBounds(root_bounds);
    221   root_window()->AddChild(window.get());
    222   window->Show();
    223   window->Focus();
    224 
    225   KeyboardControllerProxy* proxy = new TestKeyboardControllerProxy();
    226   KeyboardController controller(proxy);
    227 
    228   scoped_ptr<aura::Window> keyboard_container(controller.GetContainerWindow());
    229   keyboard_container->SetBounds(root_bounds);
    230 
    231   root_window()->AddChild(keyboard_container.get());
    232   keyboard_container->Show();
    233 
    234   ShowKeyboard(&controller);
    235 
    236   EXPECT_TRUE(window->IsVisible());
    237   EXPECT_TRUE(keyboard_container->IsVisible());
    238   EXPECT_TRUE(window->HasFocus());
    239   EXPECT_FALSE(keyboard_container->HasFocus());
    240 
    241   // Click on the keyboard. Make sure the keyboard receives the event, but does
    242   // not get focus.
    243   EventObserver observer;
    244   keyboard_container->AddPreTargetHandler(&observer);
    245 
    246   aura::test::EventGenerator generator(root_window());
    247   generator.MoveMouseTo(proxy->GetKeyboardWindow()->bounds().CenterPoint());
    248   generator.ClickLeftButton();
    249   EXPECT_TRUE(window->HasFocus());
    250   EXPECT_FALSE(keyboard_container->HasFocus());
    251   EXPECT_EQ("0 0", delegate.GetMouseButtonCountsAndReset());
    252   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_PRESSED));
    253   EXPECT_EQ(1, observer.GetEventCount(ui::ET_MOUSE_RELEASED));
    254 
    255   // Click outside of the keyboard. It should reach the window behind.
    256   generator.MoveMouseTo(gfx::Point());
    257   generator.ClickLeftButton();
    258   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
    259 }
    260 
    261 TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) {
    262   const gfx::Rect& root_bounds = root_window()->bounds();
    263   aura::test::EventCountDelegate delegate;
    264   scoped_ptr<aura::Window> window(new aura::Window(&delegate));
    265   window->Init(ui::LAYER_NOT_DRAWN);
    266   window->SetBounds(root_bounds);
    267   root_window()->AddChild(window.get());
    268   window->Show();
    269   window->Focus();
    270 
    271   KeyboardControllerProxy* proxy = new TestKeyboardControllerProxy();
    272   ui::InputMethod* input_method = proxy->GetInputMethod();
    273   TestTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
    274   TestTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE);
    275   input_method->SetFocusedTextInputClient(&input_client);
    276 
    277   KeyboardController controller(proxy);
    278 
    279   scoped_ptr<aura::Window> keyboard_container(controller.GetContainerWindow());
    280   keyboard_container->SetBounds(root_bounds);
    281   root_window()->AddChild(keyboard_container.get());
    282 
    283   EXPECT_TRUE(keyboard_container->IsVisible());
    284 
    285   input_method->SetFocusedTextInputClient(&no_input_client);
    286   EXPECT_FALSE(keyboard_container->IsVisible());
    287 
    288   input_method->SetFocusedTextInputClient(&input_client);
    289   EXPECT_TRUE(keyboard_container->IsVisible());
    290 }
    291 
    292 }  // namespace keyboard
    293