Home | History | Annotate | Download | only in input_method
      1 // Copyright 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 <algorithm>
      6 
      7 #include "ash/shell.h"
      8 #include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
      9 #include "chrome/test/base/in_process_browser_test.h"
     10 #include "chromeos/ime/component_extension_ime_manager.h"
     11 #include "chromeos/ime/input_method_manager.h"
     12 #include "content/public/test/browser_test_utils.h"
     13 #include "content/public/test/test_utils.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "ui/base/ime/chromeos/ibus_bridge.h"
     16 #include "ui/base/ime/input_method_factory.h"
     17 #include "ui/views/widget/widget.h"
     18 #include "ui/views/widget/widget_observer.h"
     19 
     20 namespace chromeos {
     21 namespace input_method {
     22 
     23 class ScopedModeIndicatorObserverForTesting :
     24       public ModeIndicatorObserverInterface {
     25  public:
     26   ScopedModeIndicatorObserverForTesting()
     27       : max_widget_list_size_(0) {
     28     ModeIndicatorController::SetModeIndicatorObserverForTesting(this);
     29   }
     30 
     31   virtual ~ScopedModeIndicatorObserverForTesting() {
     32     for (size_t i = 0; i < widget_list_.size(); ++i) {
     33       widget_list_[i]->RemoveObserver(this);
     34     }
     35     ModeIndicatorController::SetModeIndicatorObserverForTesting(NULL);
     36   }
     37 
     38   gfx::Rect last_bounds() const {
     39     return last_bounds_;
     40   }
     41 
     42   bool is_displayed() const {
     43     return is_displayed_;
     44   }
     45 
     46   const std::vector<views::Widget*>& widget_list() const {
     47     return widget_list_;
     48   }
     49 
     50   size_t widget_list_size() const {
     51     return widget_list_.size();
     52   }
     53 
     54   size_t max_widget_list_size() const {
     55     return max_widget_list_size_;
     56   }
     57 
     58   // ModeIndicatorObserverInterface override:
     59   virtual void AddModeIndicatorWidget(views::Widget* widget) OVERRIDE {
     60     widget_list_.push_back(widget);
     61     max_widget_list_size_ =
     62         std::max(max_widget_list_size_, widget_list_.size());
     63     widget->AddObserver(this);
     64   }
     65 
     66   // views::WidgetObserver override:
     67   virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE {
     68     std::vector<views::Widget*>::iterator it =
     69       std::find(widget_list_.begin(), widget_list_.end(), widget);
     70     if (it != widget_list_.end())
     71       widget_list_.erase(it);
     72   }
     73 
     74   // views::WidgetObserver override:
     75   virtual void OnWidgetVisibilityChanged(views::Widget* widget,
     76                                          bool visible) OVERRIDE {
     77     last_bounds_ = widget->GetWindowBoundsInScreen();
     78     is_displayed_ |= visible;
     79   }
     80 
     81  private:
     82   bool is_displayed_;
     83   gfx::Rect last_bounds_;
     84   size_t max_widget_list_size_;
     85   std::vector<views::Widget*> widget_list_;
     86 };
     87 
     88 class ModeIndicatorBrowserTest : public InProcessBrowserTest {
     89  public:
     90   ModeIndicatorBrowserTest()
     91       : InProcessBrowserTest() {}
     92   virtual ~ModeIndicatorBrowserTest() {}
     93 
     94   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     95     ui::SetUpInputMethodFactoryForTesting();
     96   }
     97 
     98   void InitializeIMF() {
     99     // Make sure ComponentExtensionIMEManager is initialized.
    100     // ComponentExtensionIMEManagerImpl::InitializeAsync posts
    101     // ReadComponentExtensionsInfo to the FILE thread for the
    102     // initialization.  If it is never initialized for some reasons,
    103     // the test is timed out and failed.
    104     ComponentExtensionIMEManager* ceimm =
    105         InputMethodManager::Get()->GetComponentExtensionIMEManager();
    106     while (!ceimm->IsInitialized()) {
    107       content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
    108     }
    109   }
    110 
    111  private:
    112   DISALLOW_COPY_AND_ASSIGN(ModeIndicatorBrowserTest);
    113 };
    114 
    115 namespace {
    116 // 43 is the designed size of the inner contents.
    117 // This value corresponds with kMinSize defined in
    118 // mode_indicator_delegate_view.cc.
    119 const int kInnerSize = 43;
    120 }  // namespace
    121 
    122 IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, Bounds) {
    123   InitializeIMF();
    124 
    125   InputMethodManager* imm = InputMethodManager::Get();
    126   ASSERT_TRUE(imm);
    127 
    128   // Add keyboard layouts to enable the mode indicator.
    129   imm->EnableLayouts("fr", "xkb:fr::fra");
    130   ASSERT_LT(1UL, imm->GetNumActiveInputMethods());
    131 
    132   chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
    133       chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
    134   candidate_window->FocusStateChanged(true);
    135 
    136   // Check if the size of the mode indicator is expected.
    137   gfx::Rect cursor1_bounds(100, 100, 1, 20);
    138   gfx::Rect mi1_bounds;
    139   {
    140     ScopedModeIndicatorObserverForTesting observer;
    141     candidate_window->SetCursorBounds(cursor1_bounds, cursor1_bounds);
    142     EXPECT_TRUE(imm->SwitchToNextInputMethod());
    143     mi1_bounds = observer.last_bounds();
    144     // The bounds should be bigger than the inner size.
    145     EXPECT_LE(kInnerSize, mi1_bounds.width());
    146     EXPECT_LE(kInnerSize, mi1_bounds.height());
    147     EXPECT_TRUE(observer.is_displayed());
    148   }
    149 
    150   // Check if the location of the mode indicator is coresponded to
    151   // the cursor bounds.
    152   gfx::Rect cursor2_bounds(50, 200, 1, 20);
    153   gfx::Rect mi2_bounds;
    154   {
    155     ScopedModeIndicatorObserverForTesting observer;
    156     candidate_window->SetCursorBounds(cursor2_bounds, cursor2_bounds);
    157     EXPECT_TRUE(imm->SwitchToNextInputMethod());
    158     mi2_bounds = observer.last_bounds();
    159     EXPECT_TRUE(observer.is_displayed());
    160   }
    161 
    162   EXPECT_EQ(cursor1_bounds.x() - cursor2_bounds.x(),
    163             mi1_bounds.x() - mi2_bounds.x());
    164   EXPECT_EQ(cursor1_bounds.y() - cursor2_bounds.y(),
    165             mi1_bounds.y() - mi2_bounds.y());
    166   EXPECT_EQ(mi1_bounds.width(),  mi2_bounds.width());
    167   EXPECT_EQ(mi1_bounds.height(), mi2_bounds.height());
    168 
    169   const gfx::Rect screen_bounds =
    170       ash::Shell::GetScreen()->GetDisplayMatching(cursor1_bounds).work_area();
    171 
    172   // Check if the location of the mode indicator is concidered with
    173   // the screen size.
    174   const gfx::Rect cursor3_bounds(100, screen_bounds.bottom() - 25, 1, 20);
    175   gfx::Rect mi3_bounds;
    176   {
    177     ScopedModeIndicatorObserverForTesting observer;
    178     candidate_window->SetCursorBounds(cursor3_bounds, cursor3_bounds);
    179     EXPECT_TRUE(imm->SwitchToNextInputMethod());
    180     mi3_bounds = observer.last_bounds();
    181     EXPECT_TRUE(observer.is_displayed());
    182     EXPECT_LT(mi3_bounds.bottom(), screen_bounds.bottom());
    183   }
    184 }
    185 
    186 IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, NumOfWidgets) {
    187   InitializeIMF();
    188 
    189   InputMethodManager* imm = InputMethodManager::Get();
    190   ASSERT_TRUE(imm);
    191 
    192   // Add keyboard layouts to enable the mode indicator.
    193   imm->EnableLayouts("fr", "xkb:fr::fra");
    194   ASSERT_LT(1UL, imm->GetNumActiveInputMethods());
    195 
    196   chromeos::IBusPanelCandidateWindowHandlerInterface* candidate_window =
    197       chromeos::IBusBridge::Get()->GetCandidateWindowHandler();
    198   candidate_window->FocusStateChanged(true);
    199 
    200   {
    201     ScopedModeIndicatorObserverForTesting observer;
    202 
    203     EXPECT_TRUE(imm->SwitchToNextInputMethod());
    204     EXPECT_EQ(1UL, observer.max_widget_list_size());
    205     const views::Widget* widget1 = observer.widget_list()[0];
    206 
    207     EXPECT_TRUE(imm->SwitchToNextInputMethod());
    208     EXPECT_EQ(2UL, observer.max_widget_list_size());
    209 
    210     // When a new mode indicator is displayed, the previous one should be
    211     // closed.
    212     content::RunAllPendingInMessageLoop();
    213     EXPECT_EQ(1UL, observer.widget_list_size());
    214     const views::Widget* widget2 = observer.widget_list()[0];
    215     EXPECT_NE(widget1, widget2);
    216   }
    217 }
    218 }  // namespace input_method
    219 }  // namespace chromeos
    220