focus_cycler_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/event_generator.h"
19#include "ui/aura/test/test_windows.h"
20#include "ui/aura/window.h"
21#include "ui/aura/window_event_dispatcher.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
26namespace ash {
27namespace test {
28
29using aura::Window;
30using internal::FocusCycler;
31
32namespace {
33
34internal::StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate(
35    views::Widget* widget) {
36  return static_cast<internal::StatusAreaWidgetDelegate*>(
37      widget->GetContentsView());
38}
39
40class PanedWidgetDelegate : public views::WidgetDelegate {
41 public:
42  PanedWidgetDelegate(views::Widget* widget) : widget_(widget) {}
43
44  void SetAccessiblePanes(const std::vector<views::View*>& panes) {
45    accessible_panes_ = panes;
46  }
47
48  // views::WidgetDelegate.
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  }
54  virtual views::Widget* GetWidget() OVERRIDE {
55    return widget_;
56  };
57  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
68class FocusCyclerTest : public AshTestBase {
69 public:
70  FocusCyclerTest() {}
71
72  virtual void SetUp() OVERRIDE {
73    AshTestBase::SetUp();
74
75    focus_cycler_.reset(new FocusCycler());
76
77    ASSERT_TRUE(Shelf::ForPrimaryDisplay());
78  }
79
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.
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
114  FocusCycler* focus_cycler() { return focus_cycler_.get(); }
115
116  SystemTray* tray() { return tray_.get(); }
117
118  ShelfWidget* shelf_widget() {
119    return Shelf::ForPrimaryDisplay()->shelf_widget();
120  }
121
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
134TEST_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
145TEST_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
168TEST_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
191TEST_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
226TEST_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
255// Tests that focus cycles from the active browser to the status area and back.
256TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) {
257  ASSERT_TRUE(CreateTray());
258  InstallFocusCycleOnShelf();
259  shelf_widget()->Hide();
260
261  // Create two test windows.
262  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
263  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
264  wm::ActivateWindow(window1.get());
265  wm::ActivateWindow(window0.get());
266  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
267
268  // Cycle focus to the status area.
269  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
270  EXPECT_TRUE(tray()->GetWidget()->IsActive());
271
272  // Cycle focus to the browser.
273  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
274  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
275
276  // Cycle focus to the status area.
277  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
278  EXPECT_TRUE(tray()->GetWidget()->IsActive());
279}
280
281TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) {
282  ASSERT_TRUE(CreateTray());
283  InstallFocusCycleOnShelf();
284  shelf_widget()->Hide();
285
286  // Create a single test window.
287  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
288  wm::ActivateWindow(window0.get());
289  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
290
291  // Cycle focus to the status area.
292  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
293  EXPECT_TRUE(tray()->GetWidget()->IsActive());
294
295  // Cycle focus to the browser.
296  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
297  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
298}
299
300TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) {
301  ASSERT_TRUE(CreateTray());
302
303  InstallFocusCycleOnShelf();
304
305  scoped_ptr<PanedWidgetDelegate> test_widget_delegate;
306  scoped_ptr<views::Widget> browser_widget(new views::Widget);
307  test_widget_delegate.reset(new PanedWidgetDelegate(browser_widget.get()));
308  views::Widget::InitParams widget_params(
309      views::Widget::InitParams::TYPE_WINDOW);
310  widget_params.context = CurrentContext();
311  widget_params.delegate = test_widget_delegate.get();
312  widget_params.ownership =
313      views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
314  browser_widget->Init(widget_params);
315  browser_widget->Show();
316
317  aura::Window* browser_window = browser_widget->GetNativeView();
318
319  views::View* root_view = browser_widget->GetRootView();
320
321  views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
322  root_view->AddChildView(pane1);
323
324  views::View* view1 = new views::View;
325  view1->SetFocusable(true);
326  pane1->AddChildView(view1);
327
328  views::View* view2 = new views::View;
329  view2->SetFocusable(true);
330  pane1->AddChildView(view2);
331
332  views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
333  root_view->AddChildView(pane2);
334
335  views::View* view3 = new views::View;
336  view3->SetFocusable(true);
337  pane2->AddChildView(view3);
338
339  views::View* view4 = new views::View;
340  view4->SetFocusable(true);
341  pane2->AddChildView(view4);
342
343  std::vector<views::View*> panes;
344  panes.push_back(pane1);
345  panes.push_back(pane2);
346
347  test_widget_delegate->SetAccessiblePanes(panes);
348
349  views::FocusManager* focus_manager = browser_widget->GetFocusManager();
350
351  // Cycle focus to the status area.
352  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
353  EXPECT_TRUE(tray()->GetWidget()->IsActive());
354
355  // Cycle focus to the shelf.
356  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
357  EXPECT_TRUE(shelf_widget()->IsActive());
358
359  // Cycle focus to the first pane in the browser.
360  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
361  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
362  EXPECT_EQ(focus_manager->GetFocusedView(), view1);
363
364  // Cycle focus to the second pane in the browser.
365  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
366  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
367  EXPECT_EQ(focus_manager->GetFocusedView(), view3);
368
369  // Cycle focus back to the status area.
370  focus_cycler()->RotateFocus(FocusCycler::FORWARD);
371  EXPECT_TRUE(tray()->GetWidget()->IsActive());
372
373  // Reverse direction - back to the second pane in the browser.
374  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
375  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
376  EXPECT_EQ(focus_manager->GetFocusedView(), view3);
377
378  // Back to the first pane in the browser.
379  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
380  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
381  EXPECT_EQ(focus_manager->GetFocusedView(), view1);
382
383  // Back to the shelf.
384  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
385  EXPECT_TRUE(shelf_widget()->IsActive());
386
387  // Back to the status area.
388  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
389  EXPECT_TRUE(tray()->GetWidget()->IsActive());
390
391  // Pressing "Escape" while on the status area should
392  // deactivate it, and activate the browser window.
393  aura::Window* root = Shell::GetPrimaryRootWindow();
394  aura::test::EventGenerator event_generator(root, root);
395  event_generator.PressKey(ui::VKEY_ESCAPE, 0);
396  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
397  EXPECT_EQ(focus_manager->GetFocusedView(), view1);
398
399  // Similarly, pressing "Escape" while on the shelf.
400  // should do the same thing.
401  focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
402  EXPECT_TRUE(shelf_widget()->IsActive());
403  event_generator.PressKey(ui::VKEY_ESCAPE, 0);
404  EXPECT_TRUE(wm::IsActiveWindow(browser_window));
405  EXPECT_EQ(focus_manager->GetFocusedView(), view1);
406}
407
408}  // namespace test
409}  // namespace ash
410