Tests for requestDisallowInterceptTouchEvents

Bug: 185906621

When overscrolling, there is no need to call
disallowInterceptTouchEvents(). A test was added to ensure that
it isn't called during the touch down while the animation
is progressing.

Test: new test

Change-Id: Ia9ac6d81a5b60222f489ea87f31ecba0c1d48cea
(cherry picked from commit 044c71b8fab8ea16400dbbb01604ce0cc894c6f8)
diff --git a/tests/tests/widget/res/layout/horizontal_scrollview.xml b/tests/tests/widget/res/layout/horizontal_scrollview.xml
index 2acd77f..c535722 100644
--- a/tests/tests/widget/res/layout/horizontal_scrollview.xml
+++ b/tests/tests/widget/res/layout/horizontal_scrollview.xml
@@ -121,40 +121,46 @@
         android:layout_width="100px"
         android:layout_height="100px" />
 
-    <HorizontalScrollView
-        android:id="@+id/horizontal_scroll_view_stretch"
-        android:layout_width="90px"
-        android:layout_height="90px"
-        android:edgeEffectType="stretch"
-        android:background="#FFF">
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <View
-                android:background="#00F"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-            <View
-                android:background="#0FF"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-            <View
-                android:background="#0F0"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-            <View
-                android:background="#FF0"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-            <View
-                android:background="#F00"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-            <View
-                android:background="#F0F"
-                android:layout_width="50px"
-                android:layout_height="90px"/>
-        </LinearLayout>
-    </HorizontalScrollView>
+    <view
+        class="android.widget.cts.HorizontalScrollViewTest$InterceptView"
+        android:id="@+id/wrapped_stretch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <HorizontalScrollView
+            android:id="@+id/horizontal_scroll_view_stretch"
+            android:layout_width="90px"
+            android:layout_height="90px"
+            android:edgeEffectType="stretch"
+            android:background="#FFF">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+                <View
+                    android:background="#00F"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+                <View
+                    android:background="#0FF"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+                <View
+                    android:background="#0F0"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+                <View
+                    android:background="#FF0"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+                <View
+                    android:background="#F00"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+                <View
+                    android:background="#F0F"
+                    android:layout_width="50px"
+                    android:layout_height="90px"/>
+            </LinearLayout>
+        </HorizontalScrollView>
+    </view>
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/scrollview_layout.xml b/tests/tests/widget/res/layout/scrollview_layout.xml
index 47cf600..8ff83f8 100644
--- a/tests/tests/widget/res/layout/scrollview_layout.xml
+++ b/tests/tests/widget/res/layout/scrollview_layout.xml
@@ -120,43 +120,49 @@
         class="android.widget.cts.ScrollViewTest$MyScrollView"
         android:id="@+id/scroll_view_custom_empty"
         android:layout_width="100dip"
-        android:layout_height="100dip" />
+        android:layout_height="100dip"/>
 
-    <ScrollView
-        android:id="@+id/scroll_view_stretch"
-        android:layout_width="90px"
-        android:layout_height="90px"
-        android:edgeEffectType="stretch"
-        android:background="#FFF">
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-            <View
-                android:background="#00F"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-            <View
-                android:background="#0FF"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-            <View
-                android:background="#0F0"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-            <View
-                android:background="#FF0"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-            <View
-                android:background="#F00"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-            <View
-                android:background="#F0F"
-                android:layout_width="90px"
-                android:layout_height="50px"/>
-        </LinearLayout>
-    </ScrollView>
+    <view
+        class="android.widget.cts.ScrollViewTest$InterceptView"
+        android:id="@+id/wrapped_stretch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <ScrollView
+            android:id="@+id/scroll_view_stretch"
+            android:layout_width="90px"
+            android:layout_height="90px"
+            android:edgeEffectType="stretch"
+            android:background="#FFF">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <View
+                    android:background="#00F"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+                <View
+                    android:background="#0FF"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+                <View
+                    android:background="#0F0"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+                <View
+                    android:background="#FF0"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+                <View
+                    android:background="#F00"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+                <View
+                    android:background="#F0F"
+                    android:layout_width="90px"
+                    android:layout_height="50px"/>
+            </LinearLayout>
+        </ScrollView>
+    </view>
 </LinearLayout>
 
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index a93d864..2b35073 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static android.widget.cts.util.StretchEdgeUtil.dragHoldAndRun;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertSame;
@@ -60,6 +62,8 @@
 
 import java.util.ArrayList;
 
+import kotlin.Unit;
+
 /**
  * Test {@link HorizontalScrollView}.
  */
@@ -868,6 +872,32 @@
         assertTrue(StretchEdgeUtil.dragLeftTapAndHoldStretches(mActivityRule, mScrollViewStretch));
     }
 
+    @LargeTest
+    @Test
+    public void testRequestDisallowInterceptTouchEventNotCalled() throws Throwable {
+        // Make sure that the scroll view we care about is on screen and at the top:
+        showOnlyStretch();
+
+        InterceptView interceptView = mActivity.findViewById(R.id.wrapped_stretch);
+        dragHoldAndRun(
+                mActivityRule,
+                mScrollViewStretch,
+                mScrollViewStretch.getWidth() / 2,
+                mScrollViewStretch.getHeight() / 2,
+                300,
+                0,
+                () -> {
+                    interceptView.requestDisallowInterceptCalled = false;
+                    return Unit.INSTANCE;
+                },
+                () -> Unit.INSTANCE
+        );
+
+        mActivityRule.runOnUiThread(
+                () -> assertFalse(interceptView.requestDisallowInterceptCalled)
+        );
+    }
+
     private void showOnlyStretch() throws Throwable {
         mActivityRule.runOnUiThread(() -> {
             mScrollViewCustom.setVisibility(View.GONE);
@@ -1015,4 +1045,26 @@
             return super.computeVerticalScrollExtent();
         }
     }
+
+    public static class InterceptView extends FrameLayout {
+        public boolean requestDisallowInterceptCalled = false;
+
+        public InterceptView(Context context) {
+            super(context);
+        }
+
+        public InterceptView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public InterceptView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+            requestDisallowInterceptCalled = true;
+            super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 1d75886..d94b491 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static android.widget.cts.util.StretchEdgeUtil.dragHoldAndRun;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertSame;
@@ -58,6 +60,8 @@
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 
+import kotlin.Unit;
+
 /**
  * Test {@link ScrollView}.
  */
@@ -882,6 +886,32 @@
         assertTrue(StretchEdgeUtil.dragDownTapAndHoldStretches(mActivityRule, mScrollViewStretch));
     }
 
+    @LargeTest
+    @Test
+    public void testRequestDisallowInterceptTouchEventNotCalled() throws Throwable {
+        // Make sure that the scroll view we care about is on screen and at the top:
+        showOnlyStretch();
+
+        InterceptView interceptView = mActivity.findViewById(R.id.wrapped_stretch);
+        Unit result = dragHoldAndRun(
+                mActivityRule,
+                mScrollViewStretch,
+                mScrollViewStretch.getWidth() / 2,
+                mScrollViewStretch.getHeight() / 2,
+                0,
+                300,
+                () -> {
+                    interceptView.requestDisallowInterceptCalled = false;
+                    return Unit.INSTANCE;
+                },
+                () -> Unit.INSTANCE
+        );
+
+        mActivityRule.runOnUiThread(
+                () -> assertFalse(interceptView.requestDisallowInterceptCalled)
+        );
+    }
+
     @Test
     public void testStretchAtBottom() throws Throwable {
         // Make sure that the scroll view we care about is on screen and at the top:
@@ -1038,4 +1068,26 @@
                     parentHeightMeasureSpec, heightUsed);
         }
     }
+
+    public static class InterceptView extends FrameLayout {
+        public boolean requestDisallowInterceptCalled = false;
+
+        public InterceptView(Context context) {
+            super(context);
+        }
+
+        public InterceptView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public InterceptView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+            requestDisallowInterceptCalled = true;
+            super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/util/StretchEdgeUtil.kt b/tests/tests/widget/src/android/widget/cts/util/StretchEdgeUtil.kt
index 8aa68ee..ff744b0 100644
--- a/tests/tests/widget/src/android/widget/cts/util/StretchEdgeUtil.kt
+++ b/tests/tests/widget/src/android/widget/cts/util/StretchEdgeUtil.kt
@@ -84,7 +84,7 @@
  * Drags an area of the screen and executes [onFinalMove] after sending the final drag
  * motion and [onUp] after the drag up event has been sent.
  */
-private fun dragAndExecute(
+public fun dragAndExecute(
     activityRule: ActivityTestRule<*>,
     screenX: Int,
     screenY: Int,
@@ -162,7 +162,7 @@
 /**
  * Drags in [view], starting at coordinates ([viewX], [viewY]) relative to [view] and moving
  * ([deltaX], [deltaY]) pixels before lifting. Immediately after the up event, a down event
- * is sent. If it happens within 400 milliseconds of the last motion event, the Bitmap is captured
+ * is sent. If it happens within 50 milliseconds of the last motion event, the Bitmap is captured
  * after 600ms more. If an animation was going to run, this allows that animation to finish before
  * capturing the Bitmap. This is attempted up to 5 times.
  *
@@ -185,12 +185,59 @@
     val screenX = locationOnScreen[0]
     val screenY = locationOnScreen[1]
 
+    return dragHoldAndRun(
+            activityRule,
+            view,
+            viewX,
+            viewY,
+            deltaX,
+            deltaY
+    ) {
+        takeScreenshot(
+                activityRule.activity.window,
+                screenX,
+                screenY,
+                view.width,
+                view.height
+        )
+    }
+}
+
+/**
+ * Drags in [view], starting at coordinates ([viewX], [viewY]) relative to [view] and moving
+ * ([deltaX], [deltaY]) pixels before lifting. Immediately after the up event,
+ * [runBeforeTapDown] is called and then a down event is sent. If it happens within 50 milliseconds
+ * of the last motion event, [runAfterTapDown] is run after 600ms more. If an animation was going
+ * to run, this allows that animation to finish before [runAfterTapDown] is executed.
+ * This is attempted up to 5 times.
+ *
+ * @return The return value from [runAfterTapDown] or `null` if the device did not respond quickly
+ * enough.
+ */
+fun <T> dragHoldAndRun(
+    activityRule: ActivityTestRule<*>,
+    view: View,
+    viewX: Int,
+    viewY: Int,
+    deltaX: Int,
+    deltaY: Int,
+    runBeforeTapDown: () -> Unit = {},
+    runAfterTapDown: () -> T
+): T? {
+    val locationOnScreen = IntArray(2)
+    activityRule.runOnUiThread {
+        view.getLocationOnScreen(locationOnScreen)
+    }
+
+    val screenX = locationOnScreen[0]
+    val screenY = locationOnScreen[1]
+
     val instrumentation = InstrumentationRegistry.getInstrumentation()
 
     // Try 5 times at most. If it fails, just return the null bitmap
     repeat(5) {
         var lastMotion = 0L
-        var bitmap: Bitmap? = null
+        var returnValue: T? = null
         dragAndExecute(
                 activityRule = activityRule,
                 screenX = screenX + viewX,
@@ -202,6 +249,7 @@
                 },
                 onUp = {
                     // Now press
+                    runBeforeTapDown()
                     CtsTouchUtils.injectDownEvent(instrumentation.getUiAutomation(),
                             SystemClock.uptimeMillis(), screenX + viewX,
                             screenY + viewY, null)
@@ -215,13 +263,7 @@
                         // Now make sure that we wait until the release should normally have finished:
                         sleepAnimationTime(600)
 
-                        bitmap = takeScreenshot(
-                                activityRule.activity.window,
-                                screenX,
-                                screenY,
-                                view.width,
-                                view.height
-                        )
+                        returnValue = runAfterTapDown()
                     }
                 }
         )
@@ -230,8 +272,8 @@
                 SystemClock.uptimeMillis(), false,
                 screenX + viewX, screenY + viewY, null)
 
-        if (bitmap != null) {
-            return bitmap // success!
+        if (returnValue != null) {
+            return returnValue // success!
         }
     }
     return null // timing didn't allow for success this time, so return a null