Add tests where fling ends in snapped position

Adds a test for ViewPager2 where a fling (drag with velocity) ends
exactly at a page. This is added to the DragWhileSmoothScrollTest
because it can only be tested when the ViewPager2 is moved to a
non-snapped position before initiating the fling. This has the benefit
that this scenario is thoroughly tested with the different parameters.

Test: ./gradlew viewpager2:connectedCheck
Change-Id: I383065081794aa0aee45d002eedb13e18318c873
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index 9b308b1..192bc62 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -25,6 +25,7 @@
 import androidx.recyclerview.widget.RecyclerView
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.ViewInteraction
 import androidx.test.espresso.action.CoordinatesProvider
 import androidx.test.espresso.action.GeneralLocation
 import androidx.test.espresso.action.GeneralSwipeAction
@@ -35,6 +36,7 @@
 import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withParent
 import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.rule.ActivityTestRule
 import androidx.testutils.FragmentActivityUtils
@@ -374,6 +376,13 @@
         DESC(-1)
     }
 
+    fun onPage(childMatcher: Matcher<View>): ViewInteraction {
+        return onView(allOf(
+            withParent(withParent(isAssignableFrom(ViewPager2::class.java))),
+            childMatcher
+        ))
+    }
+
     fun <T, R : Comparable<R>> List<T>.assertSorted(selector: (T) -> R) {
         assertThat(this, equalTo(this.sortedBy(selector)))
     }
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
index d0a2831..e4ba599 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DragWhileSmoothScrollTest.kt
@@ -16,7 +16,9 @@
 
 package androidx.viewpager2.widget
 
+import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.filters.LargeTest
+import androidx.testutils.SwipeToLocation.flingToCenter
 import androidx.viewpager2.widget.BaseTest.Context.SwipeMethod
 import androidx.viewpager2.widget.DragWhileSmoothScrollTest.Event.OnPageScrollStateChangedEvent
 import androidx.viewpager2.widget.DragWhileSmoothScrollTest.Event.OnPageScrolledEvent
@@ -35,6 +37,8 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 import java.util.concurrent.TimeUnit.SECONDS
+import kotlin.math.ceil
+import kotlin.math.floor
 import kotlin.math.max
 
 /**
@@ -49,7 +53,8 @@
         val startPage: Int = 0,
         val targetPage: Int,
         val dragInOppositeDirection: Boolean,
-        val distanceToTargetWhenStartDrag: Float
+        val distanceToTargetWhenStartDrag: Float,
+        val endInSnappedPosition: Boolean = false
     )
 
     companion object {
@@ -78,7 +83,9 @@
                 waitTillCloseEnough.await(1, SECONDS)
 
                 // then perform a swipe
-                if (dragInOppositeDirection == movingForward) {
+                if (endInSnappedPosition) {
+                    onPage(withText("${pageToSnapTo(movingForward)}")).perform(flingToCenter())
+                } else if (dragInOppositeDirection == movingForward) {
                     swipeBackward(SwipeMethod.MANUAL)
                 } else {
                     swipeForward(SwipeMethod.MANUAL)
@@ -140,6 +147,19 @@
         return RecordingCallback().also { registerOnPageChangeCallback(it) }
     }
 
+    private fun TestConfig.pageToSnapTo(movingForward: Boolean): Int {
+        val positionToStartDragging = if (movingForward) {
+            targetPage - distanceToTargetWhenStartDrag
+        } else {
+            targetPage + distanceToTargetWhenStartDrag
+        }
+        return if (movingForward == dragInOppositeDirection) {
+            floor(positionToStartDragging).toInt()
+        } else {
+            ceil(positionToStartDragging).toInt()
+        }
+    }
+
     private sealed class Event {
         data class OnPageScrolledEvent(
             val position: Int,
@@ -198,7 +218,28 @@
     return listOf(ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL).flatMap { orientation ->
         listOf(true, false).flatMap { dragInOppositeDirection ->
             listOf(0.4f, 1.5f).flatMap { distanceToTarget ->
-                createTestSet(orientation, dragInOppositeDirection, distanceToTarget)
+                listOf(true, false).flatMap { endInSnappedPosition ->
+                    listOf(
+                        TestConfig(
+                            title = "forward",
+                            orientation = orientation,
+                            startPage = 0,
+                            targetPage = 4,
+                            dragInOppositeDirection = dragInOppositeDirection,
+                            distanceToTargetWhenStartDrag = distanceToTarget,
+                            endInSnappedPosition = endInSnappedPosition
+                        ),
+                        TestConfig(
+                            title = "backward",
+                            orientation = orientation,
+                            startPage = 8,
+                            targetPage = 4,
+                            dragInOppositeDirection = dragInOppositeDirection,
+                            distanceToTargetWhenStartDrag = distanceToTarget,
+                            endInSnappedPosition = endInSnappedPosition
+                        )
+                    )
+                }
             }
         }.plus(listOf(
             TestConfig(
@@ -213,29 +254,4 @@
     }
 }
 
-private fun createTestSet(
-    orientation: Int,
-    dragInOppositeDirection: Boolean,
-    distanceToTarget: Float
-): List<TestConfig> {
-    return listOf(
-        TestConfig(
-            title = "forward",
-            orientation = orientation,
-            startPage = 0,
-            targetPage = 4,
-            dragInOppositeDirection = dragInOppositeDirection,
-            distanceToTargetWhenStartDrag = distanceToTarget
-        ),
-        TestConfig(
-            title = "backward",
-            orientation = orientation,
-            startPage = 8,
-            targetPage = 4,
-            dragInOppositeDirection = dragInOppositeDirection,
-            distanceToTargetWhenStartDrag = distanceToTarget
-        )
-    )
-}
-
 // endregion