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