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 #include <memory>
9
10 #include "ash/app_list/test/app_list_test_helper.h"
11 #include "ash/focus_cycler.h"
12 #include "ash/frame_throttler/frame_throttling_controller.h"
13 #include "ash/frame_throttler/mock_frame_throttling_observer.h"
14 #include "ash/home_screen/home_screen_controller.h"
15 #include "ash/public/cpp/ash_features.h"
16 #include "ash/public/cpp/shell_window_ids.h"
17 #include "ash/public/cpp/window_properties.h"
18 #include "ash/session/session_controller_impl.h"
19 #include "ash/session/test_session_controller_client.h"
20 #include "ash/shelf/shelf.h"
21 #include "ash/shelf/shelf_view_test_api.h"
22 #include "ash/shelf/shelf_widget.h"
23 #include "ash/shell.h"
24 #include "ash/test/ash_test_base.h"
25 #include "ash/test_shell_delegate.h"
26 #include "ash/wm/desks/desk.h"
27 #include "ash/wm/desks/desks_controller.h"
28 #include "ash/wm/desks/desks_test_util.h"
29 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
30 #include "ash/wm/window_cycle_list.h"
31 #include "ash/wm/window_state.h"
32 #include "ash/wm/window_util.h"
33 #include "ash/wm/wm_event.h"
34 #include "base/test/metrics/histogram_tester.h"
35 #include "base/test/scoped_feature_list.h"
36 #include "ui/aura/client/aura_constants.h"
37 #include "ui/aura/client/screen_position_client.h"
38 #include "ui/aura/env.h"
39 #include "ui/aura/test/test_windows.h"
40 #include "ui/aura/window.h"
41 #include "ui/aura/window_event_dispatcher.h"
42 #include "ui/display/display_layout_builder.h"
43 #include "ui/display/manager/display_layout_store.h"
44 #include "ui/display/manager/display_manager.h"
45 #include "ui/display/scoped_display_for_new_windows.h"
46 #include "ui/display/test/display_manager_test_api.h"
47 #include "ui/events/event_handler.h"
48 #include "ui/events/test/event_generator.h"
49 #include "ui/gfx/geometry/rect.h"
50
51 namespace ash {
52
53 namespace {
54
55 class EventCounter : public ui::EventHandler {
56 public:
EventCounter()57 EventCounter() : key_events_(0), mouse_events_(0) {}
58 ~EventCounter() override = default;
59
GetKeyEventCountAndReset()60 int GetKeyEventCountAndReset() {
61 int count = key_events_;
62 key_events_ = 0;
63 return count;
64 }
65
GetMouseEventCountAndReset()66 int GetMouseEventCountAndReset() {
67 int count = mouse_events_;
68 mouse_events_ = 0;
69 return count;
70 }
71
72 // ui::EventHandler:
OnKeyEvent(ui::KeyEvent * event)73 void OnKeyEvent(ui::KeyEvent* event) override { key_events_++; }
OnMouseEvent(ui::MouseEvent * event)74 void OnMouseEvent(ui::MouseEvent* event) override { mouse_events_++; }
75
76 private:
77 int key_events_;
78 int mouse_events_;
79
80 DISALLOW_COPY_AND_ASSIGN(EventCounter);
81 };
82
IsWindowMinimized(aura::Window * window)83 bool IsWindowMinimized(aura::Window* window) {
84 return WindowState::Get(window)->IsMinimized();
85 }
86
87 } // namespace
88
89 using aura::test::CreateTestWindowWithId;
90 using aura::test::TestWindowDelegate;
91 using aura::Window;
92
93 class WindowCycleControllerTest : public AshTestBase {
94 public:
95 WindowCycleControllerTest() = default;
96 ~WindowCycleControllerTest() override = default;
97
SetUp()98 void SetUp() override {
99 AshTestBase::SetUp();
100
101 WindowCycleList::DisableInitialDelayForTesting();
102
103 shelf_view_test_.reset(
104 new ShelfViewTestAPI(GetPrimaryShelf()->GetShelfViewForTesting()));
105 shelf_view_test_->SetAnimationDuration(
106 base::TimeDelta::FromMilliseconds(1));
107 }
108
GetWindows(WindowCycleController * controller)109 const aura::Window::Windows GetWindows(WindowCycleController* controller) {
110 return controller->window_cycle_list()->windows();
111 }
112
GetWindowCycleListWidget() const113 const views::Widget* GetWindowCycleListWidget() const {
114 return Shell::Get()
115 ->window_cycle_controller()
116 ->window_cycle_list()
117 ->widget();
118 }
119
GetWindowCycleItemViews() const120 const views::View::Views& GetWindowCycleItemViews() const {
121 return Shell::Get()
122 ->window_cycle_controller()
123 ->window_cycle_list()
124 ->GetWindowCycleItemViewsForTesting();
125 }
126
GetTargetWindow() const127 const aura::Window* GetTargetWindow() const {
128 return Shell::Get()
129 ->window_cycle_controller()
130 ->window_cycle_list()
131 ->GetTargetWindowForTesting();
132 }
133
CycleViewExists() const134 bool CycleViewExists() const {
135 return Shell::Get()
136 ->window_cycle_controller()
137 ->window_cycle_list()
138 ->cycle_view_for_testing();
139 }
140
GetCurrentIndex() const141 int GetCurrentIndex() const {
142 return Shell::Get()
143 ->window_cycle_controller()
144 ->window_cycle_list()
145 ->current_index_for_testing();
146 }
147
148 private:
149 std::unique_ptr<ShelfViewTestAPI> shelf_view_test_;
150
151 DISALLOW_COPY_AND_ASSIGN(WindowCycleControllerTest);
152 };
153
TEST_F(WindowCycleControllerTest,HandleCycleWindowBaseCases)154 TEST_F(WindowCycleControllerTest, HandleCycleWindowBaseCases) {
155 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
156
157 // Cycling doesn't crash if there are no windows.
158 controller->HandleCycleWindow(WindowCycleController::FORWARD);
159
160 // Create a single test window.
161 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
162 wm::ActivateWindow(window0.get());
163 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
164
165 // Cycling works for a single window, even though nothing changes.
166 controller->HandleCycleWindow(WindowCycleController::FORWARD);
167 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
168 }
169
170 // Verifies if there is only one window and it isn't active that cycling
171 // activates it.
TEST_F(WindowCycleControllerTest,SingleWindowNotActive)172 TEST_F(WindowCycleControllerTest, SingleWindowNotActive) {
173 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
174
175 // Create a single test window.
176 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
177 wm::ActivateWindow(window0.get());
178 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
179
180 // Rotate focus, this should move focus to another window that isn't part of
181 // the default container.
182 Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
183 EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
184
185 // Cycling should activate the window.
186 controller->HandleCycleWindow(WindowCycleController::FORWARD);
187 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
188 }
189
TEST_F(WindowCycleControllerTest,HandleCycleWindow)190 TEST_F(WindowCycleControllerTest, HandleCycleWindow) {
191 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
192
193 // Set up several windows to use to test cycling. Create them in reverse
194 // order so they are stacked 0 over 1 over 2.
195 std::unique_ptr<Window> window2(CreateTestWindowInShellWithId(2));
196 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
197 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
198 wm::ActivateWindow(window0.get());
199
200 // Simulate pressing and releasing Alt-tab.
201 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
202 controller->HandleCycleWindow(WindowCycleController::FORWARD);
203
204 // Window lists should return the topmost window in front.
205 ASSERT_TRUE(controller->window_cycle_list());
206 ASSERT_EQ(3u, GetWindows(controller).size());
207 ASSERT_EQ(window0.get(), GetWindows(controller)[0]);
208 ASSERT_EQ(window1.get(), GetWindows(controller)[1]);
209 ASSERT_EQ(window2.get(), GetWindows(controller)[2]);
210
211 controller->CompleteCycling();
212 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
213
214 // Pressing and releasing Alt-tab again should cycle back to the most-
215 // recently-used window in the current child order.
216 controller->HandleCycleWindow(WindowCycleController::FORWARD);
217 controller->CompleteCycling();
218 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
219
220 // Cancelled cycling shouldn't move the active window.
221 controller->HandleCycleWindow(WindowCycleController::FORWARD);
222 controller->CancelCycling();
223 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
224
225 // Pressing Alt-tab multiple times without releasing Alt should cycle through
226 // all the windows and wrap around.
227 controller->HandleCycleWindow(WindowCycleController::FORWARD);
228 EXPECT_TRUE(controller->IsCycling());
229
230 controller->HandleCycleWindow(WindowCycleController::FORWARD);
231 EXPECT_TRUE(controller->IsCycling());
232
233 controller->HandleCycleWindow(WindowCycleController::FORWARD);
234 EXPECT_TRUE(controller->IsCycling());
235
236 controller->CompleteCycling();
237 EXPECT_FALSE(controller->IsCycling());
238 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
239
240 // Reset our stacking order.
241 wm::ActivateWindow(window2.get());
242 wm::ActivateWindow(window1.get());
243 wm::ActivateWindow(window0.get());
244
245 // Likewise we can cycle backwards through the windows.
246 controller->HandleCycleWindow(WindowCycleController::BACKWARD);
247 controller->HandleCycleWindow(WindowCycleController::BACKWARD);
248 controller->CompleteCycling();
249 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
250
251 // Reset our stacking order.
252 wm::ActivateWindow(window2.get());
253 wm::ActivateWindow(window1.get());
254 wm::ActivateWindow(window0.get());
255
256 // When the screen is locked, cycling window does not take effect.
257 GetSessionControllerClient()->LockScreen();
258 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
259 controller->HandleCycleWindow(WindowCycleController::FORWARD);
260 EXPECT_FALSE(controller->IsCycling());
261
262 // Unlock, it works again.
263 GetSessionControllerClient()->UnlockScreen();
264 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
265 controller->HandleCycleWindow(WindowCycleController::FORWARD);
266 controller->HandleCycleWindow(WindowCycleController::FORWARD);
267 controller->CompleteCycling();
268 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
269
270 // When a modal window is active, cycling window does not take effect.
271 aura::Window* modal_container = Shell::GetContainer(
272 Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer);
273 std::unique_ptr<Window> modal_window(
274 CreateTestWindowWithId(-2, modal_container));
275 modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
276 wm::ActivateWindow(modal_window.get());
277 EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
278 controller->HandleCycleWindow(WindowCycleController::FORWARD);
279 EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
280 EXPECT_FALSE(controller->IsCycling());
281 EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
282 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
283 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
284 controller->HandleCycleWindow(WindowCycleController::BACKWARD);
285 EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
286 EXPECT_FALSE(controller->IsCycling());
287 EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
288 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
289 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
290
291 modal_window.reset();
292 std::unique_ptr<Window> skip_overview_window(
293 CreateTestWindowInShellWithId(-3));
294 skip_overview_window->SetProperty(kHideInOverviewKey, true);
295 wm::ActivateWindow(window0.get());
296 wm::ActivateWindow(skip_overview_window.get());
297 wm::ActivateWindow(window1.get());
298 EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
299 controller->HandleCycleWindow(WindowCycleController::FORWARD);
300 controller->CompleteCycling();
301 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
302 EXPECT_FALSE(wm::IsActiveWindow(skip_overview_window.get()));
303 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
304 }
305
TEST_F(WindowCycleControllerTest,Scroll)306 TEST_F(WindowCycleControllerTest, Scroll) {
307 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
308
309 // Doesn't crash if there are no windows.
310 controller->Scroll(WindowCycleController::FORWARD);
311
312 // Create test windows.
313 std::unique_ptr<Window> w5 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
314 std::unique_ptr<Window> w4 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
315 std::unique_ptr<Window> w3 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
316 std::unique_ptr<Window> w2 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
317 std::unique_ptr<Window> w1 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
318 std::unique_ptr<Window> w0 = CreateTestWindow(gfx::Rect(0, 0, 200, 200));
319
320 auto ScrollAndReturnCurrentIndex =
321 [this](WindowCycleController::Direction direction, int num_of_scrolls) {
322 WindowCycleController* controller =
323 Shell::Get()->window_cycle_controller();
324 for (int i = 0; i < num_of_scrolls; i++)
325 controller->Scroll(direction);
326
327 return GetCurrentIndex();
328 };
329
330 auto GetXOfCycleListCenterPoint = [this]() {
331 return GetWindowCycleListWidget()
332 ->GetWindowBoundsInScreen()
333 .CenterPoint()
334 .x();
335 };
336
337 auto GetXOfWindowCycleItemViewCenterPoint = [this](int index) {
338 return GetWindowCycleItemViews()[index]
339 ->GetBoundsInScreen()
340 .CenterPoint()
341 .x();
342 };
343
344 // Start cycling and scroll forward. The list should be not be centered around
345 // w1. Since w1 is so close to the beginning of the list.
346 controller->StartCycling();
347 int current_index =
348 ScrollAndReturnCurrentIndex(WindowCycleController::FORWARD, 1);
349 EXPECT_EQ(1, current_index);
350 EXPECT_GT(GetXOfCycleListCenterPoint(),
351 GetXOfWindowCycleItemViewCenterPoint(current_index));
352
353 // Scroll forward twice. The list should be centered around w3.
354 current_index =
355 ScrollAndReturnCurrentIndex(WindowCycleController::FORWARD, 2);
356 EXPECT_EQ(3, current_index);
357 EXPECT_EQ(GetXOfCycleListCenterPoint(),
358 GetXOfWindowCycleItemViewCenterPoint(current_index));
359
360 // Scroll backward once. The list should be centered around w2.
361 current_index =
362 ScrollAndReturnCurrentIndex(WindowCycleController::BACKWARD, 1);
363 EXPECT_EQ(2, current_index);
364 EXPECT_EQ(GetXOfCycleListCenterPoint(),
365 GetXOfWindowCycleItemViewCenterPoint(current_index));
366
367 // Scroll backward three times. The list should not be centered around w5.
368 current_index =
369 ScrollAndReturnCurrentIndex(WindowCycleController::BACKWARD, 3);
370 EXPECT_EQ(5, current_index);
371 EXPECT_LT(GetXOfCycleListCenterPoint(),
372 GetXOfWindowCycleItemViewCenterPoint(current_index));
373
374 // Cycle forward. Since the target window != current window, it should scroll
375 // to target window then cycle. The target_window was w0 prior to cycling.
376 controller->HandleCycleWindow(WindowCycleController::FORWARD);
377 current_index = GetCurrentIndex();
378 EXPECT_EQ(1, current_index);
379 EXPECT_GT(GetXOfCycleListCenterPoint(),
380 GetXOfWindowCycleItemViewCenterPoint(current_index));
381 controller->CompleteCycling();
382 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
383
384 // Start cycling, scroll backward once and complete cycling. Scroll should not
385 // affect the selected window.
386 controller->StartCycling();
387 current_index =
388 ScrollAndReturnCurrentIndex(WindowCycleController::BACKWARD, 1);
389 EXPECT_EQ(5, current_index);
390 controller->CompleteCycling();
391 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
392 }
393
394 // Cycles between a maximized and normal window.
TEST_F(WindowCycleControllerTest,MaximizedWindow)395 TEST_F(WindowCycleControllerTest, MaximizedWindow) {
396 // Create a couple of test windows.
397 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
398 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
399 WindowState* window1_state = WindowState::Get(window1.get());
400 window1_state->Maximize();
401 window1_state->Activate();
402 EXPECT_TRUE(window1_state->IsActive());
403
404 // Rotate focus, this should move focus to window0.
405 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
406 controller->HandleCycleWindow(WindowCycleController::FORWARD);
407 controller->CompleteCycling();
408 EXPECT_TRUE(WindowState::Get(window0.get())->IsActive());
409 EXPECT_FALSE(window1_state->IsActive());
410
411 // One more time.
412 controller->HandleCycleWindow(WindowCycleController::FORWARD);
413 controller->CompleteCycling();
414 EXPECT_TRUE(window1_state->IsActive());
415 }
416
417 // Cycles to a minimized window.
TEST_F(WindowCycleControllerTest,Minimized)418 TEST_F(WindowCycleControllerTest, Minimized) {
419 // Create a couple of test windows.
420 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
421 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
422 WindowState* window0_state = WindowState::Get(window0.get());
423 WindowState* window1_state = WindowState::Get(window1.get());
424
425 window1_state->Minimize();
426 window0_state->Activate();
427 EXPECT_TRUE(window0_state->IsActive());
428
429 // Rotate focus, this should move focus to window1 and unminimize it.
430 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
431 controller->HandleCycleWindow(WindowCycleController::FORWARD);
432 controller->CompleteCycling();
433 EXPECT_FALSE(window0_state->IsActive());
434 EXPECT_FALSE(window1_state->IsMinimized());
435 EXPECT_TRUE(window1_state->IsActive());
436
437 // One more time back to w0.
438 controller->HandleCycleWindow(WindowCycleController::FORWARD);
439 controller->CompleteCycling();
440 EXPECT_TRUE(window0_state->IsActive());
441 }
442
443 // Tests that when all windows are minimized, cycling starts with the first one
444 // rather than the second.
TEST_F(WindowCycleControllerTest,AllAreMinimized)445 TEST_F(WindowCycleControllerTest, AllAreMinimized) {
446 // Create a couple of test windows.
447 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
448 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
449 WindowState* window0_state = WindowState::Get(window0.get());
450 WindowState* window1_state = WindowState::Get(window1.get());
451
452 window0_state->Minimize();
453 window1_state->Minimize();
454
455 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
456 controller->HandleCycleWindow(WindowCycleController::FORWARD);
457 controller->CompleteCycling();
458 EXPECT_TRUE(window0_state->IsActive());
459 EXPECT_FALSE(window0_state->IsMinimized());
460 EXPECT_TRUE(window1_state->IsMinimized());
461
462 // But it's business as usual when cycling backwards.
463 window0_state->Minimize();
464 window1_state->Minimize();
465 controller->HandleCycleWindow(WindowCycleController::BACKWARD);
466 controller->CompleteCycling();
467 EXPECT_TRUE(window0_state->IsMinimized());
468 EXPECT_TRUE(window1_state->IsActive());
469 EXPECT_FALSE(window1_state->IsMinimized());
470 }
471
TEST_F(WindowCycleControllerTest,AlwaysOnTopWindow)472 TEST_F(WindowCycleControllerTest, AlwaysOnTopWindow) {
473 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
474
475 // Set up several windows to use to test cycling.
476 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
477 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
478
479 Window* top_container = Shell::GetContainer(
480 Shell::GetPrimaryRootWindow(), kShellWindowId_AlwaysOnTopContainer);
481 std::unique_ptr<Window> window2(CreateTestWindowWithId(2, top_container));
482 wm::ActivateWindow(window0.get());
483
484 // Simulate pressing and releasing Alt-tab.
485 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
486 controller->HandleCycleWindow(WindowCycleController::FORWARD);
487
488 // Window lists should return the topmost window in front.
489 ASSERT_TRUE(controller->window_cycle_list());
490 ASSERT_EQ(3u, GetWindows(controller).size());
491 EXPECT_EQ(window0.get(), GetWindows(controller)[0]);
492 EXPECT_EQ(window2.get(), GetWindows(controller)[1]);
493 EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
494
495 controller->CompleteCycling();
496 }
497
TEST_F(WindowCycleControllerTest,AlwaysOnTopMultiWindow)498 TEST_F(WindowCycleControllerTest, AlwaysOnTopMultiWindow) {
499 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
500
501 // Set up several windows to use to test cycling.
502 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
503 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
504
505 Window* top_container = Shell::GetContainer(
506 Shell::GetPrimaryRootWindow(), kShellWindowId_AlwaysOnTopContainer);
507 std::unique_ptr<Window> window2(CreateTestWindowWithId(2, top_container));
508 std::unique_ptr<Window> window3(CreateTestWindowWithId(3, top_container));
509 wm::ActivateWindow(window0.get());
510
511 // Simulate pressing and releasing Alt-tab.
512 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
513 controller->HandleCycleWindow(WindowCycleController::FORWARD);
514
515 // Window lists should return the topmost window in front.
516 ASSERT_TRUE(controller->window_cycle_list());
517 ASSERT_EQ(4u, GetWindows(controller).size());
518 EXPECT_EQ(window0.get(), GetWindows(controller)[0]);
519 EXPECT_EQ(window3.get(), GetWindows(controller)[1]);
520 EXPECT_EQ(window2.get(), GetWindows(controller)[2]);
521 EXPECT_EQ(window1.get(), GetWindows(controller)[3]);
522
523 controller->CompleteCycling();
524 }
525
TEST_F(WindowCycleControllerTest,AlwaysOnTopMultipleRootWindows)526 TEST_F(WindowCycleControllerTest, AlwaysOnTopMultipleRootWindows) {
527 // Set up a second root window
528 UpdateDisplay("1000x600,600x400");
529 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
530 ASSERT_EQ(2U, root_windows.size());
531
532 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
533
534 // Create two windows in the primary root.
535 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
536 EXPECT_EQ(root_windows[0], window0->GetRootWindow());
537 Window* top_container0 =
538 Shell::GetContainer(root_windows[0], kShellWindowId_AlwaysOnTopContainer);
539 std::unique_ptr<Window> window1(CreateTestWindowWithId(1, top_container0));
540 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
541
542 // Move the active root window to the secondary root and create two windows.
543 display::ScopedDisplayForNewWindows display_for_new_windows(root_windows[1]);
544 std::unique_ptr<Window> window2(CreateTestWindowInShellWithId(2));
545 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
546
547 Window* top_container1 =
548 Shell::GetContainer(root_windows[1], kShellWindowId_AlwaysOnTopContainer);
549 std::unique_ptr<Window> window3(CreateTestWindowWithId(3, top_container1));
550 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
551
552 wm::ActivateWindow(window2.get());
553
554 EXPECT_EQ(root_windows[0], window0->GetRootWindow());
555 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
556 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
557 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
558
559 // Simulate pressing and releasing Alt-tab.
560 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
561 controller->HandleCycleWindow(WindowCycleController::FORWARD);
562
563 // Window lists should return the topmost window in front.
564 ASSERT_TRUE(controller->window_cycle_list());
565 ASSERT_EQ(4u, GetWindows(controller).size());
566 EXPECT_EQ(window2.get(), GetWindows(controller)[0]);
567 EXPECT_EQ(window3.get(), GetWindows(controller)[1]);
568 EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
569 EXPECT_EQ(window0.get(), GetWindows(controller)[3]);
570
571 controller->CompleteCycling();
572 }
573
TEST_F(WindowCycleControllerTest,MostRecentlyUsed)574 TEST_F(WindowCycleControllerTest, MostRecentlyUsed) {
575 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
576
577 // Set up several windows to use to test cycling.
578 std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
579 std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
580 std::unique_ptr<Window> window2(CreateTestWindowInShellWithId(2));
581
582 wm::ActivateWindow(window0.get());
583
584 // Simulate pressing and releasing Alt-tab.
585 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
586 controller->HandleCycleWindow(WindowCycleController::FORWARD);
587
588 // Window lists should return the topmost window in front.
589 ASSERT_TRUE(controller->window_cycle_list());
590 ASSERT_EQ(3u, GetWindows(controller).size());
591 EXPECT_EQ(window0.get(), GetWindows(controller)[0]);
592 EXPECT_EQ(window2.get(), GetWindows(controller)[1]);
593 EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
594
595 // Cycling through then stopping the cycling will activate a window.
596 controller->HandleCycleWindow(WindowCycleController::FORWARD);
597 controller->CompleteCycling();
598 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
599
600 // Cycling alone (without CompleteCycling()) doesn't activate.
601 controller->HandleCycleWindow(WindowCycleController::FORWARD);
602 EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
603
604 controller->CompleteCycling();
605 }
606
607 // Tests that beginning window selection hides the app list.
TEST_F(WindowCycleControllerTest,SelectingHidesAppList)608 TEST_F(WindowCycleControllerTest, SelectingHidesAppList) {
609 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
610
611 std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
612 std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
613 wm::ActivateWindow(window0.get());
614
615 GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplay().id());
616 GetAppListTestHelper()->CheckVisibility(true);
617 controller->HandleCycleWindow(WindowCycleController::FORWARD);
618 GetAppListTestHelper()->WaitUntilIdle();
619 GetAppListTestHelper()->CheckVisibility(false);
620
621 // Make sure that dismissing the app list this way doesn't pass activation
622 // to a different window.
623 EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
624 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
625
626 controller->CompleteCycling();
627 }
628
629 // Tests that beginning window selection doesn't hide the app list in tablet
630 // mode.
TEST_F(WindowCycleControllerTest,SelectingDoesNotHideAppListInTabletMode)631 TEST_F(WindowCycleControllerTest, SelectingDoesNotHideAppListInTabletMode) {
632 TabletModeControllerTestApi().EnterTabletMode();
633 EXPECT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
634 EXPECT_TRUE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
635
636 std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
637 std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
638 wm::ActivateWindow(window0.get());
639
640 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
641 controller->HandleCycleWindow(WindowCycleController::FORWARD);
642
643 window0->Hide();
644 window1->Hide();
645 EXPECT_TRUE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
646 }
647
648 // Tests that cycling through windows doesn't change their minimized state.
TEST_F(WindowCycleControllerTest,CyclePreservesMinimization)649 TEST_F(WindowCycleControllerTest, CyclePreservesMinimization) {
650 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
651
652 std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
653 std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
654 wm::ActivateWindow(window1.get());
655 WindowState::Get(window1.get())->Minimize();
656 wm::ActivateWindow(window0.get());
657 EXPECT_TRUE(IsWindowMinimized(window1.get()));
658
659 // On window 2.
660 controller->HandleCycleWindow(WindowCycleController::FORWARD);
661 EXPECT_TRUE(IsWindowMinimized(window1.get()));
662
663 // Back on window 1.
664 controller->HandleCycleWindow(WindowCycleController::FORWARD);
665 EXPECT_TRUE(IsWindowMinimized(window1.get()));
666
667 controller->CompleteCycling();
668
669 EXPECT_TRUE(IsWindowMinimized(window1.get()));
670 }
671
672 // Tests that the tab key events are not sent to the window.
TEST_F(WindowCycleControllerTest,TabKeyNotLeaked)673 TEST_F(WindowCycleControllerTest, TabKeyNotLeaked) {
674 std::unique_ptr<Window> w0(CreateTestWindowInShellWithId(0));
675 std::unique_ptr<Window> w1(CreateTestWindowInShellWithId(1));
676 EventCounter event_count;
677 w0->AddPreTargetHandler(&event_count);
678 w1->AddPreTargetHandler(&event_count);
679 ui::test::EventGenerator* generator = GetEventGenerator();
680 WindowState::Get(w0.get())->Activate();
681 generator->PressKey(ui::VKEY_MENU, ui::EF_NONE);
682 EXPECT_EQ(1, event_count.GetKeyEventCountAndReset());
683 generator->PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
684 EXPECT_EQ(0, event_count.GetKeyEventCountAndReset());
685 generator->ReleaseKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
686 EXPECT_EQ(0, event_count.GetKeyEventCountAndReset());
687 generator->ReleaseKey(ui::VKEY_MENU, ui::EF_NONE);
688 EXPECT_TRUE(WindowState::Get(w1.get())->IsActive());
689 EXPECT_EQ(0, event_count.GetKeyEventCountAndReset());
690 }
691
692 // While the UI is active, mouse events are captured.
TEST_F(WindowCycleControllerTest,MouseEventsCaptured)693 TEST_F(WindowCycleControllerTest, MouseEventsCaptured) {
694 if (features::IsInteractiveWindowCycleListEnabled())
695 return;
696
697 // Set up a second root window
698 UpdateDisplay("1000x600,600x400");
699 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
700 ASSERT_EQ(2U, root_windows.size());
701
702 // This delegate allows the window to receive mouse events.
703 aura::test::TestWindowDelegate delegate;
704 std::unique_ptr<Window> w0(CreateTestWindowInShellWithDelegate(
705 &delegate, 0, gfx::Rect(0, 0, 100, 100)));
706 std::unique_ptr<Window> w1(CreateTestWindowInShellWithId(1));
707 EventCounter event_count;
708 w0->AddPreTargetHandler(&event_count);
709 w1->SetTargetHandler(&event_count);
710 ui::test::EventGenerator* generator = GetEventGenerator();
711 wm::ActivateWindow(w0.get());
712
713 // Events get through while not cycling.
714 generator->MoveMouseToCenterOf(w0.get());
715 generator->ClickLeftButton();
716 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
717
718 // Start cycling.
719 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
720 controller->HandleCycleWindow(WindowCycleController::FORWARD);
721
722 // Mouse events not over the cycle view don't get through.
723 generator->PressLeftButton();
724 EXPECT_EQ(0, event_count.GetMouseEventCountAndReset());
725
726 // Although releases do, regardless of mouse position.
727 generator->ReleaseLeftButton();
728 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
729
730 // Stop cycling: once again, events get through.
731 controller->CompleteCycling();
732 generator->ClickLeftButton();
733 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
734
735 // Click somewhere on the second root window.
736 generator->MoveMouseToCenterOf(root_windows[1]);
737 generator->ClickLeftButton();
738 EXPECT_EQ(0, event_count.GetMouseEventCountAndReset());
739 }
740
741 // Tests that we can cycle past fullscreen windows: https://crbug.com/622396.
742 // Fullscreen windows are special in that they are allowed to handle alt+tab
743 // keypresses, which means the window cycle event filter should not handle
744 // the tab press else it prevents cycling past that window.
TEST_F(WindowCycleControllerTest,TabPastFullscreenWindow)745 TEST_F(WindowCycleControllerTest, TabPastFullscreenWindow) {
746 std::unique_ptr<Window> w0(CreateTestWindowInShellWithId(0));
747 std::unique_ptr<Window> w1(CreateTestWindowInShellWithId(1));
748 WMEvent maximize_event(WM_EVENT_FULLSCREEN);
749
750 // To make this test work with or without the new alt+tab selector we make
751 // both the initial window and the second window fullscreen.
752 WindowState::Get(w0.get())->OnWMEvent(&maximize_event);
753 WindowState::Get(w1.get())->Activate();
754 WindowState::Get(w1.get())->OnWMEvent(&maximize_event);
755 EXPECT_TRUE(WindowState::Get(w0.get())->IsFullscreen());
756 EXPECT_TRUE(WindowState::Get(w1.get())->IsFullscreen());
757 WindowState::Get(w0.get())->Activate();
758 EXPECT_TRUE(WindowState::Get(w0.get())->IsActive());
759
760 ui::test::EventGenerator* generator = GetEventGenerator();
761 generator->PressKey(ui::VKEY_MENU, ui::EF_NONE);
762
763 generator->PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
764 generator->ReleaseKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
765
766 // Because w0 and w1 are full-screen, the event should be passed to the
767 // browser window to handle it (which if the browser doesn't handle it will
768 // pass on the alt+tab to continue cycling). To make this test work with or
769 // without the new alt+tab selector we check for the event on either
770 // fullscreen window.
771 EventCounter event_count;
772 w0->AddPreTargetHandler(&event_count);
773 w1->AddPreTargetHandler(&event_count);
774 generator->PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
775 EXPECT_EQ(1, event_count.GetKeyEventCountAndReset());
776 }
777
778 // Tests that the Alt+Tab UI's position isn't affected by the origin of the
779 // display it's on. See crbug.com/675718
TEST_F(WindowCycleControllerTest,MultiDisplayPositioning)780 TEST_F(WindowCycleControllerTest, MultiDisplayPositioning) {
781 int64_t primary_id = GetPrimaryDisplay().id();
782 display::DisplayIdList list =
783 display::test::CreateDisplayIdListN(primary_id, 2);
784
785 auto placements = {
786 display::DisplayPlacement::BOTTOM, display::DisplayPlacement::TOP,
787 display::DisplayPlacement::LEFT, display::DisplayPlacement::RIGHT,
788 };
789
790 gfx::Rect expected_bounds;
791 for (auto placement : placements) {
792 SCOPED_TRACE(placement);
793
794 display::DisplayLayoutBuilder builder(primary_id);
795 builder.AddDisplayPlacement(list[1], primary_id, placement, 0);
796 display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
797 list, builder.Build());
798
799 // Use two displays.
800 UpdateDisplay("500x500,600x600");
801
802 gfx::Rect second_display_bounds =
803 display_manager()->GetDisplayAt(1).bounds();
804 std::unique_ptr<Window> window0(
805 CreateTestWindowInShellWithBounds(second_display_bounds));
806 // Activate this window so that the secondary display becomes the one where
807 // the Alt+Tab UI is shown.
808 wm::ActivateWindow(window0.get());
809 std::unique_ptr<Window> window1(
810 CreateTestWindowInShellWithBounds(second_display_bounds));
811
812 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
813 controller->HandleCycleWindow(WindowCycleController::FORWARD);
814
815 const gfx::Rect bounds =
816 GetWindowCycleListWidget()->GetWindowBoundsInScreen();
817 EXPECT_TRUE(second_display_bounds.Contains(bounds));
818 EXPECT_FALSE(
819 display_manager()->GetDisplayAt(0).bounds().Intersects(bounds));
820 const gfx::Rect display_relative_bounds =
821 bounds - second_display_bounds.OffsetFromOrigin();
822 // Base case sets the expectation for other cases.
823 if (expected_bounds.IsEmpty())
824 expected_bounds = display_relative_bounds;
825 else
826 EXPECT_EQ(expected_bounds, display_relative_bounds);
827 controller->CompleteCycling();
828 }
829 }
830
TEST_F(WindowCycleControllerTest,CycleShowsAllDesksWindows)831 TEST_F(WindowCycleControllerTest, CycleShowsAllDesksWindows) {
832 auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
833 auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
834 auto* desks_controller = DesksController::Get();
835 desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
836 desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
837 ASSERT_EQ(3u, desks_controller->desks().size());
838 const Desk* desk_2 = desks_controller->desks()[1].get();
839 ActivateDesk(desk_2);
840 EXPECT_EQ(desk_2, desks_controller->active_desk());
841 auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
842 const Desk* desk_3 = desks_controller->desks()[2].get();
843 ActivateDesk(desk_3);
844 EXPECT_EQ(desk_3, desks_controller->active_desk());
845 auto win3 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
846
847 WindowCycleController* cycle_controller =
848 Shell::Get()->window_cycle_controller();
849 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
850 // All desks' windows are included in the cycle list.
851 auto cycle_windows = GetWindows(cycle_controller);
852 EXPECT_EQ(4u, cycle_windows.size());
853 EXPECT_TRUE(base::Contains(cycle_windows, win0.get()));
854 EXPECT_TRUE(base::Contains(cycle_windows, win1.get()));
855 EXPECT_TRUE(base::Contains(cycle_windows, win2.get()));
856 EXPECT_TRUE(base::Contains(cycle_windows, win3.get()));
857
858 // The MRU order is {win3, win2, win1, win0}. We're now at win2. Cycling one
859 // more time and completing the cycle, will activate win1 which exists on a
860 // desk_1. This should activate desk_1.
861 {
862 base::HistogramTester histogram_tester;
863 DeskSwitchAnimationWaiter waiter;
864 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
865 cycle_controller->CompleteCycling();
866 waiter.Wait();
867 Desk* desk_1 = desks_controller->desks()[0].get();
868 EXPECT_EQ(desk_1, desks_controller->active_desk());
869 EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
870 histogram_tester.ExpectUniqueSample(
871 "Ash.WindowCycleController.DesksSwitchDistance",
872 /*desk distance of 3 - 1 = */ 2, /*expected_count=*/1);
873 }
874
875 // Cycle again and activate win2, which exist on desk_2. Expect that desk to
876 // be activated, and a histogram sample of distance of 1 is recorded.
877 // MRU is {win1, win3, win2, win0}.
878 {
879 base::HistogramTester histogram_tester;
880 DeskSwitchAnimationWaiter waiter;
881 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
882 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
883 cycle_controller->CompleteCycling();
884 waiter.Wait();
885 EXPECT_EQ(desk_2, desks_controller->active_desk());
886 EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
887 histogram_tester.ExpectUniqueSample(
888 "Ash.WindowCycleController.DesksSwitchDistance",
889 /*desk distance of 2 - 1 = */ 1, /*expected_count=*/1);
890 }
891 }
892
893 class LimitedWindowCycleControllerTest : public WindowCycleControllerTest {
894 public:
895 LimitedWindowCycleControllerTest() = default;
896 LimitedWindowCycleControllerTest(const LimitedWindowCycleControllerTest&) =
897 delete;
898 LimitedWindowCycleControllerTest& operator=(
899 const LimitedWindowCycleControllerTest&) = delete;
900 ~LimitedWindowCycleControllerTest() override = default;
901
902 // WindowCycleControllerTest:
SetUp()903 void SetUp() override {
904 scoped_feature_list_.InitAndEnableFeature(
905 features::kLimitAltTabToActiveDesk);
906 WindowCycleControllerTest::SetUp();
907 }
908
909 private:
910 base::test::ScopedFeatureList scoped_feature_list_;
911 };
912
TEST_F(LimitedWindowCycleControllerTest,CycleShowsActiveDeskWindows)913 TEST_F(LimitedWindowCycleControllerTest, CycleShowsActiveDeskWindows) {
914 auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
915 auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
916 auto* desks_controller = DesksController::Get();
917 desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
918 desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
919 ASSERT_EQ(3u, desks_controller->desks().size());
920 const Desk* desk_2 = desks_controller->desks()[1].get();
921 ActivateDesk(desk_2);
922 EXPECT_EQ(desk_2, desks_controller->active_desk());
923 auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
924 const Desk* desk_3 = desks_controller->desks()[2].get();
925 ActivateDesk(desk_3);
926 EXPECT_EQ(desk_3, desks_controller->active_desk());
927 auto win3 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
928
929 WindowCycleController* cycle_controller =
930 Shell::Get()->window_cycle_controller();
931
932 // Should contain only windows from |desk_3|.
933 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
934 auto cycle_windows = GetWindows(cycle_controller);
935 EXPECT_EQ(1u, cycle_windows.size());
936 EXPECT_TRUE(base::Contains(cycle_windows, win3.get()));
937 cycle_controller->CompleteCycling();
938 EXPECT_EQ(win3.get(), window_util::GetActiveWindow());
939
940 // Should contain only windows from |desk_2|.
941 ActivateDesk(desk_2);
942 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
943 cycle_windows = GetWindows(cycle_controller);
944 EXPECT_EQ(1u, cycle_windows.size());
945 EXPECT_TRUE(base::Contains(cycle_windows, win2.get()));
946 cycle_controller->CompleteCycling();
947 EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
948
949 // Should contain only windows from |desk_1|.
950 const Desk* desk_1 = desks_controller->desks()[0].get();
951 ActivateDesk(desk_1);
952 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
953 cycle_windows = GetWindows(cycle_controller);
954 EXPECT_EQ(2u, cycle_windows.size());
955 EXPECT_TRUE(base::Contains(cycle_windows, win0.get()));
956 EXPECT_TRUE(base::Contains(cycle_windows, win1.get()));
957 cycle_controller->CompleteCycling();
958 EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
959
960 // Swap desks while cycling, contents should update.
961 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
962 cycle_windows = GetWindows(cycle_controller);
963 EXPECT_EQ(2u, cycle_windows.size());
964 EXPECT_TRUE(base::Contains(cycle_windows, win0.get()));
965 EXPECT_TRUE(base::Contains(cycle_windows, win1.get()));
966 ActivateDesk(desk_2);
967 EXPECT_TRUE(cycle_controller->IsCycling());
968 cycle_windows = GetWindows(cycle_controller);
969 EXPECT_EQ(1u, cycle_windows.size());
970 EXPECT_TRUE(base::Contains(cycle_windows, win2.get()));
971 cycle_controller->CompleteCycling();
972 EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
973 }
974
975 class InteractiveWindowCycleControllerTest : public WindowCycleControllerTest {
976 public:
977 InteractiveWindowCycleControllerTest() = default;
978 InteractiveWindowCycleControllerTest(const InteractiveWindowCycleControllerTest&) =
979 delete;
980 InteractiveWindowCycleControllerTest& operator=(
981 const InteractiveWindowCycleControllerTest&) = delete;
982 ~InteractiveWindowCycleControllerTest() override = default;
983
984 // WindowCycleControllerTest:
SetUp()985 void SetUp() override {
986 scoped_feature_list_.InitAndEnableFeature(
987 features::kInteractiveWindowCycleList);
988 WindowCycleControllerTest::SetUp();
989 }
990
991 private:
992 base::test::ScopedFeatureList scoped_feature_list_;
993 };
994
995 // Tests that when the cycle view is not open, the event filter does not check
996 // whether events occur within the cycle view.
997 // TODO(chinsenj): Add this to WindowCycleControllerTest.MouseEventsCaptured
998 // after feature launch.
TEST_F(InteractiveWindowCycleControllerTest,MouseEventWhenCycleViewDoesNotExist)999 TEST_F(InteractiveWindowCycleControllerTest,
1000 MouseEventWhenCycleViewDoesNotExist) {
1001 aura::test::TestWindowDelegate delegate;
1002 std::unique_ptr<Window> w0(CreateTestWindowInShellWithDelegate(
1003 &delegate, 0, gfx::Rect(0, 0, 100, 100)));
1004 EventCounter event_count;
1005 w0->AddPreTargetHandler(&event_count);
1006 ui::test::EventGenerator* generator = GetEventGenerator();
1007 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1008
1009 // Mouse events get through if the cycle view is not open.
1010 // Cycling with one window open ensures the UI doesn't show but the event
1011 // filter is.
1012 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1013 generator->MoveMouseToCenterOf(w0.get());
1014 generator->ClickLeftButton();
1015 EXPECT_TRUE(controller->IsCycling());
1016 EXPECT_FALSE(CycleViewExists());
1017 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
1018 controller->CompleteCycling();
1019 }
1020
1021 // When a user hovers their mouse over an item, it should cycle to it.
1022 // The items in the list should not move, only the focus ring.
1023 // If a user clicks on an item, it should complete cycling and activate
1024 // the hovered item.
TEST_F(InteractiveWindowCycleControllerTest,MouseHoverAndSelect)1025 TEST_F(InteractiveWindowCycleControllerTest, MouseHoverAndSelect) {
1026 std::unique_ptr<Window> w0 = CreateTestWindow();
1027 std::unique_ptr<Window> w1 = CreateTestWindow();
1028 std::unique_ptr<Window> w2 = CreateTestWindow();
1029 std::unique_ptr<Window> w3 = CreateTestWindow();
1030 std::unique_ptr<Window> w4 = CreateTestWindow();
1031 std::unique_ptr<Window> w5 = CreateTestWindow();
1032 std::unique_ptr<Window> w6 = CreateTestWindow();
1033 ui::test::EventGenerator* generator = GetEventGenerator();
1034 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1035
1036 // Cycle to the third item, mouse over second item, and release alt-tab.
1037 // Starting order of windows in cycle list is [6,5,4,3,2,1,0].
1038 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1039 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1040 gfx::Point target_item_center =
1041 GetWindowCycleItemViews()[1]->GetBoundsInScreen().CenterPoint();
1042 generator->MoveMouseTo(target_item_center);
1043 EXPECT_EQ(target_item_center,
1044 GetWindowCycleItemViews()[1]->GetBoundsInScreen().CenterPoint());
1045 controller->CompleteCycling();
1046 EXPECT_TRUE(wm::IsActiveWindow(w5.get()));
1047
1048 // Start cycle, mouse over third item, and release alt-tab.
1049 // Starting order of windows in cycle list is [5,6,4,3,2,1,0].
1050 controller->StartCycling();
1051 target_item_center =
1052 GetWindowCycleItemViews()[2]->GetBoundsInScreen().CenterPoint();
1053 generator->MoveMouseTo(target_item_center);
1054 EXPECT_EQ(target_item_center,
1055 GetWindowCycleItemViews()[2]->GetBoundsInScreen().CenterPoint());
1056 controller->CompleteCycling();
1057 EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
1058
1059 // Start cycle, cycle to the fifth item, mouse over seventh item, and click.
1060 // Starting order of windows in cycle list is [4,5,6,3,2,1,0].
1061 controller->StartCycling();
1062 for (int i = 0; i < 5; i++)
1063 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1064 target_item_center =
1065 GetWindowCycleItemViews()[6]->GetBoundsInScreen().CenterPoint();
1066 generator->MoveMouseTo(target_item_center);
1067 EXPECT_EQ(target_item_center,
1068 GetWindowCycleItemViews()[6]->GetBoundsInScreen().CenterPoint());
1069 generator->PressLeftButton();
1070 EXPECT_TRUE(wm::IsActiveWindow(w0.get()));
1071 }
1072
1073 // Tests that the left and right keys cycle after the cycle list has been
1074 // initialized.
TEST_F(InteractiveWindowCycleControllerTest,LeftRightCycle)1075 TEST_F(InteractiveWindowCycleControllerTest, LeftRightCycle) {
1076 std::unique_ptr<Window> w0 = CreateTestWindow();
1077 std::unique_ptr<Window> w1 = CreateTestWindow();
1078 std::unique_ptr<Window> w2 = CreateTestWindow();
1079 ui::test::EventGenerator* generator = GetEventGenerator();
1080 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1081
1082 // Start cycle, simulating alt button being held down. Cycle right to the
1083 // third item.
1084 // Starting order of windows in cycle list is [2,1,0].
1085 controller->StartCycling();
1086 generator->PressKey(ui::VKEY_RIGHT, ui::EF_NONE);
1087 generator->PressKey(ui::VKEY_RIGHT, ui::EF_NONE);
1088 controller->CompleteCycling();
1089 EXPECT_TRUE(wm::IsActiveWindow(w0.get()));
1090
1091 // Start cycle. Cycle right once, then left two times.
1092 // Starting order of windows in cycle list is [0,2,1].
1093 controller->StartCycling();
1094 generator->PressKey(ui::VKEY_RIGHT, ui::EF_NONE);
1095 generator->PressKey(ui::VKEY_LEFT, ui::EF_NONE);
1096 generator->PressKey(ui::VKEY_LEFT, ui::EF_NONE);
1097 controller->CompleteCycling();
1098 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
1099
1100 // Start cycle. Cycle right once, then left once, then right once.
1101 // Starting order of windows in cycle list is [0,2,1].
1102 controller->StartCycling();
1103 generator->PressKey(ui::VKEY_LEFT, ui::EF_ALT_DOWN);
1104 generator->PressKey(ui::VKEY_RIGHT, ui::EF_ALT_DOWN);
1105 generator->PressKey(ui::VKEY_LEFT, ui::EF_ALT_DOWN);
1106 controller->CompleteCycling();
1107 EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
1108 }
1109
1110 // Tests that pressing the space key, pressing the enter key, or releasing the
1111 // alt key during window cycle confirms a selection.
TEST_F(InteractiveWindowCycleControllerTest,KeysConfirmSelection)1112 TEST_F(InteractiveWindowCycleControllerTest, KeysConfirmSelection) {
1113 std::unique_ptr<Window> w0 = CreateTestWindow();
1114 std::unique_ptr<Window> w1 = CreateTestWindow();
1115 std::unique_ptr<Window> w2 = CreateTestWindow();
1116 ui::test::EventGenerator* generator = GetEventGenerator();
1117 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1118
1119 // Start cycle, simulating alt button being held down. Cycle right once and
1120 // complete cycle using space.
1121 // Starting order of windows in cycle list is [2,1,0].
1122 controller->StartCycling();
1123 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1124 generator->PressKey(ui::VKEY_SPACE, ui::EF_NONE);
1125 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
1126
1127 // Start cycle, simulating alt button being held down. Cycle right once and
1128 // complete cycle using enter.
1129 // Starting order of windows in cycle list is [1,2,0].
1130 controller->StartCycling();
1131 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1132 generator->PressKey(ui::VKEY_RETURN, ui::EF_NONE);
1133 EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
1134
1135 // Start cycle, simulating alt button being held down. Cycle right once and
1136 // complete cycle by releasing alt key (Views uses VKEY_MENU for both left and
1137 // right alt keys).
1138 // Starting order of windows in cycle list is [2,1,0].
1139 controller->StartCycling();
1140 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1141 generator->ReleaseKey(ui::VKEY_MENU, ui::EF_NONE);
1142 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
1143 }
1144
1145 // When a user taps on an item, it should set the focus ring to that item. After
1146 // they release their finger it should confirm the selection.
TEST_F(InteractiveWindowCycleControllerTest,TapSelect)1147 TEST_F(InteractiveWindowCycleControllerTest, TapSelect) {
1148 std::unique_ptr<Window> w0 = CreateTestWindow();
1149 std::unique_ptr<Window> w1 = CreateTestWindow();
1150 std::unique_ptr<Window> w2 = CreateTestWindow();
1151 ui::test::EventGenerator* generator = GetEventGenerator();
1152 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1153
1154 // Start cycle and tap third item. On tap down, the focus ring should be set
1155 // to the third item. On tap release, the selection should be confirmed.
1156 // Starting order of windows in cycle list is [2,1,0].
1157 controller->StartCycling();
1158 generator->PressTouch(
1159 GetWindowCycleItemViews()[2]->GetBoundsInScreen().CenterPoint());
1160 EXPECT_TRUE(controller->IsCycling());
1161 EXPECT_EQ(GetTargetWindow(), w0.get());
1162 generator->ReleaseTouch();
1163 EXPECT_FALSE(controller->IsCycling());
1164 EXPECT_TRUE(wm::IsActiveWindow(w0.get()));
1165
1166 // Start cycle and tap second item. On tap down, the focus ring should be set
1167 // to the second item. On tap release, the selection should be confirmed.
1168 // Starting order of windows in cycle list is [0,2,1].
1169 controller->StartCycling();
1170 generator->PressTouch(
1171 GetWindowCycleItemViews()[1]->GetBoundsInScreen().CenterPoint());
1172 EXPECT_TRUE(controller->IsCycling());
1173 EXPECT_EQ(GetTargetWindow(), w2.get());
1174 generator->ReleaseTouch();
1175 EXPECT_FALSE(controller->IsCycling());
1176 EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
1177 }
1178
1179 // Tests that mouse events are filtered until the mouse is actually used,
1180 // preventing the mouse from unexpectedly triggering events.
1181 // See crbug.com/1143275.
TEST_F(InteractiveWindowCycleControllerTest,FilterMouseEventsUntilUsed)1182 TEST_F(InteractiveWindowCycleControllerTest, FilterMouseEventsUntilUsed) {
1183 std::unique_ptr<Window> w0 = CreateTestWindow();
1184 std::unique_ptr<Window> w1 = CreateTestWindow();
1185 std::unique_ptr<Window> w2 = CreateTestWindow();
1186 EventCounter event_count;
1187 ui::test::EventGenerator* generator = GetEventGenerator();
1188 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1189
1190 // Start cycling.
1191 // Current window order is [2,1,0].
1192 controller->StartCycling();
1193 auto item_views = GetWindowCycleItemViews();
1194 item_views[2]->AddPreTargetHandler(&event_count);
1195
1196 // Move the mouse over to the third item and complete cycling. These mouse
1197 // events shouldn't be filtered since the user has moved their mouse.
1198 generator->MoveMouseTo(gfx::Point(0, 0));
1199 const gfx::Point third_item_center =
1200 GetWindowCycleItemViews()[2]->GetBoundsInScreen().CenterPoint();
1201 generator->MoveMouseTo(third_item_center);
1202 controller->CompleteCycling();
1203 EXPECT_TRUE(wm::IsActiveWindow(w0.get()));
1204 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
1205
1206 // Start cycling again while the mouse is over where the third item will be
1207 // when cycling starts.
1208 // Current window order is [0,2,1].
1209 controller->StartCycling();
1210 item_views = GetWindowCycleItemViews();
1211 item_views[2]->AddPreTargetHandler(&event_count);
1212
1213 // Generate mouse events at the cursor's initial position. These mouse events
1214 // should be filtered because the user hasn't moved their mouse yet.
1215 generator->MoveMouseTo(third_item_center);
1216 controller->CompleteCycling();
1217 EXPECT_TRUE(wm::IsActiveWindow(w0.get()));
1218 EXPECT_EQ(0, event_count.GetMouseEventCountAndReset());
1219
1220 // Start cycling again and click. This should not be filtered out.
1221 // Current window order is [0,2,1].
1222 controller->StartCycling();
1223 generator->PressLeftButton();
1224 EXPECT_FALSE(controller->IsCycling());
1225 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
1226 }
1227
1228 // When a user has the window cycle list open and clicks outside of it, it
1229 // should cancel cycling.
TEST_F(InteractiveWindowCycleControllerTest,MousePressOutsideOfListCancelsCycling)1230 TEST_F(InteractiveWindowCycleControllerTest,
1231 MousePressOutsideOfListCancelsCycling) {
1232 std::unique_ptr<Window> w0 = CreateTestWindow();
1233 std::unique_ptr<Window> w1 = CreateTestWindow();
1234 std::unique_ptr<Window> w2 = CreateTestWindow();
1235 ui::test::EventGenerator* generator = GetEventGenerator();
1236 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1237
1238 // Cycle to second item, move to above the window cycle list, and click.
1239 controller->StartCycling();
1240 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1241 gfx::Point above_window_cycle_list =
1242 GetWindowCycleListWidget()->GetWindowBoundsInScreen().top_center();
1243 above_window_cycle_list.Offset(0, 100);
1244 generator->MoveMouseTo(above_window_cycle_list);
1245 generator->ClickLeftButton();
1246 EXPECT_FALSE(controller->IsCycling());
1247 EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
1248 }
1249
1250 // When the user has one window open, the window cycle view isn't shown. In this
1251 // case we should not eat mouse events.
TEST_F(InteractiveWindowCycleControllerTest,MouseEventsNotEatenWhenCycleViewNotVisible)1252 TEST_F(InteractiveWindowCycleControllerTest,
1253 MouseEventsNotEatenWhenCycleViewNotVisible) {
1254 std::unique_ptr<Window> w0 = CreateTestWindow();
1255 EventCounter event_count;
1256 w0->AddPreTargetHandler(&event_count);
1257 ui::test::EventGenerator* generator = GetEventGenerator();
1258
1259 // Start cycling. Since there's only one window the cycle view shouldn't be
1260 // visible.
1261 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1262 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1263 ASSERT_TRUE(controller->IsCycling());
1264 ASSERT_FALSE(controller->IsWindowListVisible());
1265
1266 generator->MoveMouseToCenterOf(w0.get());
1267 generator->ClickLeftButton();
1268 EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
1269 }
1270
1271 // Tests that frame throttling starts and ends accordingly when window cycling
1272 // starts and ends.
TEST_F(WindowCycleControllerTest,FrameThrottling)1273 TEST_F(WindowCycleControllerTest, FrameThrottling) {
1274 MockFrameThrottlingObserver observer;
1275 FrameThrottlingController* frame_throttling_controller =
1276 Shell::Get()->frame_throttling_controller();
1277 uint8_t throttled_fps = frame_throttling_controller->throttled_fps();
1278 frame_throttling_controller->AddObserver(&observer);
1279 const int window_count = 5;
1280 std::unique_ptr<aura::Window> created_windows[window_count];
1281 std::vector<aura::Window*> windows(window_count, nullptr);
1282 for (int i = 0; i < window_count; ++i) {
1283 created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER);
1284 windows[i] = created_windows[i].get();
1285 }
1286
1287 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
1288 EXPECT_CALL(observer,
1289 OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
1290 throttled_fps));
1291 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1292 EXPECT_CALL(observer,
1293 OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
1294 throttled_fps))
1295 .Times(0);
1296 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1297 EXPECT_CALL(observer, OnThrottlingEnded());
1298 controller->CompleteCycling();
1299
1300 EXPECT_CALL(observer,
1301 OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
1302 throttled_fps));
1303 controller->HandleCycleWindow(WindowCycleController::FORWARD);
1304 EXPECT_CALL(observer, OnThrottlingEnded());
1305 controller->CancelCycling();
1306 frame_throttling_controller->RemoveObserver(&observer);
1307 }
1308
1309 // Tests that pressing Alt+Tab while there is an on-going desk animation
1310 // prevents a new window cycle from starting.
TEST_F(WindowCycleControllerTest,DoubleAltTabWithDeskSwitch)1311 TEST_F(WindowCycleControllerTest, DoubleAltTabWithDeskSwitch) {
1312 WindowCycleController* cycle_controller =
1313 Shell::Get()->window_cycle_controller();
1314
1315 auto win0 = CreateAppWindow(gfx::Rect(250, 100));
1316 auto* desks_controller = DesksController::Get();
1317 desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
1318 ASSERT_EQ(2u, desks_controller->desks().size());
1319 const Desk* desk_0 = desks_controller->desks()[0].get();
1320 const Desk* desk_1 = desks_controller->desks()[1].get();
1321 ActivateDesk(desk_1);
1322 EXPECT_EQ(desk_1, desks_controller->active_desk());
1323 auto win1 = CreateAppWindow(gfx::Rect(300, 200));
1324 ASSERT_EQ(win1.get(), window_util::GetActiveWindow());
1325 auto desk_1_windows = desk_1->windows();
1326 EXPECT_EQ(1u, desk_1_windows.size());
1327 EXPECT_TRUE(base::Contains(desk_1_windows, win1.get()));
1328
1329 DeskSwitchAnimationWaiter waiter;
1330 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
1331 cycle_controller->CompleteCycling();
1332 EXPECT_FALSE(cycle_controller->CanCycle());
1333 cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
1334 EXPECT_FALSE(cycle_controller->IsCycling());
1335 waiter.Wait();
1336 EXPECT_EQ(desk_0, desks_controller->active_desk());
1337 EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
1338 }
1339
1340 } // namespace ash
1341