• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "ash/focus_cycler.h"
6 
7 #include "ash/launcher/launcher.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/shelf/shelf_widget.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/system/status_area_widget.h"
13 #include "ash/system/status_area_widget_delegate.h"
14 #include "ash/system/tray/system_tray.h"
15 #include "ash/wm/window_util.h"
16 #include "ash/test/ash_test_base.h"
17 #include "ash/shell_factory.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/aura/test/event_generator.h"
20 #include "ui/aura/test/test_windows.h"
21 #include "ui/aura/window.h"
22 #include "ui/views/accessible_pane_view.h"
23 #include "ui/views/controls/button/menu_button.h"
24 #include "ui/views/widget/widget.h"
25 
26 namespace ash {
27 namespace test {
28 
29 using aura::Window;
30 using internal::FocusCycler;
31 
32 namespace {
33 
GetStatusAreaWidgetDelegate(views::Widget * widget)34 internal::StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate(
35     views::Widget* widget) {
36   return static_cast<internal::StatusAreaWidgetDelegate*>(
37       widget->GetContentsView());
38 }
39 
40 class PanedWidgetDelegate : public views::WidgetDelegate {
41  public:
PanedWidgetDelegate(views::Widget * widget)42   PanedWidgetDelegate(views::Widget* widget) : widget_(widget) {}
43 
SetAccessiblePanes(const std::vector<views::View * > & panes)44   void SetAccessiblePanes(const std::vector<views::View*>& panes) {
45     accessible_panes_ = panes;
46   }
47 
48   // views::WidgetDelegate.
GetAccessiblePanes(std::vector<views::View * > * panes)49   virtual void GetAccessiblePanes(std::vector<views::View*>* panes) OVERRIDE {
50     std::copy(accessible_panes_.begin(),
51               accessible_panes_.end(),
52               std::back_inserter(*panes));
53   }
GetWidget()54   virtual views::Widget* GetWidget() OVERRIDE {
55     return widget_;
56   };
GetWidget() const57   virtual const views::Widget* GetWidget() const OVERRIDE {
58     return widget_;
59   }
60 
61  private:
62   views::Widget* widget_;
63   std::vector<views::View*> accessible_panes_;
64 };
65 
66 }  // namespace
67 
68 class FocusCyclerTest : public AshTestBase {
69  public:
FocusCyclerTest()70   FocusCyclerTest() {}
71 
SetUp()72   virtual void SetUp() OVERRIDE {
73     AshTestBase::SetUp();
74 
75     focus_cycler_.reset(new FocusCycler());
76 
77     ASSERT_TRUE(Launcher::ForPrimaryDisplay());
78   }
79 
TearDown()80   virtual void TearDown() OVERRIDE {
81     if (tray_) {
82       GetStatusAreaWidgetDelegate(tray_->GetWidget())->
83           SetFocusCyclerForTesting(NULL);
84       tray_.reset();
85     }
86 
87     shelf_widget()->SetFocusCycler(NULL);
88 
89     focus_cycler_.reset();
90 
91     AshTestBase::TearDown();
92   }
93 
94  protected:
95   // Creates the system tray, returning true on success.
CreateTray()96   bool CreateTray() {
97     if (tray_)
98       return false;
99     aura::Window* parent = Shell::GetPrimaryRootWindowController()->
100         GetContainer(ash::internal::kShellWindowId_StatusContainer);
101 
102     internal::StatusAreaWidget* widget = new internal::StatusAreaWidget(parent);
103     widget->CreateTrayViews();
104     widget->Show();
105     tray_.reset(widget->system_tray());
106     if (!tray_->GetWidget())
107       return false;
108     focus_cycler_->AddWidget(tray()->GetWidget());
109     GetStatusAreaWidgetDelegate(tray_->GetWidget())->SetFocusCyclerForTesting(
110         focus_cycler());
111     return true;
112   }
113 
focus_cycler()114   FocusCycler* focus_cycler() { return focus_cycler_.get(); }
115 
tray()116   SystemTray* tray() { return tray_.get(); }
117 
shelf_widget()118   ShelfWidget* shelf_widget() {
119     return Launcher::ForPrimaryDisplay()->shelf_widget();
120   }
121 
InstallFocusCycleOnShelf()122   void InstallFocusCycleOnShelf() {
123     // Add the shelf.
124     shelf_widget()->SetFocusCycler(focus_cycler());
125   }
126 
127  private:
128   scoped_ptr<FocusCycler> focus_cycler_;
129   scoped_ptr<SystemTray> tray_;
130 
131   DISALLOW_COPY_AND_ASSIGN(FocusCyclerTest);
132 };
133 
TEST_F(FocusCyclerTest,CycleFocusBrowserOnly)134 TEST_F(FocusCyclerTest, CycleFocusBrowserOnly) {
135   // Create a single test window.
136   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
137   wm::ActivateWindow(window0.get());
138   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
139 
140   // Cycle the window
141   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
142   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
143 }
144 
TEST_F(FocusCyclerTest,CycleFocusForward)145 TEST_F(FocusCyclerTest, CycleFocusForward) {
146   ASSERT_TRUE(CreateTray());
147 
148   InstallFocusCycleOnShelf();
149 
150   // Create a single test window.
151   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
152   wm::ActivateWindow(window0.get());
153   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
154 
155   // Cycle focus to the status area.
156   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
157   EXPECT_TRUE(tray()->GetWidget()->IsActive());
158 
159   // Cycle focus to the shelf.
160   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
161   EXPECT_TRUE(shelf_widget()->IsActive());
162 
163   // Cycle focus to the browser.
164   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
165   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
166 }
167 
TEST_F(FocusCyclerTest,CycleFocusBackward)168 TEST_F(FocusCyclerTest, CycleFocusBackward) {
169   ASSERT_TRUE(CreateTray());
170 
171   InstallFocusCycleOnShelf();
172 
173   // Create a single test window.
174   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
175   wm::ActivateWindow(window0.get());
176   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
177 
178   // Cycle focus to the shelf.
179   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
180   EXPECT_TRUE(shelf_widget()->IsActive());
181 
182   // Cycle focus to the status area.
183   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
184   EXPECT_TRUE(tray()->GetWidget()->IsActive());
185 
186   // Cycle focus to the browser.
187   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
188   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
189 }
190 
TEST_F(FocusCyclerTest,CycleFocusForwardBackward)191 TEST_F(FocusCyclerTest, CycleFocusForwardBackward) {
192   ASSERT_TRUE(CreateTray());
193 
194   InstallFocusCycleOnShelf();
195 
196   // Create a single test window.
197   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
198   wm::ActivateWindow(window0.get());
199   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
200 
201   // Cycle focus to the shelf.
202   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
203   EXPECT_TRUE(shelf_widget()->IsActive());
204 
205   // Cycle focus to the status area.
206   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
207   EXPECT_TRUE(tray()->GetWidget()->IsActive());
208 
209   // Cycle focus to the browser.
210   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
211   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
212 
213   // Cycle focus to the status area.
214   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
215   EXPECT_TRUE(tray()->GetWidget()->IsActive());
216 
217   // Cycle focus to the shelf.
218   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
219   EXPECT_TRUE(shelf_widget()->IsActive());
220 
221   // Cycle focus to the browser.
222   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
223   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
224 }
225 
TEST_F(FocusCyclerTest,CycleFocusNoBrowser)226 TEST_F(FocusCyclerTest, CycleFocusNoBrowser) {
227   ASSERT_TRUE(CreateTray());
228 
229   InstallFocusCycleOnShelf();
230 
231   // Add the shelf and focus it.
232   focus_cycler()->FocusWidget(shelf_widget());
233 
234   // Cycle focus to the status area.
235   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
236   EXPECT_TRUE(tray()->GetWidget()->IsActive());
237 
238   // Cycle focus to the shelf.
239   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
240   EXPECT_TRUE(shelf_widget()->IsActive());
241 
242   // Cycle focus to the status area.
243   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
244   EXPECT_TRUE(tray()->GetWidget()->IsActive());
245 
246   // Cycle focus to the shelf.
247   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
248   EXPECT_TRUE(shelf_widget()->IsActive());
249 
250   // Cycle focus to the status area.
251   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
252   EXPECT_TRUE(tray()->GetWidget()->IsActive());
253 }
254 
TEST_F(FocusCyclerTest,Shelf_CycleFocusForward)255 TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) {
256   ASSERT_TRUE(CreateTray());
257   InstallFocusCycleOnShelf();
258   shelf_widget()->Hide();
259 
260   // Create a single test window.
261   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
262   wm::ActivateWindow(window0.get());
263   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
264 
265   // Cycle focus to the status area.
266   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
267   EXPECT_TRUE(tray()->GetWidget()->IsActive());
268 
269   // Cycle focus to the browser.
270   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
271   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
272 }
273 
TEST_F(FocusCyclerTest,Shelf_CycleFocusBackwardInvisible)274 TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) {
275   ASSERT_TRUE(CreateTray());
276   InstallFocusCycleOnShelf();
277   shelf_widget()->Hide();
278 
279   // Create a single test window.
280   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
281   wm::ActivateWindow(window0.get());
282   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
283 
284   // Cycle focus to the status area.
285   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
286   EXPECT_TRUE(tray()->GetWidget()->IsActive());
287 
288   // Cycle focus to the browser.
289   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
290   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
291 }
292 
TEST_F(FocusCyclerTest,CycleFocusThroughWindowWithPanes)293 TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) {
294   ASSERT_TRUE(CreateTray());
295 
296   InstallFocusCycleOnShelf();
297 
298   scoped_ptr<PanedWidgetDelegate> test_widget_delegate;
299   scoped_ptr<views::Widget> browser_widget(new views::Widget);
300   test_widget_delegate.reset(new PanedWidgetDelegate(browser_widget.get()));
301   views::Widget::InitParams widget_params(
302       views::Widget::InitParams::TYPE_WINDOW);
303   widget_params.context = CurrentContext();
304   widget_params.delegate = test_widget_delegate.get();
305   widget_params.ownership =
306       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
307   browser_widget->Init(widget_params);
308   browser_widget->Show();
309 
310   aura::Window* browser_window = browser_widget->GetNativeView();
311 
312   views::View* root_view = browser_widget->GetRootView();
313 
314   views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
315   root_view->AddChildView(pane1);
316 
317   views::View* view1 = new views::View;
318   view1->SetFocusable(true);
319   pane1->AddChildView(view1);
320 
321   views::View* view2 = new views::View;
322   view2->SetFocusable(true);
323   pane1->AddChildView(view2);
324 
325   views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
326   root_view->AddChildView(pane2);
327 
328   views::View* view3 = new views::View;
329   view3->SetFocusable(true);
330   pane2->AddChildView(view3);
331 
332   views::View* view4 = new views::View;
333   view4->SetFocusable(true);
334   pane2->AddChildView(view4);
335 
336   std::vector<views::View*> panes;
337   panes.push_back(pane1);
338   panes.push_back(pane2);
339 
340   test_widget_delegate->SetAccessiblePanes(panes);
341 
342   views::FocusManager* focus_manager = browser_widget->GetFocusManager();
343 
344   // Cycle focus to the status area.
345   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
346   EXPECT_TRUE(tray()->GetWidget()->IsActive());
347 
348   // Cycle focus to the shelf.
349   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
350   EXPECT_TRUE(shelf_widget()->IsActive());
351 
352   // Cycle focus to the first pane in the browser.
353   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
354   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
355   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
356 
357   // Cycle focus to the second pane in the browser.
358   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
359   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
360   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
361 
362   // Cycle focus back to the status area.
363   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
364   EXPECT_TRUE(tray()->GetWidget()->IsActive());
365 
366   // Reverse direction - back to the second pane in the browser.
367   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
368   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
369   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
370 
371   // Back to the first pane in the browser.
372   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
373   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
374   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
375 
376   // Back to the shelf.
377   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
378   EXPECT_TRUE(shelf_widget()->IsActive());
379 
380   // Back to the status area.
381   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
382   EXPECT_TRUE(tray()->GetWidget()->IsActive());
383 
384   // Pressing "Escape" while on the status area should
385   // deactivate it, and activate the browser window.
386   aura::Window* root = Shell::GetPrimaryRootWindow();
387   aura::test::EventGenerator event_generator(root, root);
388   event_generator.PressKey(ui::VKEY_ESCAPE, 0);
389   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
390   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
391 
392   // Similarly, pressing "Escape" while on the shelf.
393   // should do the same thing.
394   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
395   EXPECT_TRUE(shelf_widget()->IsActive());
396   event_generator.PressKey(ui::VKEY_ESCAPE, 0);
397   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
398   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
399 }
400 
401 }  // namespace test
402 }  // namespace ash
403