Revert "Cleanup Gesture selection."

This reverts commit 809b6acbcbef583825e6f80af0e877fa946b9233.

Reason for revert: Caused regression.

https://b.corp.google.com/issues/78615740

Change-Id: Ic23a08352d3b183518ef90460129099cb65668d8

Bug: 78615740
diff --git a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java b/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
index d84cb83..de50953 100644
--- a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
+++ b/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
@@ -18,7 +18,6 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.view.MotionEvent;
 
@@ -26,7 +25,7 @@
 import androidx.recyclerview.selection.testing.SelectionTrackers;
 import androidx.recyclerview.selection.testing.TestAutoScroller;
 import androidx.recyclerview.selection.testing.TestEvents;
-import androidx.recyclerview.selection.testing.TestSelectionPredicate;
+import androidx.recyclerview.selection.testing.TestItemDetailsLookup;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -56,7 +55,7 @@
 
     private GestureSelectionHelper mHelper;
     private SelectionTracker<String> mSelectionTracker;
-    private TestSelectionPredicate<String> mSelectionPredicate;
+    private TestItemDetailsLookup mDetailsLookup;
     private SelectionProbe mSelection;
     private OperationMonitor mMonitor;
     private TestViewDelegate mView;
@@ -64,14 +63,13 @@
     @Before
     public void setUp() {
         mSelectionTracker = SelectionTrackers.createStringTracker("gesture-selection-test", 100);
-        mSelectionPredicate = new TestSelectionPredicate<>();
+        mDetailsLookup = new TestItemDetailsLookup();
+        mDetailsLookup.initAt(3);
         mSelection = new SelectionProbe(mSelectionTracker);
         mMonitor = new OperationMonitor();
         mView = new TestViewDelegate();
         mHelper = new GestureSelectionHelper(
-                mSelectionTracker, mSelectionPredicate, mView, new TestAutoScroller(), mMonitor);
-
-        mSelectionPredicate.setReturnValue(true);
+                mSelectionTracker, mDetailsLookup, mView, new TestAutoScroller(), mMonitor);
     }
 
     @Test
@@ -82,26 +80,16 @@
 
     @Test
     public void testIgnoresDown_NoItemDetails() {
+        mDetailsLookup.reset();
         assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
     }
 
     @Test
-    public void testThrowsWhenStartingWithoutRange() {
-        mView.mNextPosition = 0;
-
-        // Normally, this is controller by the TouchSelectionHelper via a a long press gesture.
-        mSelectionTracker.select("1");
-        // If mSelectionTracker.anchorRange(1) didn't initialize the range, then start
-        // should throw an exception.
-        try {
-            mHelper.start();
-            fail("Should have thrown IllegalStateException.");
-        } catch (IllegalStateException expected) { }
-    }
-
-    @Test
-    public void testIgnoresEventsWhenNotStarted() {
-        assertFalse(mHelper.onInterceptTouchEvent(null, MOVE));
+    public void testNoStartOnIllegalPosition() {
+        mView.mNextPosition = RecyclerView.NO_POSITION;
+        mHelper.onInterceptTouchEvent(null, DOWN);
+        mHelper.start();
+        assertFalse(mMonitor.isStarted());
     }
 
     @Test
@@ -113,12 +101,14 @@
     @Test
     public void testClaimsMoveIfStarted() {
         mView.mNextPosition = 0;
+        // TODO(b/109808552): This should be removed with that bug is fixed because it will be a
+        // no-op at that time.
+        mHelper.onInterceptTouchEvent(null, DOWN);
 
         // Normally, this is controller by the TouchSelectionHelper via a a long press gesture.
         mSelectionTracker.select("1");
         mSelectionTracker.anchorRange(1);
         mHelper.start();
-
         assertTrue(mHelper.onInterceptTouchEvent(null, MOVE));
     }
 
@@ -132,7 +122,6 @@
 
         mSelectionTracker.select("1");
         mSelectionTracker.anchorRange(1);
-
         mHelper.start();
 
         mHelper.onTouchEvent(null, MOVE);
@@ -141,7 +130,7 @@
         mHelper.onTouchEvent(null, MOVE);
         mHelper.onTouchEvent(null, UP);
 
-        mSelection.assertRangeSelected(1, 9);
+        mSelection.assertRangeSelected(1,  9);
     }
 
     private static final class TestViewDelegate extends GestureSelectionHelper.ViewDelegate {
diff --git a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/TouchInputHandlerTest.java b/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/TouchInputHandlerTest.java
index 15fe7e3..b4cbf4a 100644
--- a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/TouchInputHandlerTest.java
+++ b/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/TouchInputHandlerTest.java
@@ -20,12 +20,13 @@
 
 import static org.junit.Assert.assertFalse;
 
+import android.view.MotionEvent;
+
 import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
 import androidx.recyclerview.selection.testing.SelectionProbe;
 import androidx.recyclerview.selection.testing.SelectionTrackers;
 import androidx.recyclerview.selection.testing.TestAdapter;
 import androidx.recyclerview.selection.testing.TestData;
-import androidx.recyclerview.selection.testing.TestDragListener;
 import androidx.recyclerview.selection.testing.TestFocusDelegate;
 import androidx.recyclerview.selection.testing.TestItemDetailsLookup;
 import androidx.recyclerview.selection.testing.TestItemKeyProvider;
@@ -53,10 +54,11 @@
     private TestSelectionPredicate mSelectionPredicate;
     private TestRunnable mGestureStarted;
     private TestRunnable mHapticPerformer;
+    private TestDragListener mOnItemDragListener;
     private TestOnItemActivatedListener mActivationCallbacks;
+    private TestFocusDelegate mFocusCallbacks;
     private TestItemDetailsLookup mDetailsLookup;
     private SelectionProbe mSelection;
-    private TestDragListener mDragInitiatedListener;
 
     @Before
     public void setUp() {
@@ -66,8 +68,9 @@
         mSelection = new SelectionProbe(mSelectionMgr);
         mGestureStarted = new TestRunnable();
         mHapticPerformer = new TestRunnable();
+        mOnItemDragListener = new TestDragListener();
         mActivationCallbacks = new TestOnItemActivatedListener();
-        mDragInitiatedListener = new TestDragListener();
+        mFocusCallbacks = new TestFocusDelegate();
 
         mInputDelegate = new TouchInputHandler(
                 mSelectionMgr,
@@ -77,16 +80,15 @@
                 mDetailsLookup,
                 mSelectionPredicate,
                 mGestureStarted,
-                mDragInitiatedListener,
+                mOnItemDragListener,
                 mActivationCallbacks,
-                new TestFocusDelegate(),
+                mFocusCallbacks,
                 mHapticPerformer);
     }
 
     @Test
     public void testTap_ActivatesWhenNoExistingSelection() {
         ItemDetails doc = mDetailsLookup.initAt(11);
-
         mInputDelegate.onSingleTapUp(TAP);
 
         mActivationCallbacks.assertActivated(doc);
@@ -98,69 +100,26 @@
     }
 
     @Test
-    public void testLongPress_UnselectedItem_Selects() {
+    public void testLongPress_SelectsItem() {
         mSelectionPredicate.setReturnValue(true);
-        mDetailsLookup.initAt(7);
 
+        mDetailsLookup.initAt(7);
         mInputDelegate.onLongPress(TAP);
 
         mSelection.assertSelection(7);
     }
 
     @Test
-    public void testLongPress_UnselectedItem_PerformsHapticFeedback() {
+    public void testLongPress_StartsGestureSelection() {
         mSelectionPredicate.setReturnValue(true);
+
         mDetailsLookup.initAt(7);
-
         mInputDelegate.onLongPress(TAP);
-
-        mHapticPerformer.assertRan();
-    }
-
-    @Test
-    public void testLongPress_UnselectedItem_StartsGestureSelection() {
-        mSelectionPredicate.setReturnValue(true);
-        mDetailsLookup.initAt(7);
-
-        mInputDelegate.onLongPress(TAP);
-
         mGestureStarted.assertRan();
     }
 
     @Test
-    public void testLongPress_UnselectedItem_DoesNotInitiateDrag() {
-        mSelectionPredicate.setReturnValue(true);
-        mDetailsLookup.initAt(7);
-
-        mInputDelegate.onLongPress(TAP);
-
-        mDragInitiatedListener.assertDragInitiated(false);
-    }
-
-    @Test
-    public void testLongPress_SelectedItem_InitiatesDrag() {
-        mSelectionPredicate.setReturnValue(true);
-        mSelectionMgr.select("7");
-        mDetailsLookup.initAt(7);
-
-        mInputDelegate.onLongPress(TAP);
-
-        mDragInitiatedListener.assertDragInitiated(true);
-    }
-
-    @Test
-    public void testLongPress_SelectedItem_PerformsHapticFeedback() {
-        mSelectionPredicate.setReturnValue(true);
-        mSelectionMgr.select("7");
-        mDetailsLookup.initAt(7);
-
-        mInputDelegate.onLongPress(TAP);
-
-        mHapticPerformer.assertRan();
-    }
-
-    @Test
-    public void testTapSelectHotspot_UnselectedItem_Selections() {
+    public void testSelectHotspot_StartsSelectionMode() {
         mSelectionPredicate.setReturnValue(true);
 
         mDetailsLookup.initAt(7).setInItemSelectRegion(true);
@@ -170,7 +129,7 @@
     }
 
     @Test
-    public void testTapSelectionHotspot_SelectedItem_Unselected() {
+    public void testSelectionHotspot_UnselectsSelectedItem() {
         mSelectionMgr.select("11");
 
         mDetailsLookup.initAt(11).setInItemSelectRegion(true);
@@ -180,6 +139,16 @@
     }
 
     @Test
+    public void testStartsSelection_PerformsHapticFeedback() {
+        mSelectionPredicate.setReturnValue(true);
+
+        mDetailsLookup.initAt(7);
+        mInputDelegate.onLongPress(TAP);
+
+        mHapticPerformer.assertRan();
+    }
+
+    @Test
     public void testLongPress_AddsToSelection() {
         mSelectionPredicate.setReturnValue(true);
 
@@ -221,4 +190,11 @@
 
         mSelection.assertNoSelection();
     }
+
+    private static final class TestDragListener implements OnDragInitiatedListener {
+        @Override
+        public boolean onDragInitiated(MotionEvent e) {
+            return false;
+        }
+    }
 }
diff --git a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestDragListener.java b/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestDragListener.java
deleted file mode 100644
index 643c779..0000000
--- a/recyclerview/selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestDragListener.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 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 androidx.recyclerview.selection.testing;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.view.MotionEvent;
-
-import androidx.recyclerview.selection.OnDragInitiatedListener;
-
-public final class TestDragListener implements OnDragInitiatedListener {
-
-    private boolean mDragInitiated;
-
-    @Override
-    public boolean onDragInitiated(MotionEvent e) {
-        mDragInitiated = true;
-        return false;
-    }
-
-    public void assertDragInitiated(boolean expected) {
-        if (expected) {
-            assertTrue("onDragInitiated never called.", mDragInitiated);
-        } else {
-            assertFalse("onDragInitiated called, but should not have.", mDragInitiated);
-        }
-    }
-}
diff --git a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
index 7f2a5bb..f127576 100644
--- a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
+++ b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
@@ -19,6 +19,7 @@
 import static androidx.core.util.Preconditions.checkArgument;
 import static androidx.core.util.Preconditions.checkState;
 
+import android.graphics.Point;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -26,7 +27,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.view.ViewCompat;
-import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
 
@@ -41,11 +41,12 @@
     private static final String TAG = "GestureSelectionHelper";
 
     private final SelectionTracker<?> mSelectionMgr;
-    private final SelectionTracker.SelectionPredicate<?> mSelectionPredicate;
+    private final ItemDetailsLookup<?> mDetailsLookup;
     private final AutoScroller mScroller;
     private final ViewDelegate mView;
     private final OperationMonitor mLock;
 
+    private int mLastStartedItemPos = RecyclerView.NO_POSITION;
     private boolean mStarted = false;
 
     /**
@@ -54,19 +55,19 @@
      */
     GestureSelectionHelper(
             @NonNull SelectionTracker<?> selectionTracker,
-            @NonNull SelectionPredicate<?> selectionPredicate,
+            @NonNull ItemDetailsLookup<?> detailsLookup,
             @NonNull ViewDelegate view,
             @NonNull AutoScroller scroller,
             @NonNull OperationMonitor lock) {
 
         checkArgument(selectionTracker != null);
-        checkArgument(selectionPredicate != null);
+        checkArgument(detailsLookup != null);
         checkArgument(view != null);
         checkArgument(scroller != null);
         checkArgument(lock != null);
 
         mSelectionMgr = selectionTracker;
-        mSelectionPredicate = selectionPredicate;
+        mDetailsLookup = detailsLookup;
         mView = view;
         mScroller = scroller;
         mLock = lock;
@@ -77,9 +78,16 @@
      */
     void start() {
         checkState(!mStarted);
+        // See: b/70518185. It appears start() is being called via onLongPress
+        // even though we never received an intial handleInterceptedDownEvent
+        // where we would usually initialize mLastStartedItemPos.
+        if (mLastStartedItemPos == RecyclerView.NO_POSITION) {
+            Log.w(TAG, "Illegal state. Can't start without valid mLastStartedItemPos.");
+            return;
+        }
 
         // Partner code in MotionInputHandler ensures items
-        // are selected and range anchor initialized prior to
+        // are selected and range established prior to
         // start being called.
         // Verify the truth of that statement here
         // to make the implicit coupling less of a time bomb.
@@ -94,14 +102,20 @@
     @Override
     /** @hide */
     public boolean onInterceptTouchEvent(@NonNull RecyclerView unused, @NonNull MotionEvent e) {
-        switch (e.getActionMasked()) {
-            case MotionEvent.ACTION_MOVE:
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                return mStarted;
-            default:
-                return false;
+        if (MotionEvents.isMouseEvent(e)) {
+            if (Shared.DEBUG) Log.w(TAG, "Unexpected Mouse event. Check configuration.");
         }
+
+        // TODO(b/109808552): It seems that mLastStartedItemPos should likely be set as a method
+        // parameter in start().
+        if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            if (mDetailsLookup.getItemDetails(e) != null) {
+                mLastStartedItemPos = mView.getItemUnder(e);
+            }
+        }
+
+        // See handleTouch(MotionEvent) javadoc for explanation as to why this is correct.
+        return handleTouch(e);
     }
 
     @Override
@@ -132,14 +146,6 @@
             return false;
         }
 
-        if (!mSelectionMgr.isRangeActive()) {
-            Log.e(TAG,
-                    "Internal state of GestureSelectionHelper out of sync w/ SelectionTracker "
-                            + "(isRangeActive is false). Ignoring event and resetting state.");
-            endSelection();
-            return false;
-        }
-
         switch (e.getActionMasked()) {
             case MotionEvent.ACTION_MOVE:
                 handleMoveEvent(e);
@@ -166,6 +172,9 @@
     private void handleUpEvent() {
         mSelectionMgr.mergeProvisionalSelection();
         endSelection();
+        if (mLastStartedItemPos != RecyclerView.NO_POSITION) {
+            mSelectionMgr.startRange(mLastStartedItemPos);
+        }
     }
 
     // Called when ACTION_CANCEL event is to be handled.
@@ -179,6 +188,7 @@
     private void endSelection() {
         checkState(mStarted);
 
+        mLastStartedItemPos = RecyclerView.NO_POSITION;
         mStarted = false;
         mScroller.reset();
         mLock.stop();
@@ -187,12 +197,14 @@
     // Call when an intercepted ACTION_MOVE event is passed down.
     // At this point, we are sure user wants to gesture multi-select.
     private void handleMoveEvent(@NonNull MotionEvent e) {
+        Point lastInterceptedPoint = MotionEvents.getOrigin(e);
+
         int lastGlidedItemPos = mView.getLastGlidedItemPosition(e);
-        if (mSelectionPredicate.canSetStateAtPosition(lastGlidedItemPos, true)) {
+        if (lastGlidedItemPos != RecyclerView.NO_POSITION) {
             extendSelection(lastGlidedItemPos);
         }
 
-        mScroller.scroll(MotionEvents.getOrigin(e));
+        mScroller.scroll(lastInterceptedPoint);
     }
 
     // It's possible for events to go over the top/bottom of the RecyclerView.
@@ -220,14 +232,14 @@
      */
     static GestureSelectionHelper create(
             @NonNull SelectionTracker<?> selectionMgr,
-            @NonNull SelectionPredicate<?> selectionPredicate,
+            @NonNull ItemDetailsLookup<?> detailsLookup,
             @NonNull RecyclerView recyclerView,
             @NonNull AutoScroller scroller,
             @NonNull OperationMonitor lock) {
 
         return new GestureSelectionHelper(
                 selectionMgr,
-                selectionPredicate,
+                detailsLookup,
                 new RecyclerViewDelegate(recyclerView),
                 scroller,
                 lock);
diff --git a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java
index 0a3d324..a7eb208 100644
--- a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java
+++ b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MotionInputHandler.java
@@ -88,7 +88,7 @@
         mFocusDelegate.focusItem(details);
     }
 
-    final boolean shouldExtendRange(@NonNull MotionEvent e) {
+    final boolean isRangeExtension(@NonNull MotionEvent e) {
         return MotionEvents.isShiftKeyPressed(e)
                 && mSelectionTracker.isRangeActive()
                 // Without full corpus access we can't reliably implement range
diff --git a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
index e4f4548..ca45137 100644
--- a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
+++ b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/MouseInputHandler.java
@@ -126,7 +126,7 @@
         checkState(mSelectionTracker.hasSelection());
         checkArgument(item != null);
 
-        if (shouldExtendRange(e)) {
+        if (isRangeExtension(e)) {
             extendSelectionRange(item);
         } else {
             if (shouldClearSelection(e, item)) {
diff --git a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
index 4e3a932..bd63fd6 100644
--- a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
+++ b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
@@ -711,7 +711,7 @@
             // of motions and gestures in order to provide gesture driven selection support
             // when used in conjunction with RecyclerView.
             final GestureSelectionHelper gestureHelper = GestureSelectionHelper.create(
-                    tracker, mSelectionPredicate, mRecyclerView, scroller, mMonitor);
+                    tracker, mDetailsLookup, mRecyclerView, scroller, mMonitor);
 
             // Finally hook the framework up to listening to recycle view events.
             mRecyclerView.addOnItemTouchListener(eventRouter);
diff --git a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java
index d82812c..271ff3c 100644
--- a/recyclerview/selection/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java
+++ b/recyclerview/selection/src/main/java/androidx/recyclerview/selection/TouchInputHandler.java
@@ -88,7 +88,7 @@
         }
 
         if (mSelectionTracker.hasSelection()) {
-            if (shouldExtendRange(e)) {
+            if (isRangeExtension(e)) {
                 extendSelectionRange(item);
             } else if (mSelectionTracker.isSelected(item.getSelectionKey())) {
                 mSelectionTracker.deselect(item.getSelectionKey());
@@ -121,26 +121,32 @@
 
         boolean handled = false;
 
-        if (shouldExtendRange(e)) {
+        if (isRangeExtension(e)) {
             extendSelectionRange(item);
-            mHapticPerformer.run();
+            handled = true;
         } else {
-            if (mSelectionTracker.isSelected(item.getSelectionKey())) {
-                // Long press on existing selected item initiates drag/drop.
-                mOnDragInitiatedListener.onDragInitiated(e);
-                mHapticPerformer.run();
-            } else if (mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true)
-                    && selectItem(item)) {
-                // And finally if the item was selected && we can select multiple
-                // we kick off gesture selection.
-                // NOTE: isRangeActive should ALWAYS be true at this point, but there have
-                // been reports indicating that assumption isn't correct. So we explicitly
-                // check isRangeActive.
-                if (mSelectionPredicate.canSelectMultiple() && mSelectionTracker.isRangeActive()) {
-                    mGestureStarter.run();
+            if (!mSelectionTracker.isSelected(item.getSelectionKey())
+                    && mSelectionPredicate.canSetStateForKey(item.getSelectionKey(), true)) {
+                // If we cannot select it, we didn't apply anchoring - therefore should not
+                // start gesture selection
+                if (selectItem(item)) {
+                    // And finally if the item was selected && we can select multiple
+                    // we kick off gesture selection.
+                    if (mSelectionPredicate.canSelectMultiple()) {
+                        mGestureStarter.run();
+                    }
+                    handled = true;
                 }
-                mHapticPerformer.run();
+            } else {
+                // We only initiate drag and drop on long press for touch to allow regular
+                // touch-based scrolling
+                mOnDragInitiatedListener.onDragInitiated(e);
+                handled = true;
             }
         }
+
+        if (handled) {
+            mHapticPerformer.run();
+        }
     }
 }