Add BothAxesSwipeDetector

This reports both x and y displacement, and both velocities onDragEnd().

Bug: 126596417
Change-Id: I1c62074b99fe21bc9eedf615e3c9a0a0a400bf81
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 08d73d0..12ca5ee 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -33,6 +33,7 @@
  * swipe action happens.
  *
  * @see SingleAxisSwipeDetector
+ * @see BothAxesSwipeDetector
  */
 public abstract class BaseSwipeDetector {
 
diff --git a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
new file mode 100644
index 0000000..944391e
--- /dev/null
+++ b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.touch;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * Two dimensional scroll/drag/swipe gesture detector that reports x and y displacement/velocity.
+ */
+public class BothAxesSwipeDetector extends BaseSwipeDetector {
+
+    public static final int DIRECTION_UP = 1 << 0;
+    // Note that this will track left instead of right in RTL.
+    public static final int DIRECTION_RIGHT = 1 << 1;
+    public static final int DIRECTION_DOWN = 1 << 2;
+    // Note that this will track right instead of left in RTL.
+    public static final int DIRECTION_LEFT = 1 << 3;
+
+    /* Client of this gesture detector can register a callback. */
+    private final Listener mListener;
+
+    private int mScrollDirections;
+
+    public BothAxesSwipeDetector(@NonNull Context context, @NonNull Listener l) {
+        this(ViewConfiguration.get(context), l, Utilities.isRtl(context.getResources()));
+    }
+
+    @VisibleForTesting
+    protected BothAxesSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
+            boolean isRtl) {
+        super(config, isRtl);
+        mListener = l;
+    }
+
+    public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
+        mScrollDirections = scrollDirectionFlags;
+        mIgnoreSlopWhenSettling = ignoreSlop;
+    }
+
+    @Override
+    protected boolean shouldScrollStart(PointF displacement) {
+        // Check if the client is interested in scroll in current direction.
+        boolean canScrollUp = (mScrollDirections & DIRECTION_UP) > 0
+                && displacement.y <= -mTouchSlop;
+        boolean canScrollRight = (mScrollDirections & DIRECTION_RIGHT) > 0
+                && displacement.x >= mTouchSlop;
+        boolean canScrollDown = (mScrollDirections & DIRECTION_DOWN) > 0
+                && displacement.y >= mTouchSlop;
+        boolean canScrollLeft = (mScrollDirections & DIRECTION_LEFT) > 0
+                && displacement.x <= -mTouchSlop;
+        return canScrollUp || canScrollRight || canScrollDown || canScrollLeft;
+    }
+
+    @Override
+    protected void reportDragStartInternal(boolean recatch) {
+        mListener.onDragStart(!recatch);
+    }
+
+    @Override
+    protected void reportDraggingInternal(PointF displacement, MotionEvent event) {
+        mListener.onDrag(displacement, event);
+    }
+
+    @Override
+    protected void reportDragEndInternal(PointF velocity) {
+        mListener.onDragEnd(velocity);
+    }
+
+    /** Listener to receive updates on the swipe. */
+    public interface Listener {
+        /** @param start whether this was the original drag start, as opposed to a recatch. */
+        void onDragStart(boolean start);
+
+        boolean onDrag(PointF displacement, MotionEvent motionEvent);
+
+        void onDragEnd(PointF velocity);
+    }
+}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index 0bf2ff6..f2ebc45 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -161,6 +161,7 @@
 
     /** Listener to receive updates on the swipe. */
     public interface Listener {
+        /** @param start whether this was the original drag start, as opposed to a recatch. */
         void onDragStart(boolean start);
 
         // TODO remove