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