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