[Merge to M87] Add flags for reverse scrolling

This CL adds a flag for the reverse scrolling features:

- kReverseScrollGestures: enable reverse scroll gestures

(cherry picked from commit 75bb1ae7903b031d27429838340fae6454e79b49)

Bug: 1107183
Change-Id: Id1f918bacbca2726300927e7bf0e680b9237053b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419922
Commit-Queue: Xiaodan Zhu <[email protected]>
Reviewed-by: Xiyuan Xia <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#814922}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2459509
Reviewed-by: Xiaoqian Dai <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#122}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 42021d8..a3bf0b86 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -118,6 +118,9 @@
 const base::Feature kHideShelfControlsInTabletMode{
     "HideShelfControlsInTabletMode", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kReverseScrollGestures{"EnableReverseScrollGestures",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kSystemTrayMicGainSetting{"SystemTrayMicGainSetting",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -254,6 +257,10 @@
   return base::FeatureList::IsEnabled(kHideShelfControlsInTabletMode);
 }
 
+bool IsReverseScrollGesturesEnabled() {
+  return base::FeatureList::IsEnabled(kReverseScrollGestures);
+}
+
 bool AreContextualNudgesEnabled() {
   if (!IsHideShelfControlsInTabletModeEnabled())
     return false;
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 9057bce8..77cf1e1 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -153,6 +153,12 @@
 // preferences, or policy).
 ASH_PUBLIC_EXPORT extern const base::Feature kHideShelfControlsInTabletMode;
 
+// When enabled, the overivew and desk reverse scrolling behaviors are changed
+// and if the user performs the old gestures, a notification or toast will show
+// up.
+// TODO(https://crbug.com/1107183): Remove this after the feature is launched.
+ASH_PUBLIC_EXPORT extern const base::Feature kReverseScrollGestures;
+
 // Enables sliders for setting mic gain levels in the more audio settings
 // section in the system tray.
 ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayMicGainSetting;
@@ -228,6 +234,8 @@
 
 ASH_PUBLIC_EXPORT bool IsHideShelfControlsInTabletModeEnabled();
 
+ASH_PUBLIC_EXPORT bool IsReverseScrollGesturesEnabled();
+
 ASH_PUBLIC_EXPORT bool AreContextualNudgesEnabled();
 
 ASH_PUBLIC_EXPORT bool IsSystemTrayMicGainSettingEnabled();
diff --git a/ash/wm/gestures/wm_gesture_handler.cc b/ash/wm/gestures/wm_gesture_handler.cc
index 365cba06..86c1546 100644
--- a/ash/wm/gestures/wm_gesture_handler.cc
+++ b/ash/wm/gestures/wm_gesture_handler.cc
@@ -63,6 +63,11 @@
 
 // Reverse an offset when the reverse scrolling is on.
 float GetOffset(float offset) {
+  // The handler code uses the new directions which is the reverse of the old
+  // handler code. Reverse the offset if the ReverseScrollGestures feature is
+  // disabled so that the users get old behavior.
+  if (!features::IsReverseScrollGesturesEnabled())
+    return -offset;
   return IsNaturalScrollOn() ? -offset : offset;
 }
 
@@ -132,7 +137,7 @@
     // show notification; in M88, swip up will only show notification; in M89
     // the notification is removed.
     if (GetOffset(scroll_y) > 0) {
-      if (IsNaturalScrollOn())
+      if (!features::IsReverseScrollGesturesEnabled() || IsNaturalScrollOn())
         return false;
 
       ShowOverviewGestureNotification();
@@ -148,7 +153,7 @@
     // but show notification; in M88, swip down will only show notification; in
     // M89 the notification is removed.
     if (GetOffset(scroll_y) < 0) {
-      if (IsNaturalScrollOn())
+      if (!features::IsReverseScrollGesturesEnabled() || IsNaturalScrollOn())
         return false;
 
       ShowOverviewGestureNotification();
@@ -171,8 +176,8 @@
   if (std::fabs(scroll_x) < WmGestureHandler::kHorizontalThresholdDp)
     return false;
 
-  if (!IsNaturalScrollOn()) {
-    if (scroll_x > 0 && !DesksController::Get()->GetNextDesk() &&
+  if (features::IsReverseScrollGesturesEnabled() && !IsNaturalScrollOn()) {
+    if (GetOffset(scroll_x) > 0 && !DesksController::Get()->GetNextDesk() &&
         DesksController::Get()->GetPreviousDesk()) {
       if (!gDidWrongLastDeskGesture) {
         gDidWrongLastDeskGesture = true;
@@ -180,7 +185,7 @@
         ShowReverseGestureToast(kSwitchLastDeskToastId,
                                 IDS_CHANGE_LAST_DESK_REVERSE_GESTURE);
       }
-    } else if (scroll_x < 0 &&
+    } else if (GetOffset(scroll_x) < 0 &&
                !DesksController::Get()->GetPreviousDesk() &&
                DesksController::Get()->GetNextDesk()) {
       if (!gDidWrongNextDeskGesture) {
diff --git a/ash/wm/gestures/wm_gesture_handler_unittest.cc b/ash/wm/gestures/wm_gesture_handler_unittest.cc
index 5cf0971..cfe7f09 100644
--- a/ash/wm/gestures/wm_gesture_handler_unittest.cc
+++ b/ash/wm/gestures/wm_gesture_handler_unittest.cc
@@ -63,6 +63,22 @@
   }
 }
 
+int GetOffsetX(int offset) {
+  // The handler code uses the new directions which is the reverse of the old
+  // handler code. Reverse the offset if the ReverseScrollGestures feature is
+  // disabled so that the unit tests test the old behavior.
+  return features::IsReverseScrollGesturesEnabled() ? offset : -offset;
+}
+
+int GetOffsetY(int offset) {
+  // The handler code uses the new directions which is the reverse of the old
+  // handler code. Reverse the offset if the ReverseScrollGestures feature is
+  // disabled so that the unit tests test the old behavior.
+  if (!features::IsReverseScrollGesturesEnabled() || IsNaturalScrollOn())
+    return -offset;
+  return offset;
+}
+
 const Desk* GetActiveDesk() {
   return DesksController::Get()->active_desk();
 }
@@ -84,8 +100,8 @@
 
   void Scroll(float x_offset, float y_offset, int fingers) {
     GetEventGenerator()->ScrollSequence(
-        gfx::Point(), base::TimeDelta::FromMilliseconds(5), x_offset,
-        IsNaturalScrollOn() ? -y_offset : y_offset, /*steps=*/100, fingers);
+        gfx::Point(), base::TimeDelta::FromMilliseconds(5),
+        GetOffsetX(x_offset), GetOffsetY(y_offset), /*steps=*/100, fingers);
   }
 
   void ScrollToSwitchDesks(bool scroll_left) {
@@ -120,6 +136,9 @@
 
 // Tests wrong gestures that swiping down to enter and up to exit overview.
 TEST_F(WmGestureHandlerTest, WrongVerticalScrolls) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kReverseScrollGestures);
+
   const float long_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
 
   // Swiping down can enter overview but a notification will be shown.
@@ -171,7 +190,8 @@
   auto scroll_until_window_highlighted = [this](float x_offset,
                                                 float y_offset) {
     do {
-      Scroll(x_offset, y_offset, kNumFingersForHighlight);
+      Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset),
+             kNumFingersForHighlight);
     } while (!GetHighlightedWindow());
   };
 
@@ -222,15 +242,16 @@
   // still ongoing.
   for (int i = 0; i < 100; ++i) {
     timestamp += step_delay;
-    ui::ScrollEvent move(ui::ET_SCROLL, gfx::Point(), timestamp, 0, 0, 10, 0,
-                         10, num_fingers);
+    ui::ScrollEvent move(ui::ET_SCROLL, gfx::Point(), timestamp, 0, 0,
+                         GetOffsetY(10), 0, GetOffsetY(10), num_fingers);
     GetEventGenerator()->Dispatch(&move);
   }
   ASSERT_FALSE(InOverviewSession());
 
   timestamp += step_delay;
   ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gfx::Point(),
-                              timestamp, 0, 0, -10, 0, -10, num_fingers);
+                              timestamp, 0, 0, GetOffsetY(-10), 0,
+                              GetOffsetY(-10), num_fingers);
   GetEventGenerator()->Dispatch(&fling_start);
   EXPECT_TRUE(InOverviewSession());
 }
@@ -366,7 +387,7 @@
                                                             float y_offset) {
     WindowCycleController* controller = Shell::Get()->window_cycle_controller();
     controller->StartCycling();
-    Scroll(x_offset, y_offset, kNumFingersForHighlight);
+    Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset), kNumFingersForHighlight);
     controller->CompleteCycling();
   };
 
@@ -393,7 +414,7 @@
   EXPECT_TRUE(InOverviewSession());
 
   Shell::Get()->window_cycle_controller()->StartCycling();
-  Scroll(horizontal_scroll, 0, kNumFingersForHighlight);
+  Scroll(GetOffsetX(horizontal_scroll), 0, kNumFingersForHighlight);
   EXPECT_EQ(nullptr, GetHighlightedWindow());
 
   Shell::Get()->window_cycle_controller()->CompleteCycling();
@@ -418,7 +439,8 @@
     controller->StartCycling();
     // Since two finger swipes are negated, negate in tests to mimic how this
     // actually behaves on devices.
-    Scroll(-x_offset, y_offset, kNumFingersForWindowCycle);
+    Scroll(GetOffsetX(-x_offset), GetOffsetY(y_offset),
+           kNumFingersForWindowCycle);
     controller->CompleteCycling();
   };
 
@@ -521,8 +543,10 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kInteractiveWindowCycleList);
+    scoped_feature_list_.InitWithFeatures(
+        {features::kInteractiveWindowCycleList,
+         features::kReverseScrollGestures},
+        {});
     AshTestBase::SetUp();
 
     // Set natural scroll on.