1// Copyright 2014 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/wm/window_cycle_controller.h"
6
7#include <algorithm>
8
9#include "ash/session/session_state_delegate.h"
10#include "ash/shelf/shelf.h"
11#include "ash/shelf/shelf_widget.h"
12#include "ash/shell.h"
13#include "ash/shell_window_ids.h"
14#include "ash/test/ash_test_base.h"
15#include "ash/test/shelf_test_api.h"
16#include "ash/test/shelf_view_test_api.h"
17#include "ash/test/test_shelf_delegate.h"
18#include "ash/test/test_shell_delegate.h"
19#include "ash/wm/window_cycle_list.h"
20#include "ash/wm/window_state.h"
21#include "ash/wm/window_util.h"
22#include "base/memory/scoped_ptr.h"
23#include "ui/aura/client/aura_constants.h"
24#include "ui/aura/client/screen_position_client.h"
25#include "ui/aura/env.h"
26#include "ui/aura/test/test_windows.h"
27#include "ui/aura/window.h"
28#include "ui/aura/window_event_dispatcher.h"
29#include "ui/gfx/rect.h"
30#include "ui/gfx/screen.h"
31
32namespace ash {
33
34using aura::test::CreateTestWindowWithId;
35using aura::test::TestWindowDelegate;
36using aura::Window;
37
38class WindowCycleControllerTest : public test::AshTestBase {
39 public:
40  WindowCycleControllerTest() {}
41  virtual ~WindowCycleControllerTest() {}
42
43  virtual void SetUp() OVERRIDE {
44    test::AshTestBase::SetUp();
45    ASSERT_TRUE(test::TestShelfDelegate::instance());
46
47    shelf_view_test_.reset(new test::ShelfViewTestAPI(
48        test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
49    shelf_view_test_->SetAnimationDuration(1);
50  }
51
52  aura::Window* CreatePanelWindow() {
53    gfx::Rect rect(100, 100);
54    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
55        NULL, ui::wm::WINDOW_TYPE_PANEL, 0, rect);
56    test::TestShelfDelegate::instance()->AddShelfItem(window);
57    shelf_view_test_->RunMessageLoopUntilAnimationsDone();
58    return window;
59  }
60
61 private:
62  scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
63
64  DISALLOW_COPY_AND_ASSIGN(WindowCycleControllerTest);
65};
66
67TEST_F(WindowCycleControllerTest, HandleCycleWindowBaseCases) {
68  WindowCycleController* controller =
69      Shell::GetInstance()->window_cycle_controller();
70
71  // Cycling doesn't crash if there are no windows.
72  controller->HandleCycleWindow(WindowCycleController::FORWARD);
73
74  // Create a single test window.
75  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
76  wm::ActivateWindow(window0.get());
77  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
78
79  // Cycling works for a single window, even though nothing changes.
80  controller->HandleCycleWindow(WindowCycleController::FORWARD);
81  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
82}
83
84// Verifies if there is only one window and it isn't active that cycling
85// activates it.
86TEST_F(WindowCycleControllerTest, SingleWindowNotActive) {
87  WindowCycleController* controller =
88      Shell::GetInstance()->window_cycle_controller();
89
90  // Create a single test window.
91  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
92  wm::ActivateWindow(window0.get());
93  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
94
95  // Rotate focus, this should move focus to another window that isn't part of
96  // the default container.
97  Shell::GetInstance()->RotateFocus(Shell::FORWARD);
98  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
99
100  // Cycling should activate the window.
101  controller->HandleCycleWindow(WindowCycleController::FORWARD);
102  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
103}
104
105TEST_F(WindowCycleControllerTest, HandleCycleWindow) {
106  WindowCycleController* controller =
107      Shell::GetInstance()->window_cycle_controller();
108
109  // Set up several windows to use to test cycling.  Create them in reverse
110  // order so they are stacked 0 over 1 over 2.
111  scoped_ptr<Window> window2(CreateTestWindowInShellWithId(2));
112  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
113  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
114  wm::ActivateWindow(window0.get());
115
116  // Simulate pressing and releasing Alt-tab.
117  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
118  controller->HandleCycleWindow(WindowCycleController::FORWARD);
119
120  // Window lists should return the topmost window in front.
121  ASSERT_TRUE(controller->window_cycle_list());
122  ASSERT_EQ(3u, controller->window_cycle_list()->windows().size());
123  ASSERT_EQ(window0.get(), controller->window_cycle_list()->windows()[0]);
124  ASSERT_EQ(window1.get(), controller->window_cycle_list()->windows()[1]);
125  ASSERT_EQ(window2.get(), controller->window_cycle_list()->windows()[2]);
126
127  controller->StopCycling();
128  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
129
130  // Pressing and releasing Alt-tab again should cycle back to the most-
131  // recently-used window in the current child order.
132  controller->HandleCycleWindow(WindowCycleController::FORWARD);
133  controller->StopCycling();
134  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
135
136  // Pressing Alt-tab multiple times without releasing Alt should cycle through
137  // all the windows and wrap around.
138  controller->HandleCycleWindow(WindowCycleController::FORWARD);
139  EXPECT_TRUE(controller->IsCycling());
140  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
141
142  controller->HandleCycleWindow(WindowCycleController::FORWARD);
143  EXPECT_TRUE(controller->IsCycling());
144  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
145
146  controller->HandleCycleWindow(WindowCycleController::FORWARD);
147  EXPECT_TRUE(controller->IsCycling());
148  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
149
150  controller->StopCycling();
151  EXPECT_FALSE(controller->IsCycling());
152  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
153
154  // Reset our stacking order.
155  wm::ActivateWindow(window2.get());
156  wm::ActivateWindow(window1.get());
157  wm::ActivateWindow(window0.get());
158
159  // Likewise we can cycle backwards through all the windows.
160  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
161  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
162  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
163  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
164  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
165  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
166  controller->StopCycling();
167  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
168
169  // When the screen is locked, cycling window does not take effect.
170  Shell::GetInstance()->session_state_delegate()->LockScreen();
171  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
172  controller->HandleCycleWindow(WindowCycleController::FORWARD);
173  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
174  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
175  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
176
177  Shell::GetInstance()->session_state_delegate()->UnlockScreen();
178  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
179  controller->HandleCycleWindow(WindowCycleController::FORWARD);
180  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
181  controller->HandleCycleWindow(WindowCycleController::FORWARD);
182  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
183
184  // When a modal window is active, cycling window does not take effect.
185  aura::Window* modal_container =
186      ash::Shell::GetContainer(
187          Shell::GetPrimaryRootWindow(),
188          kShellWindowId_SystemModalContainer);
189  scoped_ptr<Window> modal_window(
190      CreateTestWindowWithId(-2, modal_container));
191  modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
192  wm::ActivateWindow(modal_window.get());
193  EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
194  controller->HandleCycleWindow(WindowCycleController::FORWARD);
195  EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
196  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
197  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
198  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
199  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
200  EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
201  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
202  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
203  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
204}
205
206// Cycles between a maximized and normal window.
207TEST_F(WindowCycleControllerTest, MaximizedWindow) {
208  // Create a couple of test windows.
209  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
210  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
211  wm::WindowState* window1_state = wm::GetWindowState(window1.get());
212  window1_state->Maximize();
213  window1_state->Activate();
214  EXPECT_TRUE(window1_state->IsActive());
215
216  // Rotate focus, this should move focus to window0.
217  WindowCycleController* controller =
218      Shell::GetInstance()->window_cycle_controller();
219  controller->HandleCycleWindow(WindowCycleController::FORWARD);
220  EXPECT_TRUE(wm::GetWindowState(window0.get())->IsActive());
221
222  // One more time.
223  controller->HandleCycleWindow(WindowCycleController::FORWARD);
224  EXPECT_TRUE(window1_state->IsActive());
225}
226
227// Cycles to a minimized window.
228TEST_F(WindowCycleControllerTest, Minimized) {
229  // Create a couple of test windows.
230  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
231  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
232  wm::WindowState* window0_state = wm::GetWindowState(window0.get());
233  wm::WindowState* window1_state = wm::GetWindowState(window1.get());
234
235  window1_state->Minimize();
236  window0_state->Activate();
237  EXPECT_TRUE(window0_state->IsActive());
238
239  // Rotate focus, this should move focus to window1 and unminimize it.
240  WindowCycleController* controller =
241      Shell::GetInstance()->window_cycle_controller();
242  controller->HandleCycleWindow(WindowCycleController::FORWARD);
243  EXPECT_FALSE(window1_state->IsMinimized());
244  EXPECT_TRUE(window1_state->IsActive());
245
246  // One more time back to w0.
247  controller->HandleCycleWindow(WindowCycleController::FORWARD);
248  EXPECT_TRUE(window0_state->IsActive());
249}
250
251TEST_F(WindowCycleControllerTest, AlwaysOnTopWindow) {
252  WindowCycleController* controller =
253      Shell::GetInstance()->window_cycle_controller();
254
255  // Set up several windows to use to test cycling.
256  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
257  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
258
259  Window* top_container =
260      Shell::GetContainer(
261          Shell::GetPrimaryRootWindow(),
262          kShellWindowId_AlwaysOnTopContainer);
263  scoped_ptr<Window> window2(CreateTestWindowWithId(2, top_container));
264  wm::ActivateWindow(window0.get());
265
266  // Simulate pressing and releasing Alt-tab.
267  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
268  controller->HandleCycleWindow(WindowCycleController::FORWARD);
269
270  // Window lists should return the topmost window in front.
271  ASSERT_TRUE(controller->window_cycle_list());
272  ASSERT_EQ(3u, controller->window_cycle_list()->windows().size());
273  EXPECT_EQ(window0.get(), controller->window_cycle_list()->windows()[0]);
274  EXPECT_EQ(window2.get(), controller->window_cycle_list()->windows()[1]);
275  EXPECT_EQ(window1.get(), controller->window_cycle_list()->windows()[2]);
276
277  controller->StopCycling();
278  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
279
280  controller->HandleCycleWindow(WindowCycleController::FORWARD);
281  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
282
283  controller->StopCycling();
284
285  controller->HandleCycleWindow(WindowCycleController::FORWARD);
286  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
287
288  controller->HandleCycleWindow(WindowCycleController::FORWARD);
289  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
290
291  controller->HandleCycleWindow(WindowCycleController::FORWARD);
292  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
293}
294
295TEST_F(WindowCycleControllerTest, AlwaysOnTopMultiWindow) {
296  WindowCycleController* controller =
297      Shell::GetInstance()->window_cycle_controller();
298
299  // Set up several windows to use to test cycling.
300  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
301  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
302
303  Window* top_container =
304      Shell::GetContainer(
305          Shell::GetPrimaryRootWindow(),
306          kShellWindowId_AlwaysOnTopContainer);
307  scoped_ptr<Window> window2(CreateTestWindowWithId(2, top_container));
308  scoped_ptr<Window> window3(CreateTestWindowWithId(3, top_container));
309  wm::ActivateWindow(window0.get());
310
311  // Simulate pressing and releasing Alt-tab.
312  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
313  controller->HandleCycleWindow(WindowCycleController::FORWARD);
314
315  // Window lists should return the topmost window in front.
316  ASSERT_TRUE(controller->window_cycle_list());
317  ASSERT_EQ(4u, controller->window_cycle_list()->windows().size());
318  EXPECT_EQ(window0.get(), controller->window_cycle_list()->windows()[0]);
319  EXPECT_EQ(window3.get(), controller->window_cycle_list()->windows()[1]);
320  EXPECT_EQ(window2.get(), controller->window_cycle_list()->windows()[2]);
321  EXPECT_EQ(window1.get(), controller->window_cycle_list()->windows()[3]);
322
323  controller->StopCycling();
324  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
325
326  controller->HandleCycleWindow(WindowCycleController::FORWARD);
327  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
328
329  controller->StopCycling();
330
331  controller->HandleCycleWindow(WindowCycleController::FORWARD);
332  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
333
334  controller->HandleCycleWindow(WindowCycleController::FORWARD);
335  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
336
337  controller->HandleCycleWindow(WindowCycleController::FORWARD);
338  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
339
340  controller->HandleCycleWindow(WindowCycleController::FORWARD);
341  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
342}
343
344TEST_F(WindowCycleControllerTest, AlwaysOnTopMultipleRootWindows) {
345  if (!SupportsMultipleDisplays())
346    return;
347
348  // Set up a second root window
349  UpdateDisplay("1000x600,600x400");
350  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
351  ASSERT_EQ(2U, root_windows.size());
352
353  WindowCycleController* controller =
354      Shell::GetInstance()->window_cycle_controller();
355
356  Shell::GetInstance()->set_target_root_window(root_windows[0]);
357
358  // Create two windows in the primary root.
359  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
360  EXPECT_EQ(root_windows[0], window0->GetRootWindow());
361  Window* top_container0 =
362      Shell::GetContainer(
363          root_windows[0],
364          kShellWindowId_AlwaysOnTopContainer);
365  scoped_ptr<Window> window1(CreateTestWindowWithId(1, top_container0));
366  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
367
368  // And two on the secondary root.
369  Shell::GetInstance()->set_target_root_window(root_windows[1]);
370  scoped_ptr<Window> window2(CreateTestWindowInShellWithId(2));
371  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
372
373  Window* top_container1 =
374      Shell::GetContainer(
375          root_windows[1],
376          kShellWindowId_AlwaysOnTopContainer);
377  scoped_ptr<Window> window3(CreateTestWindowWithId(3, top_container1));
378  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
379
380  // Move the active root window to the secondary.
381  Shell::GetInstance()->set_target_root_window(root_windows[1]);
382
383  wm::ActivateWindow(window2.get());
384
385  EXPECT_EQ(root_windows[0], window0->GetRootWindow());
386  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
387  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
388  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
389
390  // Simulate pressing and releasing Alt-tab.
391  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
392  controller->HandleCycleWindow(WindowCycleController::FORWARD);
393
394  // Window lists should return the topmost window in front.
395  ASSERT_TRUE(controller->window_cycle_list());
396  ASSERT_EQ(4u, controller->window_cycle_list()->windows().size());
397  EXPECT_EQ(window2.get(), controller->window_cycle_list()->windows()[0]);
398  EXPECT_EQ(window3.get(), controller->window_cycle_list()->windows()[1]);
399  EXPECT_EQ(window1.get(), controller->window_cycle_list()->windows()[2]);
400  EXPECT_EQ(window0.get(), controller->window_cycle_list()->windows()[3]);
401
402  controller->StopCycling();
403  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
404
405  controller->HandleCycleWindow(WindowCycleController::FORWARD);
406  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
407
408  controller->StopCycling();
409
410  controller->HandleCycleWindow(WindowCycleController::FORWARD);
411  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
412
413  controller->HandleCycleWindow(WindowCycleController::FORWARD);
414  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
415
416  controller->HandleCycleWindow(WindowCycleController::FORWARD);
417  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
418
419  controller->HandleCycleWindow(WindowCycleController::FORWARD);
420  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
421}
422
423TEST_F(WindowCycleControllerTest, MostRecentlyUsed) {
424  WindowCycleController* controller =
425      Shell::GetInstance()->window_cycle_controller();
426
427  // Set up several windows to use to test cycling.
428  scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
429  scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1));
430  scoped_ptr<Window> window2(CreateTestWindowInShellWithId(2));
431
432  wm::ActivateWindow(window0.get());
433
434  // Simulate pressing and releasing Alt-tab.
435  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
436  controller->HandleCycleWindow(WindowCycleController::FORWARD);
437
438  // Window lists should return the topmost window in front.
439  ASSERT_TRUE(controller->window_cycle_list());
440  ASSERT_EQ(3u, controller->window_cycle_list()->windows().size());
441  EXPECT_EQ(window0.get(), controller->window_cycle_list()->windows()[0]);
442  EXPECT_EQ(window2.get(), controller->window_cycle_list()->windows()[1]);
443  EXPECT_EQ(window1.get(), controller->window_cycle_list()->windows()[2]);
444
445  controller->HandleCycleWindow(WindowCycleController::FORWARD);
446  controller->StopCycling();
447  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
448
449
450  controller->HandleCycleWindow(WindowCycleController::FORWARD);
451  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
452
453  controller->StopCycling();
454
455  controller->HandleCycleWindow(WindowCycleController::FORWARD);
456  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
457
458  controller->HandleCycleWindow(WindowCycleController::FORWARD);
459  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
460
461  controller->HandleCycleWindow(WindowCycleController::FORWARD);
462  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
463}
464
465// Tests that beginning window selection hides the app list.
466TEST_F(WindowCycleControllerTest, SelectingHidesAppList) {
467  WindowCycleController* controller =
468      Shell::GetInstance()->window_cycle_controller();
469
470  scoped_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
471  scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
472  Shell::GetInstance()->ShowAppList(NULL);
473  EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
474  controller->HandleCycleWindow(WindowCycleController::FORWARD);
475  EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
476}
477
478// Tests that cycling through windows shows and minimizes windows as they
479// are passed.
480TEST_F(WindowCycleControllerTest, CyclePreservesMinimization) {
481  WindowCycleController* controller =
482      Shell::GetInstance()->window_cycle_controller();
483
484  scoped_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
485  scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
486  wm::ActivateWindow(window1.get());
487  wm::GetWindowState(window1.get())->Minimize();
488  wm::ActivateWindow(window0.get());
489  EXPECT_TRUE(wm::IsWindowMinimized(window1.get()));
490
491  // On window 2.
492  controller->HandleCycleWindow(WindowCycleController::FORWARD);
493  EXPECT_FALSE(wm::IsWindowMinimized(window1.get()));
494
495  // Back on window 1.
496  controller->HandleCycleWindow(WindowCycleController::FORWARD);
497  EXPECT_TRUE(wm::IsWindowMinimized(window1.get()));
498
499  controller->StopCycling();
500
501  EXPECT_TRUE(wm::IsWindowMinimized(window1.get()));
502}
503
504// Tests cycles between panel and normal windows.
505TEST_F(WindowCycleControllerTest, CyclePanels) {
506  WindowCycleController* controller =
507      Shell::GetInstance()->window_cycle_controller();
508
509  scoped_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
510  scoped_ptr<aura::Window> panel0(CreatePanelWindow());
511  scoped_ptr<aura::Window> panel1(CreatePanelWindow());
512  wm::ActivateWindow(window0.get());
513  wm::ActivateWindow(panel1.get());
514  wm::ActivateWindow(panel0.get());
515  EXPECT_TRUE(wm::IsActiveWindow(panel0.get()));
516
517  controller->HandleCycleWindow(WindowCycleController::FORWARD);
518  controller->StopCycling();
519  EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
520
521  // Cycling again should select the most recently used panel.
522  controller->HandleCycleWindow(WindowCycleController::FORWARD);
523  controller->StopCycling();
524  EXPECT_TRUE(wm::IsActiveWindow(panel0.get()));
525
526  // Cycling twice again should select the first window.
527  controller->HandleCycleWindow(WindowCycleController::FORWARD);
528  controller->HandleCycleWindow(WindowCycleController::FORWARD);
529  controller->StopCycling();
530  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
531}
532
533// Tests cycles between panel and normal windows.
534TEST_F(WindowCycleControllerTest, CyclePanelsDestroyed) {
535  WindowCycleController* controller =
536      Shell::GetInstance()->window_cycle_controller();
537
538  scoped_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
539  scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
540  scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
541  scoped_ptr<aura::Window> panel0(CreatePanelWindow());
542  scoped_ptr<aura::Window> panel1(CreatePanelWindow());
543  wm::ActivateWindow(window2.get());
544  wm::ActivateWindow(panel1.get());
545  wm::ActivateWindow(panel0.get());
546  wm::ActivateWindow(window1.get());
547  wm::ActivateWindow(window0.get());
548  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
549
550  // Cycling once highlights window2.
551  controller->HandleCycleWindow(WindowCycleController::FORWARD);
552  // All panels are destroyed.
553  panel0.reset();
554  panel1.reset();
555  // Cycling again should now select window2.
556  controller->HandleCycleWindow(WindowCycleController::FORWARD);
557  controller->StopCycling();
558  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
559}
560
561// Tests cycles between panel and normal windows.
562TEST_F(WindowCycleControllerTest, CycleMruPanelDestroyed) {
563  WindowCycleController* controller =
564      Shell::GetInstance()->window_cycle_controller();
565
566  scoped_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
567  scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
568  scoped_ptr<aura::Window> panel0(CreatePanelWindow());
569  scoped_ptr<aura::Window> panel1(CreatePanelWindow());
570  wm::ActivateWindow(panel1.get());
571  wm::ActivateWindow(panel0.get());
572  wm::ActivateWindow(window1.get());
573  wm::ActivateWindow(window0.get());
574  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
575
576  // Cycling once highlights window2.
577  controller->HandleCycleWindow(WindowCycleController::FORWARD);
578
579  // Panel 1 is the next item as the MRU panel, removing it should make panel 2
580  // the next window to be selected.
581  panel0.reset();
582  // Cycling again should now select panel1.
583  controller->HandleCycleWindow(WindowCycleController::FORWARD);
584  controller->StopCycling();
585  EXPECT_TRUE(wm::IsActiveWindow(panel1.get()));
586}
587
588}  // namespace ash
589