1 // Copyright 2013 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/gestures/wm_gesture_handler.h"
6
7 #include "ash/public/cpp/ash_features.h"
8 #include "ash/public/cpp/ash_pref_names.h"
9 #include "ash/session/session_controller_impl.h"
10 #include "ash/shell.h"
11 #include "ash/test/ash_test_base.h"
12 #include "ash/wm/desks/desk.h"
13 #include "ash/wm/desks/desk_animation_base.h"
14 #include "ash/wm/desks/desks_controller.h"
15 #include "ash/wm/desks/desks_histogram_enums.h"
16 #include "ash/wm/desks/desks_test_util.h"
17 #include "ash/wm/desks/root_window_desk_switch_animator_test_api.h"
18 #include "ash/wm/overview/overview_controller.h"
19 #include "ash/wm/overview/overview_test_util.h"
20 #include "ash/wm/window_cycle_controller.h"
21 #include "ash/wm/window_cycle_list.h"
22 #include "ash/wm/window_util.h"
23 #include "base/test/scoped_feature_list.h"
24 #include "components/prefs/pref_service.h"
25 #include "ui/aura/window.h"
26 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
27 #include "ui/events/base_event_utils.h"
28 #include "ui/events/test/event_generator.h"
29 #include "ui/message_center/message_center.h"
30 #include "ui/views/widget/widget.h"
31
32 namespace ash {
33
34 namespace {
35
36 constexpr int kNumFingersForWindowCycle = 2;
37 constexpr int kNumFingersForHighlight = 3;
38 constexpr int kNumFingersForDesksSwitch = 4;
39
InOverviewSession()40 bool InOverviewSession() {
41 return Shell::Get()->overview_controller()->InOverviewSession();
42 }
43
GetHighlightedWindow()44 const aura::Window* GetHighlightedWindow() {
45 return InOverviewSession() ? GetOverviewHighlightedWindow() : nullptr;
46 }
47
IsNaturalScrollOn()48 bool IsNaturalScrollOn() {
49 PrefService* pref =
50 Shell::Get()->session_controller()->GetActivePrefService();
51 return pref->GetBoolean(prefs::kTouchpadEnabled) &&
52 pref->GetBoolean(prefs::kNaturalScroll);
53 }
54
GetOffsetX(int offset)55 int GetOffsetX(int offset) {
56 // The handler code uses the new directions which is the reverse of the old
57 // handler code. Reverse the offset if the ReverseScrollGestures feature is
58 // disabled so that the unit tests test the old behavior.
59 return features::IsReverseScrollGesturesEnabled() ? offset : -offset;
60 }
61
GetOffsetY(int offset)62 int GetOffsetY(int offset) {
63 // The handler code uses the new directions which is the reverse of the old
64 // handler code. Reverse the offset if the ReverseScrollGestures feature is
65 // disabled so that the unit tests test the old behavior.
66 if (!features::IsReverseScrollGesturesEnabled() || IsNaturalScrollOn())
67 return -offset;
68 return offset;
69 }
70
GetActiveDesk()71 const Desk* GetActiveDesk() {
72 return DesksController::Get()->active_desk();
73 }
74
GetNextDesk()75 const Desk* GetNextDesk() {
76 return DesksController::Get()->GetNextDesk();
77 }
78
AddDesk()79 void AddDesk() {
80 DesksController::Get()->NewDesk(DesksCreationRemovalSource::kButton);
81 }
82
83 } // namespace
84
85 class WmGestureHandlerTest : public AshTestBase {
86 public:
87 WmGestureHandlerTest() = default;
88 WmGestureHandlerTest(const WmGestureHandlerTest&) = delete;
89 WmGestureHandlerTest& operator=(const WmGestureHandlerTest&) = delete;
90 ~WmGestureHandlerTest() override = default;
91
Scroll(float x_offset,float y_offset,int fingers)92 void Scroll(float x_offset, float y_offset, int fingers) {
93 GetEventGenerator()->ScrollSequence(
94 gfx::Point(), base::TimeDelta::FromMilliseconds(5),
95 GetOffsetX(x_offset), GetOffsetY(y_offset), /*steps=*/100, fingers);
96 }
97
ScrollToSwitchDesks(bool scroll_left)98 void ScrollToSwitchDesks(bool scroll_left) {
99 if (features::IsEnhancedDeskAnimations()) {
100 // Scrolling to switch desks with enhanced desk animations is a bit tricky
101 // because it involves multiple async operations.
102 ui::ScopedAnimationDurationScaleMode test_duration_mode(
103 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
104
105 // Start off with a fling cancel (touchpad start) to start the touchpad
106 // swipe sequence.
107 base::TimeTicks timestamp = ui::EventTimeForNow();
108 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gfx::Point(),
109 timestamp, 0, 0, 0, 0, 0,
110 kNumFingersForDesksSwitch);
111 auto* event_generator = GetEventGenerator();
112 event_generator->Dispatch(&fling_cancel);
113
114 // Continue with a large enough scroll to start the desk switch animation.
115 // The animation does not start on fling cancel since there is no finger
116 // data in production code.
117 const base::TimeDelta step_delay = base::TimeDelta::FromMilliseconds(5);
118 timestamp += step_delay;
119 const int direction = scroll_left ? -1 : 1;
120 const int initial_move_x =
121 (WmGestureHandler::kContinuousGestureMoveThresholdDp + 5) * direction;
122 ui::ScrollEvent initial_move(ui::ET_SCROLL, gfx::Point(), timestamp, 0,
123 initial_move_x, 0, initial_move_x, 0,
124 kNumFingersForDesksSwitch);
125 event_generator->Dispatch(&initial_move);
126
127 // Wait until the animations ending screenshot has been taken. Otherwise,
128 // we will just stay at the initial desk if no screenshot has been taken.
129 auto* animation = DesksController::Get()->animation();
130 DCHECK(animation);
131 auto* desk_switch_animator =
132 animation->GetDeskSwitchAnimatorAtIndexForTesting(0);
133 base::RunLoop run_loop;
134 RootWindowDeskSwitchAnimatorTestApi(desk_switch_animator)
135 .SetOnEndingScreenshotTakenCallback(run_loop.QuitClosure());
136 run_loop.Run();
137
138 // Send some more move events, enough to shift to the next desk.
139 const int steps = 100;
140 const float x_offset =
141 direction * WmGestureHandler::kHorizontalThresholdDp;
142 float dx = x_offset / steps;
143 for (int i = 0; i < steps; ++i) {
144 timestamp += step_delay;
145 ui::ScrollEvent move(ui::ET_SCROLL, gfx::Point(), timestamp, 0, dx, 0,
146 dx, 0, kNumFingersForDesksSwitch);
147 event_generator->Dispatch(&move);
148 }
149
150 // End the swipe and wait for the animation to finish.
151 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gfx::Point(),
152 timestamp, 0, x_offset, 0, x_offset, 0,
153 kNumFingersForDesksSwitch);
154 DeskSwitchAnimationWaiter animation_finished_waiter;
155 event_generator->Dispatch(&fling_start);
156 animation_finished_waiter.Wait();
157 return;
158 }
159
160 DeskSwitchAnimationWaiter waiter;
161 const float x_offset =
162 (scroll_left ? -1 : 1) * WmGestureHandler::kHorizontalThresholdDp;
163 Scroll(x_offset, 0, kNumFingersForDesksSwitch);
164 waiter.Wait();
165 }
166
MouseWheelScroll(int delta_x,int delta_y,int num_of_times)167 void MouseWheelScroll(int delta_x, int delta_y, int num_of_times) {
168 auto* generator = GetEventGenerator();
169 for (int i = 0; i < num_of_times; i++)
170 generator->MoveMouseWheel(delta_x, delta_y);
171 }
172 };
173
174 // Tests a three fingers upwards scroll gesture to enter and a scroll down to
175 // exit overview.
TEST_F(WmGestureHandlerTest,VerticalScrolls)176 TEST_F(WmGestureHandlerTest, VerticalScrolls) {
177 const float long_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
178 Scroll(0, long_scroll, 3);
179 EXPECT_TRUE(InOverviewSession());
180
181 // Swiping down exits.
182 Scroll(0, -long_scroll, 3);
183 EXPECT_FALSE(InOverviewSession());
184 }
185
186 // Tests wrong gestures that swiping down to enter and up to exit overview.
TEST_F(WmGestureHandlerTest,WrongVerticalScrolls)187 TEST_F(WmGestureHandlerTest, WrongVerticalScrolls) {
188 base::test::ScopedFeatureList feature_list;
189 feature_list.InitAndEnableFeature(features::kReverseScrollGestures);
190
191 const float long_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
192
193 // Swiping down cannot enter overview.
194 Scroll(0, -long_scroll, 3);
195 EXPECT_FALSE(InOverviewSession());
196
197 // Enter overview.
198 Scroll(0, long_scroll, 3);
199 EXPECT_TRUE(InOverviewSession());
200
201 // Swiping up cannot exit overview.
202 Scroll(0, long_scroll, 3);
203 EXPECT_TRUE(InOverviewSession());
204 }
205
206 // Tests three or four finger horizontal scroll gesture (depending on flags) to
207 // move selection left or right.
TEST_F(WmGestureHandlerTest,HorizontalScrollInOverview)208 TEST_F(WmGestureHandlerTest, HorizontalScrollInOverview) {
209 const gfx::Rect bounds(0, 0, 400, 400);
210 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
211 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
212 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
213 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
214 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
215 const float vertical_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
216 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
217 // Enter overview mode as if using an accelerator.
218 // Entering overview mode with an upwards three-finger scroll gesture would
219 // have the same result (allow selection using horizontal scroll).
220 Shell::Get()->overview_controller()->StartOverview();
221 EXPECT_TRUE(InOverviewSession());
222
223 // Scrolls until a window is highlight, ignoring any desks items (if any).
224 auto scroll_until_window_highlighted = [this](float x_offset,
225 float y_offset) {
226 do {
227 Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset),
228 kNumFingersForHighlight);
229 } while (!GetHighlightedWindow());
230 };
231
232 // Select the first window first.
233 scroll_until_window_highlighted(horizontal_scroll, 0);
234
235 // Long scroll right moves selection to the fourth window.
236 scroll_until_window_highlighted(horizontal_scroll * 3, 0);
237 EXPECT_TRUE(InOverviewSession());
238
239 // Short scroll left moves selection to the third window.
240 scroll_until_window_highlighted(-horizontal_scroll, 0);
241 EXPECT_TRUE(InOverviewSession());
242
243 // Short scroll left moves selection to the second window.
244 scroll_until_window_highlighted(-horizontal_scroll, 0);
245 EXPECT_TRUE(InOverviewSession());
246
247 // Swiping down (3 fingers) exits and selects the currently-highlighted
248 // window.
249 Scroll(0, -vertical_scroll, 3);
250 EXPECT_FALSE(InOverviewSession());
251
252 // Second MRU window is selected (i.e. |window4|).
253 EXPECT_EQ(window4.get(), window_util::GetActiveWindow());
254 }
255
256 // Tests that a mostly horizontal scroll does not trigger overview.
TEST_F(WmGestureHandlerTest,HorizontalScrolls)257 TEST_F(WmGestureHandlerTest, HorizontalScrolls) {
258 const float long_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
259 Scroll(long_scroll + 100, long_scroll, kNumFingersForHighlight);
260 EXPECT_FALSE(InOverviewSession());
261
262 Scroll(-long_scroll - 100, long_scroll, kNumFingersForHighlight);
263 EXPECT_FALSE(InOverviewSession());
264 }
265
266 // Tests that we only enter overview after a scroll has ended.
TEST_F(WmGestureHandlerTest,EnterOverviewOnScrollEnd)267 TEST_F(WmGestureHandlerTest, EnterOverviewOnScrollEnd) {
268 base::TimeTicks timestamp = base::TimeTicks::Now();
269 const int num_fingers = 3;
270 base::TimeDelta step_delay(base::TimeDelta::FromMilliseconds(5));
271 ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gfx::Point(),
272 timestamp, 0, 0, 0, 0, 0, num_fingers);
273 GetEventGenerator()->Dispatch(&fling_cancel);
274
275 // Scroll up by 1000px. We are not in overview yet, because the scroll is
276 // still ongoing.
277 for (int i = 0; i < 100; ++i) {
278 timestamp += step_delay;
279 ui::ScrollEvent move(ui::ET_SCROLL, gfx::Point(), timestamp, 0, 0,
280 GetOffsetY(10), 0, GetOffsetY(10), num_fingers);
281 GetEventGenerator()->Dispatch(&move);
282 }
283 ASSERT_FALSE(InOverviewSession());
284
285 timestamp += step_delay;
286 ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gfx::Point(),
287 timestamp, 0, 0, GetOffsetY(-10), 0,
288 GetOffsetY(-10), num_fingers);
289 GetEventGenerator()->Dispatch(&fling_start);
290 EXPECT_TRUE(InOverviewSession());
291 }
292
293 using DesksGestureHandlerTest = WmGestureHandlerTest;
294
295 // Tests that a four-finger horizontal scroll will switch desks as expected.
TEST_F(DesksGestureHandlerTest,HorizontalScrolls)296 TEST_F(DesksGestureHandlerTest, HorizontalScrolls) {
297 auto* desk_controller = DesksController::Get();
298 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
299 ASSERT_EQ(2u, desk_controller->desks().size());
300 ASSERT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
301
302 // Tests that scrolling right should take us to the next desk.
303 ScrollToSwitchDesks(/*scroll_left=*/false);
304 EXPECT_EQ(desk_controller->desks()[1].get(), desk_controller->active_desk());
305
306 // Tests that scrolling left should take us to the previous desk.
307 ScrollToSwitchDesks(/*scroll_left=*/true);
308 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
309
310 // Tests that since there is no previous desk, we remain on the same desk when
311 // scrolling left.
312 const float long_scroll = WmGestureHandler::kHorizontalThresholdDp;
313 Scroll(-long_scroll, 0.f, kNumFingersForDesksSwitch);
314 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
315 }
316
317 // Tests that vertical scrolls and horizontal scrolls that are too small do not
318 // switch desks.
TEST_F(DesksGestureHandlerTest,NoDeskChanges)319 TEST_F(DesksGestureHandlerTest, NoDeskChanges) {
320 auto* desk_controller = DesksController::Get();
321 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
322 ASSERT_EQ(2u, desk_controller->desks().size());
323 ASSERT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
324
325 const float short_scroll = WmGestureHandler::kHorizontalThresholdDp - 10.f;
326 const float long_scroll = WmGestureHandler::kHorizontalThresholdDp;
327 // Tests that a short horizontal scroll does not switch desks.
328 Scroll(-short_scroll, 0.f, kNumFingersForDesksSwitch);
329 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
330
331 // Tests that a scroll that meets the horizontal requirements, but is mostly
332 // vertical does not switch desks.
333 Scroll(-long_scroll, long_scroll + 10.f, kNumFingersForDesksSwitch);
334 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
335
336 // Tests that a vertical scroll does not switch desks.
337 Scroll(0.f, WmGestureHandler::kVerticalThresholdDp,
338 kNumFingersForDesksSwitch);
339 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
340 }
341
342 // Tests that a large scroll only moves to the next desk.
TEST_F(DesksGestureHandlerTest,NoDoubleDeskChange)343 TEST_F(DesksGestureHandlerTest, NoDoubleDeskChange) {
344 // Enhanced desk animations supports switching multiple desks with large
345 // enough scrolls.
346 if (features::IsEnhancedDeskAnimations())
347 return;
348
349 auto* desk_controller = DesksController::Get();
350 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
351 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
352 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
353 ASSERT_EQ(4u, desk_controller->desks().size());
354 ASSERT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
355
356 const float long_scroll = WmGestureHandler::kHorizontalThresholdDp * 3;
357 DeskSwitchAnimationWaiter waiter;
358 Scroll(long_scroll, 0, kNumFingersForDesksSwitch);
359 waiter.Wait();
360 EXPECT_EQ(desk_controller->desks()[1].get(), desk_controller->active_desk());
361 }
362
363 // Tests that touchpad gesture scrolls don't lead to any desk changes when the
364 // screen is locked.
TEST_F(DesksGestureHandlerTest,NoDeskChangesInLockScreen)365 TEST_F(DesksGestureHandlerTest, NoDeskChangesInLockScreen) {
366 auto* desk_controller = DesksController::Get();
367 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
368 desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
369 ASSERT_EQ(3u, desk_controller->desks().size());
370 ASSERT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
371
372 auto* session_controller = Shell::Get()->session_controller();
373 session_controller->LockScreen();
374 GetSessionControllerClient()->FlushForTest(); // LockScreen is an async call.
375 ASSERT_TRUE(session_controller->IsScreenLocked());
376
377 const float long_scroll = WmGestureHandler::kHorizontalThresholdDp * 3;
378 Scroll(long_scroll, 0, kNumFingersForDesksSwitch);
379 EXPECT_FALSE(desk_controller->AreDesksBeingModified());
380 EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
381 }
382
383 class InteractiveWindowCycleListGestureHandlerTest
384 : public WmGestureHandlerTest {
385 public:
386 InteractiveWindowCycleListGestureHandlerTest() = default;
387 InteractiveWindowCycleListGestureHandlerTest(
388 const InteractiveWindowCycleListGestureHandlerTest&) = delete;
389 InteractiveWindowCycleListGestureHandlerTest& operator=(
390 const InteractiveWindowCycleListGestureHandlerTest&) = delete;
391 ~InteractiveWindowCycleListGestureHandlerTest() override = default;
392
393 // AshTestBase:
SetUp()394 void SetUp() override {
395 scoped_feature_list_.InitAndEnableFeature(
396 features::kInteractiveWindowCycleList);
397 AshTestBase::SetUp();
398 WindowCycleList::DisableInitialDelayForTesting();
399 }
400
GetCurrentIndex() const401 int GetCurrentIndex() const {
402 return Shell::Get()
403 ->window_cycle_controller()
404 ->window_cycle_list()
405 ->current_index_for_testing();
406 }
407
408 private:
409 base::test::ScopedFeatureList scoped_feature_list_;
410 };
411
412 // Tests three finger horizontal scroll gesture to move selection left or right.
TEST_F(InteractiveWindowCycleListGestureHandlerTest,ThreeFingerHorizontalScrollInWindowCycleList)413 TEST_F(InteractiveWindowCycleListGestureHandlerTest,
414 ThreeFingerHorizontalScrollInWindowCycleList) {
415 const gfx::Rect bounds(0, 0, 400, 400);
416 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
417 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
418 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
419 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
420 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
421 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
422
423 auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
424 float y_offset) {
425 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
426 controller->StartCycling();
427 Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset), kNumFingersForHighlight);
428 controller->CompleteCycling();
429 };
430
431 // Start cycle, simulating alt key being held down. Scroll right to fourth
432 // item.
433 // Current order is [5,4,3,2,1].
434 scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
435 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
436
437 // Start cycle. Scroll left to third item.
438 // Current order is [2,5,4,3,1].
439 scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
440 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
441
442 // Start cycle. Scroll right to second item.
443 // Current order is [4,2,5,3,1].
444 scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
445 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
446
447 // Open an overview session and window cycle list. Scroll right to second
448 // item. Scroll should only go to the window cycle list.
449 // Current order is [2,4,5,3,1].
450 Shell::Get()->overview_controller()->StartOverview();
451 EXPECT_TRUE(InOverviewSession());
452
453 Shell::Get()->window_cycle_controller()->StartCycling();
454 Scroll(GetOffsetX(horizontal_scroll), 0, kNumFingersForHighlight);
455 EXPECT_EQ(nullptr, GetHighlightedWindow());
456
457 Shell::Get()->window_cycle_controller()->CompleteCycling();
458 EXPECT_FALSE(InOverviewSession());
459 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
460 }
461
462 // Tests two finger horizontal scroll gesture to move selection left or right.
TEST_F(InteractiveWindowCycleListGestureHandlerTest,TwoFingerHorizontalScrollInWindowCycleList)463 TEST_F(InteractiveWindowCycleListGestureHandlerTest,
464 TwoFingerHorizontalScrollInWindowCycleList) {
465 const gfx::Rect bounds(0, 0, 400, 400);
466 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
467 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
468 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
469 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
470 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
471 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
472
473 auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
474 float y_offset) {
475 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
476 controller->StartCycling();
477 // Since two finger swipes are negated, negate in tests to mimic how this
478 // actually behaves on devices.
479 Scroll(GetOffsetX(-x_offset), GetOffsetY(y_offset),
480 kNumFingersForWindowCycle);
481 controller->CompleteCycling();
482 };
483
484 // Start cycle, simulating alt key being held down. Scroll right to fourth
485 // item.
486 // Current order is [5,4,3,2,1].
487 scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
488 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
489
490 // Start cycle. Scroll left to third item.
491 // Current order is [2,5,4,3,1].
492 scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
493 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
494
495 // Start cycle. Scroll right to second item.
496 // Current order is [4,2,5,3,1].
497 scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
498 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
499 }
500
501 // Tests mouse wheel scroll gesture to move selection left or right.
TEST_F(InteractiveWindowCycleListGestureHandlerTest,MouseWheelScrollInWindowCycleList)502 TEST_F(InteractiveWindowCycleListGestureHandlerTest,
503 MouseWheelScrollInWindowCycleList) {
504 const gfx::Rect bounds(0, 0, 400, 400);
505 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
506 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
507 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
508 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
509 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
510 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
511
512 auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
513 float y_offset,
514 int num_of_times) {
515 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
516 controller->StartCycling();
517 MouseWheelScroll(x_offset, y_offset, num_of_times);
518 controller->CompleteCycling();
519 };
520
521 // Start cycle, simulating alt key being held down. Scroll right to fourth
522 // item.
523 // Current order is [5,4,3,2,1].
524 scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
525 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
526
527 // Start cycle. Scroll left to third item.
528 // Current order is [2,5,4,3,1].
529 scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
530 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
531
532 // Start cycle. Scroll right to second item.
533 // Current order is [4,2,5,3,1].
534 scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
535 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
536 }
537
538 // Tests that swiping up closes window cycle if it's open and starts overview
539 // mode.
540 // TODO(chinsenj): Add this test to
541 // WmGestureHandlerTest.VerticalScrolls after this feature is launched.
TEST_F(InteractiveWindowCycleListGestureHandlerTest,VerticalScroll)542 TEST_F(InteractiveWindowCycleListGestureHandlerTest, VerticalScroll) {
543 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
544 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
545 const float vertical_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
546 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
547 auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
548
549 // Start cycling and then swipe up to open up overview.
550 window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
551 EXPECT_TRUE(window_cycle_controller->IsCycling());
552 Scroll(0, vertical_scroll, 3);
553 EXPECT_TRUE(InOverviewSession());
554 EXPECT_FALSE(window_cycle_controller->IsCycling());
555
556 // Start cycling and then swipe down.
557 window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
558 EXPECT_TRUE(window_cycle_controller->IsCycling());
559 Scroll(0, -vertical_scroll, 3);
560 EXPECT_TRUE(window_cycle_controller->IsCycling());
561
562 // Swipe diagonally with horizontal bias.
563 Scroll(horizontal_scroll * 3, vertical_scroll, 3);
564 EXPECT_TRUE(window_cycle_controller->IsCycling());
565 EXPECT_FALSE(InOverviewSession());
566
567 // Swipe diagonally with vertical bias.
568 Scroll(horizontal_scroll, vertical_scroll, 3);
569 EXPECT_FALSE(window_cycle_controller->IsCycling());
570 EXPECT_TRUE(InOverviewSession());
571 }
572
573 class ReverseGestureHandlerTest : public WmGestureHandlerTest {
574 public:
575 ReverseGestureHandlerTest() = default;
576 ReverseGestureHandlerTest(const ReverseGestureHandlerTest&) = delete;
577 ReverseGestureHandlerTest& operator=(const ReverseGestureHandlerTest&) =
578 delete;
579 ~ReverseGestureHandlerTest() override = default;
580
581 // AshTestBase:
SetUp()582 void SetUp() override {
583 scoped_feature_list_.InitWithFeatures(
584 {features::kInteractiveWindowCycleList,
585 features::kReverseScrollGestures},
586 {});
587 AshTestBase::SetUp();
588
589 // Set natural scroll on.
590 PrefService* pref =
591 Shell::Get()->session_controller()->GetActivePrefService();
592 pref->SetBoolean(prefs::kTouchpadEnabled, true);
593 pref->SetBoolean(prefs::kNaturalScroll, true);
594 pref->SetBoolean(prefs::kMouseReverseScroll, true);
595 }
596
597 private:
598 base::test::ScopedFeatureList scoped_feature_list_;
599 };
600
TEST_F(ReverseGestureHandlerTest,Overview)601 TEST_F(ReverseGestureHandlerTest, Overview) {
602 const float long_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
603
604 // Use the new gestures.
605 // Swiping up with three fingers enters overview.
606 Scroll(0, long_scroll, 3);
607 EXPECT_TRUE(InOverviewSession());
608
609 // Swiping up again with three fingers does nothing.
610 Scroll(0, long_scroll, 3);
611 EXPECT_TRUE(InOverviewSession());
612
613 // Swiping down with three fingers exits overview.
614 Scroll(0, -long_scroll, 3);
615 EXPECT_FALSE(InOverviewSession());
616
617 // Swiping down again with three fingers does nothing.
618 Scroll(0, -long_scroll, 3);
619 EXPECT_FALSE(InOverviewSession());
620 }
621
TEST_F(ReverseGestureHandlerTest,SwitchDesk)622 TEST_F(ReverseGestureHandlerTest, SwitchDesk) {
623 // Add a new desk2.
624 AddDesk();
625 const Desk* desk1 = GetActiveDesk();
626 const Desk* desk2 = GetNextDesk();
627
628 // Scroll left to get next desk.
629 ScrollToSwitchDesks(/*scroll_left=*/true);
630 EXPECT_EQ(desk2, GetActiveDesk());
631 // Scroll right to get previous desk.
632 ScrollToSwitchDesks(/*scroll_right=*/false);
633 EXPECT_EQ(desk1, GetActiveDesk());
634 }
635
636 // Tests mouse wheel scroll gesture to move selection left or right. Mouse
637 // reverse scroll should reverse its direction.
TEST_F(ReverseGestureHandlerTest,MouseWheelScrollInWindowCycleList)638 TEST_F(ReverseGestureHandlerTest, MouseWheelScrollInWindowCycleList) {
639 const gfx::Rect bounds(0, 0, 400, 400);
640 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
641 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
642 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
643 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
644 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
645 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
646
647 auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
648 float y_offset,
649 int num_of_times) {
650 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
651 controller->StartCycling();
652 MouseWheelScroll(x_offset, y_offset, num_of_times);
653 controller->CompleteCycling();
654 };
655
656 // Start cycle, simulating alt key being held down. Scroll right to fourth
657 // item.
658 // Current order is [5,4,3,2,1].
659 scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
660 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
661
662 // Start cycle. Scroll left to third item.
663 // Current order is [2,5,4,3,1].
664 scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
665 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
666
667 // Start cycle. Scroll right to second item.
668 // Current order is [4,2,5,3,1].
669 scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
670 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
671
672 // Turn mouse reverse scroll off.
673 PrefService* pref =
674 Shell::Get()->session_controller()->GetActivePrefService();
675 pref->SetBoolean(prefs::kMouseReverseScroll, false);
676
677 // Start cycle. Scroll left once.
678 // Current order is [2,4,5,3,1].
679 scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
680 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
681
682 // Start cycle. Scroll right once.
683 // Current order is [1,2,4,5,3].
684 scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
685 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
686 }
687
688 // Tests that natural scroll doesn't affect two and three finger horizontal
689 // scroll gestures for cycling window cycle list.
TEST_F(ReverseGestureHandlerTest,WindowCycleListTrackpadGestures)690 TEST_F(ReverseGestureHandlerTest, WindowCycleListTrackpadGestures) {
691 const gfx::Rect bounds(0, 0, 400, 400);
692 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
693 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
694 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
695 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
696 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
697 const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
698
699 auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
700 float y_offset,
701 int num_fingers) {
702 WindowCycleController* controller = Shell::Get()->window_cycle_controller();
703 controller->StartCycling();
704 Scroll(x_offset, y_offset, num_fingers);
705 controller->CompleteCycling();
706 };
707
708 // Start cycle, scroll right with two finger gesture.
709 // Current order is [5,4,3,2,1].
710 scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
711 kNumFingersForWindowCycle);
712 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
713
714 // Start cycle, scroll right with three finger gesture.
715 // Current order is [4,5,3,2,1].
716 scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
717 kNumFingersForHighlight);
718 EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
719
720 // Turn natural scroll off.
721 PrefService* pref =
722 Shell::Get()->session_controller()->GetActivePrefService();
723 pref->SetBoolean(prefs::kNaturalScroll, false);
724
725 // Start cycle, scroll right with two finger gesture. Note: two figner swipes
726 // are negated, so negate in tests to mimic how this actually behaves on
727 // devices.
728 // Current order is [5,4,3,2,1].
729 scroll_until_window_highlighted_and_confirm(-horizontal_scroll, 0,
730 kNumFingersForWindowCycle);
731 EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
732
733 // Start cycle, scroll right with three finger gesture.
734 // Current order is [4,5,3,2,1].
735 scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
736 kNumFingersForHighlight);
737 EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
738 }
739
740 } // namespace ash
741