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/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"
30 using internal::FocusCycler
;
34 internal::StatusAreaWidgetDelegate
* GetStatusAreaWidgetDelegate(
35 views::Widget
* widget
) {
36 return static_cast<internal::StatusAreaWidgetDelegate
*>(
37 widget
->GetContentsView());
40 class PanedWidgetDelegate
: public views::WidgetDelegate
{
42 PanedWidgetDelegate(views::Widget
* widget
) : widget_(widget
) {}
44 void SetAccessiblePanes(const std::vector
<views::View
*>& panes
) {
45 accessible_panes_
= panes
;
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
));
54 virtual views::Widget
* GetWidget() OVERRIDE
{
57 virtual const views::Widget
* GetWidget() const OVERRIDE
{
62 views::Widget
* widget_
;
63 std::vector
<views::View
*> accessible_panes_
;
68 class FocusCyclerTest
: public AshTestBase
{
72 virtual void SetUp() OVERRIDE
{
75 focus_cycler_
.reset(new FocusCycler());
77 ASSERT_TRUE(Launcher::ForPrimaryDisplay());
80 virtual void TearDown() OVERRIDE
{
82 GetStatusAreaWidgetDelegate(tray_
->GetWidget())->
83 SetFocusCyclerForTesting(NULL
);
87 shelf_widget()->SetFocusCycler(NULL
);
89 focus_cycler_
.reset();
91 AshTestBase::TearDown();
95 // Creates the system tray, returning true on success.
99 aura::Window
* parent
= Shell::GetPrimaryRootWindowController()->
100 GetContainer(ash::internal::kShellWindowId_StatusContainer
);
102 internal::StatusAreaWidget
* widget
= new internal::StatusAreaWidget(parent
);
103 widget
->CreateTrayViews();
105 tray_
.reset(widget
->system_tray());
106 if (!tray_
->GetWidget())
108 focus_cycler_
->AddWidget(tray()->GetWidget());
109 GetStatusAreaWidgetDelegate(tray_
->GetWidget())->SetFocusCyclerForTesting(
114 FocusCycler
* focus_cycler() { return focus_cycler_
.get(); }
116 SystemTray
* tray() { return tray_
.get(); }
118 ShelfWidget
* shelf_widget() {
119 return Launcher::ForPrimaryDisplay()->shelf_widget();
122 void InstallFocusCycleOnShelf() {
124 shelf_widget()->SetFocusCycler(focus_cycler());
128 scoped_ptr
<FocusCycler
> focus_cycler_
;
129 scoped_ptr
<SystemTray
> tray_
;
131 DISALLOW_COPY_AND_ASSIGN(FocusCyclerTest
);
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()));
141 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
142 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
145 TEST_F(FocusCyclerTest
, CycleFocusForward
) {
146 ASSERT_TRUE(CreateTray());
148 InstallFocusCycleOnShelf();
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()));
155 // Cycle focus to the status area.
156 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
157 EXPECT_TRUE(tray()->GetWidget()->IsActive());
159 // Cycle focus to the shelf.
160 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
161 EXPECT_TRUE(shelf_widget()->IsActive());
163 // Cycle focus to the browser.
164 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
165 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
168 TEST_F(FocusCyclerTest
, CycleFocusBackward
) {
169 ASSERT_TRUE(CreateTray());
171 InstallFocusCycleOnShelf();
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()));
178 // Cycle focus to the shelf.
179 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
180 EXPECT_TRUE(shelf_widget()->IsActive());
182 // Cycle focus to the status area.
183 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
184 EXPECT_TRUE(tray()->GetWidget()->IsActive());
186 // Cycle focus to the browser.
187 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
188 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
191 TEST_F(FocusCyclerTest
, CycleFocusForwardBackward
) {
192 ASSERT_TRUE(CreateTray());
194 InstallFocusCycleOnShelf();
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()));
201 // Cycle focus to the shelf.
202 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
203 EXPECT_TRUE(shelf_widget()->IsActive());
205 // Cycle focus to the status area.
206 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
207 EXPECT_TRUE(tray()->GetWidget()->IsActive());
209 // Cycle focus to the browser.
210 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
211 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
213 // Cycle focus to the status area.
214 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
215 EXPECT_TRUE(tray()->GetWidget()->IsActive());
217 // Cycle focus to the shelf.
218 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
219 EXPECT_TRUE(shelf_widget()->IsActive());
221 // Cycle focus to the browser.
222 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
223 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
226 TEST_F(FocusCyclerTest
, CycleFocusNoBrowser
) {
227 ASSERT_TRUE(CreateTray());
229 InstallFocusCycleOnShelf();
231 // Add the shelf and focus it.
232 focus_cycler()->FocusWidget(shelf_widget());
234 // Cycle focus to the status area.
235 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
236 EXPECT_TRUE(tray()->GetWidget()->IsActive());
238 // Cycle focus to the shelf.
239 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
240 EXPECT_TRUE(shelf_widget()->IsActive());
242 // Cycle focus to the status area.
243 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
244 EXPECT_TRUE(tray()->GetWidget()->IsActive());
246 // Cycle focus to the shelf.
247 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
248 EXPECT_TRUE(shelf_widget()->IsActive());
250 // Cycle focus to the status area.
251 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
252 EXPECT_TRUE(tray()->GetWidget()->IsActive());
255 TEST_F(FocusCyclerTest
, Shelf_CycleFocusForward
) {
256 ASSERT_TRUE(CreateTray());
257 InstallFocusCycleOnShelf();
258 shelf_widget()->Hide();
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()));
265 // Cycle focus to the status area.
266 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
267 EXPECT_TRUE(tray()->GetWidget()->IsActive());
269 // Cycle focus to the browser.
270 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
271 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
274 TEST_F(FocusCyclerTest
, Shelf_CycleFocusBackwardInvisible
) {
275 ASSERT_TRUE(CreateTray());
276 InstallFocusCycleOnShelf();
277 shelf_widget()->Hide();
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()));
284 // Cycle focus to the status area.
285 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
286 EXPECT_TRUE(tray()->GetWidget()->IsActive());
288 // Cycle focus to the browser.
289 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
290 EXPECT_TRUE(wm::IsActiveWindow(window0
.get()));
293 TEST_F(FocusCyclerTest
, CycleFocusThroughWindowWithPanes
) {
294 ASSERT_TRUE(CreateTray());
296 InstallFocusCycleOnShelf();
298 scoped_ptr
<views::Widget
> browser_widget(new views::Widget
);
299 PanedWidgetDelegate
* test_widget_delegate
=
300 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
;
305 widget_params
.ownership
=
306 views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
307 browser_widget
->Init(widget_params
);
308 browser_widget
->Show();
310 aura::Window
* browser_window
= browser_widget
->GetNativeView();
312 views::View
* root_view
= browser_widget
->GetRootView();
314 views::AccessiblePaneView
* pane1
= new views::AccessiblePaneView();
315 root_view
->AddChildView(pane1
);
317 views::View
* view1
= new views::View
;
318 view1
->set_focusable(true);
319 pane1
->AddChildView(view1
);
321 views::View
* view2
= new views::View
;
322 view2
->set_focusable(true);
323 pane1
->AddChildView(view2
);
325 views::AccessiblePaneView
* pane2
= new views::AccessiblePaneView();
326 root_view
->AddChildView(pane2
);
328 views::View
* view3
= new views::View
;
329 view3
->set_focusable(true);
330 pane2
->AddChildView(view3
);
332 views::View
* view4
= new views::View
;
333 view4
->set_focusable(true);
334 pane2
->AddChildView(view4
);
336 std::vector
<views::View
*> panes
;
337 panes
.push_back(pane1
);
338 panes
.push_back(pane2
);
340 test_widget_delegate
->SetAccessiblePanes(panes
);
342 views::FocusManager
* focus_manager
= browser_widget
->GetFocusManager();
344 // Cycle focus to the status area.
345 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
346 EXPECT_TRUE(tray()->GetWidget()->IsActive());
348 // Cycle focus to the shelf.
349 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
350 EXPECT_TRUE(shelf_widget()->IsActive());
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
);
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
);
362 // Cycle focus back to the status area.
363 focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
364 EXPECT_TRUE(tray()->GetWidget()->IsActive());
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
);
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
);
376 // Back to the shelf.
377 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
378 EXPECT_TRUE(shelf_widget()->IsActive());
380 // Back to the status area.
381 focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
382 EXPECT_TRUE(tray()->GetWidget()->IsActive());
384 // Pressing "Escape" while on the status area should
385 // deactivate it, and activate the browser window.
386 aura::RootWindow
* 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
);
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
);