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.
5 #include "ash/focus_cycler.h"
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"
33 StatusAreaWidgetDelegate
* GetStatusAreaWidgetDelegate(views::Widget
* widget
) {
34 return static_cast<StatusAreaWidgetDelegate
*>(widget
->GetContentsView());
37 class PanedWidgetDelegate
: public views::WidgetDelegate
{
39 PanedWidgetDelegate(views::Widget
* widget
) : widget_(widget
) {}
41 void SetAccessiblePanes(const std::vector
<views::View
*>& panes
) {
42 accessible_panes_
= panes
;
45 // views::WidgetDelegate.
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
));
51 virtual views::Widget
* GetWidget() OVERRIDE
{
54 virtual const views::Widget
* GetWidget() const OVERRIDE
{
59 views::Widget
* widget_
;
60 std::vector
<views::View
*> accessible_panes_
;
65 class FocusCyclerTest
: public AshTestBase
{
69 virtual void SetUp() OVERRIDE
{
72 focus_cycler_
.reset(new FocusCycler());
74 ASSERT_TRUE(Shelf::ForPrimaryDisplay());
77 virtual void TearDown() OVERRIDE
{
79 GetStatusAreaWidgetDelegate(tray_
->GetWidget())->
80 SetFocusCyclerForTesting(NULL
);
84 shelf_widget()->SetFocusCycler(NULL
);
86 focus_cycler_
.reset();
88 AshTestBase::TearDown();
92 // Creates the system tray, returning true on success.
96 aura::Window
* parent
=
97 Shell::GetPrimaryRootWindowController()->GetContainer(
98 ash::kShellWindowId_StatusContainer
);
100 StatusAreaWidget
* widget
= new StatusAreaWidget(parent
);
101 widget
->CreateTrayViews();
103 tray_
.reset(widget
->system_tray());
104 if (!tray_
->GetWidget())
106 focus_cycler_
->AddWidget(tray()->GetWidget());
107 GetStatusAreaWidgetDelegate(tray_
->GetWidget())->SetFocusCyclerForTesting(
112 FocusCycler
* focus_cycler() { return focus_cycler_
.get(); }
114 SystemTray
* tray() { return tray_
.get(); }
116 ShelfWidget
* shelf_widget() {
117 return Shelf::ForPrimaryDisplay()->shelf_widget();
120 void InstallFocusCycleOnShelf() {
122 shelf_widget()->SetFocusCycler(focus_cycler());
126 scoped_ptr
<FocusCycler
> focus_cycler_
;
127 scoped_ptr
<SystemTray
> tray_
;
129 DISALLOW_COPY_AND_ASSIGN(FocusCyclerTest
);
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()));
139 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
140 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
143 TEST_F(FocusCyclerTest
, CycleFocusForward
) {
144 ASSERT_TRUE(CreateTray());
146 InstallFocusCycleOnShelf();
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()));
153 // Cycle focus to the status area.
154 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
155 EXPECT_TRUE(tray()->GetWidget()->IsActive());
157 // Cycle focus to the shelf.
158 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
159 EXPECT_TRUE(shelf_widget()->IsActive());
161 // Cycle focus to the browser.
162 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
163 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
166 TEST_F(FocusCyclerTest
, CycleFocusBackward
) {
167 ASSERT_TRUE(CreateTray());
169 InstallFocusCycleOnShelf();
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()));
176 // Cycle focus to the shelf.
177 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
178 EXPECT_TRUE(shelf_widget()->IsActive());
180 // Cycle focus to the status area.
181 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
182 EXPECT_TRUE(tray()->GetWidget()->IsActive());
184 // Cycle focus to the browser.
185 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
186 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
189 TEST_F(FocusCyclerTest
, CycleFocusForwardBackward
) {
190 ASSERT_TRUE(CreateTray());
192 InstallFocusCycleOnShelf();
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()));
199 // Cycle focus to the shelf.
200 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
201 EXPECT_TRUE(shelf_widget()->IsActive());
203 // Cycle focus to the status area.
204 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
205 EXPECT_TRUE(tray()->GetWidget()->IsActive());
207 // Cycle focus to the browser.
208 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
209 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
211 // Cycle focus to the status area.
212 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
213 EXPECT_TRUE(tray()->GetWidget()->IsActive());
215 // Cycle focus to the shelf.
216 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
217 EXPECT_TRUE(shelf_widget()->IsActive());
219 // Cycle focus to the browser.
220 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
221 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
224 TEST_F(FocusCyclerTest
, CycleFocusNoBrowser
) {
225 ASSERT_TRUE(CreateTray());
227 InstallFocusCycleOnShelf();
229 // Add the shelf and focus it.
230 focus_cycler()->FocusWidget(shelf_widget());
232 // Cycle focus to the status area.
233 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
234 EXPECT_TRUE(tray()->GetWidget()->IsActive());
236 // Cycle focus to the shelf.
237 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
238 EXPECT_TRUE(shelf_widget()->IsActive());
240 // Cycle focus to the status area.
241 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
242 EXPECT_TRUE(tray()->GetWidget()->IsActive());
244 // Cycle focus to the shelf.
245 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
246 EXPECT_TRUE(shelf_widget()->IsActive());
248 // Cycle focus to the status area.
249 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
250 EXPECT_TRUE(tray()->GetWidget()->IsActive());
253 // Tests that focus cycles from the active browser to the status area and back.
254 TEST_F(FocusCyclerTest
, Shelf_CycleFocusForward
) {
255 ASSERT_TRUE(CreateTray());
256 InstallFocusCycleOnShelf();
257 shelf_widget()->Hide();
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()));
266 // Cycle focus to the status area.
267 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
268 EXPECT_TRUE(tray()->GetWidget()->IsActive());
270 // Cycle focus to the browser.
271 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
272 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
274 // Cycle focus to the status area.
275 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
276 EXPECT_TRUE(tray()->GetWidget()->IsActive());
279 TEST_F(FocusCyclerTest
, Shelf_CycleFocusBackwardInvisible
) {
280 ASSERT_TRUE(CreateTray());
281 InstallFocusCycleOnShelf();
282 shelf_widget()->Hide();
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()));
289 // Cycle focus to the status area.
290 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
291 EXPECT_TRUE(tray()->GetWidget()->IsActive());
293 // Cycle focus to the browser.
294 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
295 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
298 TEST_F(FocusCyclerTest
, CycleFocusThroughWindowWithPanes
) {
299 ASSERT_TRUE(CreateTray());
301 InstallFocusCycleOnShelf();
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();
315 aura::Window
* browser_window
= browser_widget
->GetNativeView();
317 views::View
* root_view
= browser_widget
->GetRootView();
319 views::AccessiblePaneView
* pane1
= new views::AccessiblePaneView();
320 root_view
->AddChildView(pane1
);
322 views::View
* view1
= new views::View
;
323 view1
->SetFocusable(true);
324 pane1
->AddChildView(view1
);
326 views::View
* view2
= new views::View
;
327 view2
->SetFocusable(true);
328 pane1
->AddChildView(view2
);
330 views::AccessiblePaneView
* pane2
= new views::AccessiblePaneView();
331 root_view
->AddChildView(pane2
);
333 views::View
* view3
= new views::View
;
334 view3
->SetFocusable(true);
335 pane2
->AddChildView(view3
);
337 views::View
* view4
= new views::View
;
338 view4
->SetFocusable(true);
339 pane2
->AddChildView(view4
);
341 std::vector
<views::View
*> panes
;
342 panes
.push_back(pane1
);
343 panes
.push_back(pane2
);
345 test_widget_delegate
->SetAccessiblePanes(panes
);
347 views::FocusManager
* focus_manager
= browser_widget
->GetFocusManager();
349 // Cycle focus to the status area.
350 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
351 EXPECT_TRUE(tray()->GetWidget()->IsActive());
353 // Cycle focus to the shelf.
354 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
355 EXPECT_TRUE(shelf_widget()->IsActive());
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
);
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
);
367 // Cycle focus back to the status area.
368 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
369 EXPECT_TRUE(tray()->GetWidget()->IsActive());
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
);
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
);
381 // Back to the shelf.
382 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
383 EXPECT_TRUE(shelf_widget()->IsActive());
385 // Back to the status area.
386 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
387 EXPECT_TRUE(tray()->GetWidget()->IsActive());
389 // Pressing "Escape" while on the status area should
390 // deactivate it, and activate the browser window.
391 aura::Window
* root
= Shell::GetPrimaryRootWindow();
392 aura::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
);
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
);