Merge "Implements LAUNCHER_ITEM_DROP_FOLDER_CREATED event." into ub-launcher3-rvc-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 6b0d7a3..1f6c506 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -26,7 +26,6 @@
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
-import static com.android.quickstep.GestureState.STATE_OVERSCROLL_WINDOW_CREATED;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
@@ -431,6 +430,6 @@
 
     @Override
     public boolean allowInterceptByParent() {
-        return !mPassedPilferInputSlop || mGestureState.hasState(STATE_OVERSCROLL_WINDOW_CREATED);
+        return !mPassedPilferInputSlop;
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
index 1941830..c49b8f2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
@@ -24,11 +24,9 @@
 
 import static com.android.launcher3.Utilities.squaredHypot;
 
-import static java.lang.Math.abs;
-
 import android.content.Context;
 import android.graphics.PointF;
-import android.util.Log;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
@@ -46,31 +44,24 @@
  * Input consumer for handling events to pass to an {@code OverscrollPlugin}.
  */
 public class OverscrollInputConsumer extends DelegateInputConsumer {
+
     private static final String TAG = "OverscrollInputConsumer";
-    private static final boolean DEBUG_LOGS_ENABLED = false;
-    private static void debugPrint(String log) {
-        if (DEBUG_LOGS_ENABLED) {
-            Log.v(TAG, log);
-        }
-    }
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
     private final PointF mStartDragPos = new PointF();
     private final int mAngleThreshold;
 
-    private final int mFlingDistanceThresholdPx;
-    private final int mFlingVelocityThresholdPx;
+    private final float mFlingThresholdPx;
     private int mActivePointerId = -1;
     private boolean mPassedSlop = false;
-    // True if we set ourselves as active, meaning we no longer pass events to the delegate.
-    private boolean mPassedActiveThreshold = false;
-    private final float mSquaredActiveThreshold;
+
     private final float mSquaredSlop;
 
     private final GestureState mGestureState;
     @Nullable
     private final OverscrollPlugin mPlugin;
+    private final GestureDetector mGestureDetector;
 
     @Nullable
     private RecentsView mRecentsView;
@@ -81,19 +72,15 @@
 
         mAngleThreshold = context.getResources()
                 .getInteger(R.integer.assistant_gesture_corner_deg_threshold);
-        mFlingDistanceThresholdPx = (int) context.getResources()
-                .getDimension(R.dimen.gestures_overscroll_fling_threshold);
-        mFlingVelocityThresholdPx = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
+        mFlingThresholdPx = context.getResources()
+            .getDimension(R.dimen.gestures_overscroll_fling_threshold);
         mGestureState = gestureState;
         mPlugin = plugin;
 
         float slop = ViewConfiguration.get(context).getScaledTouchSlop();
 
         mSquaredSlop = slop * slop;
-
-        float dragThreshold = (int) context.getResources()
-                .getDimension(R.dimen.gestures_overscroll_drag_threshold);
-        mSquaredActiveThreshold = dragThreshold * dragThreshold;
+        mGestureDetector = new GestureDetector(context, new FlingGestureListener());
     }
 
     @Override
@@ -103,27 +90,12 @@
 
     @Override
     public void onMotionEvent(MotionEvent ev) {
-        if (mPlugin == null) {
-            return;
-        }
-
         switch (ev.getActionMasked()) {
             case ACTION_DOWN: {
-                if (mPlugin.blockOtherGestures()) {
-                    // When an Activity is visible, blocking other gestures prevents the Activity
-                    // from disappearing upon ACTION_DOWN in the navigation bar. (it will reappear
-                    // on ACTION_MOVE or ACTION_UP)
-                    debugPrint("Becoming active on ACTION_DOWN");
-                    if (mState != STATE_ACTIVE) {
-                        setActive(ev);
-                    }
-                }
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
-                mPlugin.onTouchEvent(ev, getHorizontalDistancePx(), getVerticalDistancePx(),
-                        (int) Math.sqrt(mSquaredActiveThreshold), mFlingDistanceThresholdPx,
-                        mFlingVelocityThresholdPx, getDeviceState(), getUnderlyingActivity());
+
                 break;
             }
             case ACTION_POINTER_DOWN: {
@@ -159,82 +131,53 @@
                 }
                 mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
 
-                float squaredDist = squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y);
-
-
-
                 if (!mPassedSlop) {
                     // Normal gesture, ensure we pass the slop before we start tracking the gesture
-                    if (squaredDist > mSquaredSlop) {
-                        debugPrint("passed slop");
+                    if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
+                            > mSquaredSlop) {
+
                         mPassedSlop = true;
                         mStartDragPos.set(mLastPos.x, mLastPos.y);
                         if (isOverscrolled()) {
-                            debugPrint("setting STATE_OVERSCROLL_WINDOW_CREATED");
-                            mGestureState.setState(GestureState.STATE_OVERSCROLL_WINDOW_CREATED);
-                            if (!mPlugin.allowsUnderlyingActivityOverscroll()
-                                    && (mState != STATE_ACTIVE)) {
-                                debugPrint("setting active gesture handler to overscroll to "
-                                        + "prevent losing active touch when Activity starts");
-                                setActive(ev);
-                            }
-                        }
-                    } else {
-                        debugPrint("Not past slop");
-                    }
-                }
-
-                if (mPassedSlop && !mPassedActiveThreshold && isOverscrolled()) {
-                    if ((squaredDist > mSquaredActiveThreshold)) {
-                        debugPrint("Past slop and past threshold, set active");
-
-                        mPassedActiveThreshold = true;
-                        if (mState != STATE_ACTIVE) {
                             setActive(ev);
+
+                            if (mPlugin != null) {
+                                mPlugin.onTouchStart(getDeviceState(), getUnderlyingActivity());
+                            }
+                        } else {
+                            mState = STATE_DELEGATE_ACTIVE;
                         }
                     }
                 }
 
-                if (mPassedSlop && mState != STATE_DELEGATE_ACTIVE && isOverscrolled()) {
-                    debugPrint("Relaying touch event");
-                    mPlugin.onTouchEvent(ev, getHorizontalDistancePx(), getVerticalDistancePx(),
-                            (int) Math.sqrt(mSquaredActiveThreshold), mFlingDistanceThresholdPx,
-                            mFlingVelocityThresholdPx, getDeviceState(), getUnderlyingActivity());
+                if (mPassedSlop && mState != STATE_DELEGATE_ACTIVE && isOverscrolled()
+                        && mPlugin != null) {
+                    mPlugin.onTouchTraveled(getDistancePx());
                 }
 
                 break;
             }
             case ACTION_CANCEL:
             case ACTION_UP:
-                if (mPassedSlop && isOverscrolled()) {
-                    mPlugin.onTouchEvent(ev, getHorizontalDistancePx(), getVerticalDistancePx(),
-                            (int) Math.sqrt(mSquaredActiveThreshold), mFlingDistanceThresholdPx,
-                            mFlingVelocityThresholdPx, getDeviceState(), getUnderlyingActivity());
+                if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop && mPlugin != null) {
+                    mPlugin.onTouchEnd(getDistancePx());
                 }
 
                 mPassedSlop = false;
-                mPassedActiveThreshold = false;
                 mState = STATE_INACTIVE;
                 break;
         }
 
+        if (mState != STATE_DELEGATE_ACTIVE) {
+            mGestureDetector.onTouchEvent(ev);
+        }
+
         if (mState != STATE_ACTIVE) {
             mDelegate.onMotionEvent(ev);
         }
     }
 
     private boolean isOverscrolled() {
-        if (mPlugin.blockOtherGestures()) {
-            // When an Activity is visible, this `InputConsumer` immediately becomes
-            // the active gesture handler to prevent the Activity from disappearing on TOUCH_DOWN
-            // in the navbar.
-            //
-            // Returning `true` ensures that case will still result in touches being handled,
-            // instead of dropping touches until the gesture reaches the thresholds calculated
-            // below.
-            return true;
-        }
-
         if (mRecentsView == null) {
             BaseDraggingActivity activity = mGestureState.getActivityInterface()
                     .getCreatedActivity();
@@ -253,10 +196,9 @@
                 || mRecentsView.getRunningTaskIndex() <= maxIndex);
 
         // Check if the gesture is within our angle threshold of horizontal
-        float deltaY = abs(mLastPos.y - mDownPos.y);
-        float deltaX = abs(mDownPos.x - mLastPos.x);
-
-        boolean angleInBounds = (Math.toDegrees(Math.atan2(deltaY, deltaX)) < mAngleThreshold);
+        float deltaY = Math.abs(mLastPos.y - mDownPos.y);
+        float deltaX = mDownPos.x - mLastPos.x; // Positive if this is a gesture to the left
+        boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < mAngleThreshold;
 
         return atRightMostApp && angleInBounds;
     }
@@ -277,22 +219,35 @@
         return deviceState;
     }
 
-    private int getHorizontalDistancePx() {
-        return (int) (mLastPos.x - mDownPos.x);
-    }
-
-    private int getVerticalDistancePx() {
-        return (int) (mLastPos.y - mDownPos.y);
+    private int getDistancePx() {
+        return (int) Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y);
     }
 
     private String getUnderlyingActivity() {
-        // Overly defensive, got guidance on code review that something in the chain of
-        // `mGestureState.getRunningTask().topActivity` can be null and thus cause a null pointer
-        // exception to be thrown, but we aren't sure which part can be null.
-        if ((mGestureState == null) || (mGestureState.getRunningTask() == null)
-                || (mGestureState.getRunningTask().topActivity == null)) {
-            return "";
-        }
         return mGestureState.getRunningTask().topActivity.flattenToString();
     }
+
+    private class FlingGestureListener extends GestureDetector.SimpleOnGestureListener {
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            if (isValidAngle(velocityX, -velocityY)
+                    && getDistancePx() >= mFlingThresholdPx
+                    && mState != STATE_DELEGATE_ACTIVE) {
+
+                if (mPlugin != null) {
+                    mPlugin.onFling(-velocityX);
+                }
+            }
+            return true;
+        }
+
+        private boolean isValidAngle(float deltaX, float deltaY) {
+            float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+            // normalize so that angle is measured clockwise from horizontal in the bottom right
+            // corner and counterclockwise from horizontal in the bottom left corner
+
+            angle = angle > 90 ? 180 - angle : angle;
+            return (angle < mAngleThreshold);
+        }
+    }
 }
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6624ff9..b06dc6b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -79,7 +79,6 @@
 
     <!-- Overscroll Gesture -->
     <dimen name="gestures_overscroll_fling_threshold">40dp</dimen>
-    <dimen name="gestures_overscroll_drag_threshold">136dp</dimen>
 
     <!-- Tips Gesture Tutorial -->
     <dimen name="gesture_tutorial_title_margin_start_end">40dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 209412a..544f420 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -106,10 +106,6 @@
     public static final int STATE_RECENTS_ANIMATION_ENDED =
             getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
 
-    // Called when we create an overscroll window when swiping right to left on the most recent app
-    public static final int STATE_OVERSCROLL_WINDOW_CREATED =
-            getFlagForIndex("STATE_OVERSCROLL_WINDOW_CREATED");
-
     // Called when RecentsView stops scrolling and settles on a TaskView.
     public static final int STATE_RECENTS_SCROLLING_FINISHED =
             getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6919339..78d194b 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -110,9 +110,6 @@
     public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
             "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
 
-    public static final BooleanFlag ENABLE_QUICK_CAPTURE_WINDOW = getDebugFlag(
-            "ENABLE_QUICK_CAPTURE_WINDOW", false, "Use window to host quick capture");
-
     public static final BooleanFlag FORCE_LOCAL_OVERSCROLL_PLUGIN = getDebugFlag(
             "FORCE_LOCAL_OVERSCROLL_PLUGIN", false,
             "Use a launcher-provided OverscrollPlugin if available");
diff --git a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
index a434d07..28a9193 100644
--- a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
@@ -15,8 +15,6 @@
  */
 package com.android.systemui.plugins;
 
-import android.view.MotionEvent;
-
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
 /**
@@ -30,7 +28,7 @@
 public interface OverscrollPlugin extends Plugin {
 
     String ACTION = "com.android.systemui.action.PLUGIN_LAUNCHER_OVERSCROLL";
-    int VERSION = 4;
+    int VERSION = 3;
 
     String DEVICE_STATE_LOCKED = "Locked";
     String DEVICE_STATE_LAUNCHER = "Launcher";
@@ -43,33 +41,33 @@
     boolean isActive();
 
     /**
-     * Called when a touch has been recognized as an overscroll gesture.
-     * @param horizontalDistancePx Horizontal distance from the last finger location to the finger
-     *                               location when it first touched the screen.
-     * @param verticalDistancePx Horizontal distance from the last finger location to the finger
-     *                             location when it first touched the screen.
-     * @param thresholdPx Minimum distance for gesture.
-     * @param flingDistanceThresholdPx Minimum distance for gesture by fling.
-     * @param flingVelocityThresholdPx Minimum velocity for gesture by fling.
+     * Called when a touch is down and has been recognized as an overscroll gesture.
+     * A call of this method will always result in `onTouchUp` being called, and possibly
+     * `onFling` as well.
+     *
      * @param deviceState String representing the current device state
      * @param underlyingActivity String representing the currently active Activity
      */
-    void onTouchEvent(MotionEvent event,
-                      int horizontalDistancePx,
-                      int verticalDistancePx,
-                      int thresholdPx,
-                      int flingDistanceThresholdPx,
-                      int flingVelocityThresholdPx,
-                      String deviceState,
-                      String underlyingActivity);
+    void onTouchStart(String deviceState, String underlyingActivity);
 
     /**
-     * @return `true` if overscroll gesture handling should override all other gestures.
+     * Called when a touch that was previously recognized has moved.
+     *
+     * @param px distance between the position of touch on this update and the position of the
+     * touch when it was initially recognized.
      */
-    boolean blockOtherGestures();
+    void onTouchTraveled(int px);
 
     /**
-     * @return `true` if the overscroll gesture can pan the underlying app.
+     * Called when a touch that was previously recognized has ended.
+     *
+     * @param px distance between the position of touch on this update and the position of the
+     * touch when it was initially recognized.
      */
-    boolean allowsUnderlyingActivityOverscroll();
+    void onTouchEnd(int px);
+
+    /**
+     * Called when the user starts Compose with a fling. `onTouchUp` will also be called.
+     */
+    void onFling(float velocity);
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index dd170c5..ce7d39d 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -622,6 +622,8 @@
      * @return the Workspace object.
      */
     public Workspace pressHome() {
+        mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(
+                e -> Log.d("b/155926212", e.toString()));
         try (LauncherInstrumentation.Closable e = eventsCheck()) {
             // Click home, then wait for any accessibility event, then wait until accessibility
             // events stop.
@@ -629,7 +631,9 @@
             // otherwise waitForIdle may return immediately in case when there was a big enough
             // pause in accessibility events prior to pressing Home.
             final String action;
+            Log.d("b/155926212", "Before isLauncherVisible()");
             final boolean launcherWasVisible = isLauncherVisible();
+            Log.d("b/155926212", "After isLauncherVisible(): " + launcherWasVisible);
             if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
                 checkForAnomaly();
 
@@ -685,6 +689,8 @@
                     "performed action to switch to Home - " + action)) {
                 return getWorkspace();
             }
+        } finally {
+            mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(null);
         }
     }