Convert GridLayoutManagerSnappingTest to Kotlin
Bug: 244324972
Test: Commented the @Ignore on snapOnScrollSameView and ran a few
variants of it. Results looked the same as expected
(including some failures).
Relying on presubmit to check the rest.
Change-Id: I776f73c6bc89dea834a55c4627a129fedeb27425
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.java
deleted file mode 100644
index 41b5cf7..0000000
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright 2018 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.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.SdkSuppress;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@LargeTest
-@RunWith(Parameterized.class)
-public class GridLayoutManagerSnappingTest extends BaseGridLayoutManagerTest {
-
- final Config mConfig;
- private final boolean mReverseScroll;
- private final boolean mApplyPadding;
-
- public GridLayoutManagerSnappingTest(Config config, boolean reverseScroll,
- boolean applyPadding) {
- mConfig = config;
- mReverseScroll = reverseScroll;
- mApplyPadding = applyPadding;
- }
-
- @Parameterized.Parameters(name = "config:{0},reverseScroll:{1},applyPadding:{2}")
- public static List<Object[]> getParams() {
- List<Object[]> result = new ArrayList<>();
- List<Config> configs = createBaseVariations();
- for (Config config : configs) {
- for (boolean reverseScroll : new boolean[] {true, false}) {
- for (boolean applyPadding : new boolean[] {true, false}) {
- result.add(new Object[]{config, reverseScroll, applyPadding});
- }
- }
- }
- return result;
- }
-
- @Override
- public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable {
- RecyclerView rv = super.setupBasic(config, testAdapter);
- if (mApplyPadding) {
- rv.setPadding(17, 23, 0, 0);
- }
- return rv;
- }
-
- @Ignore // b/244324972
- @Test
- public void snapOnScrollSameView() throws Throwable {
- final Config config = (Config) mConfig.clone();
- RecyclerView recyclerView = setupBasic(config);
- waitForFirstLayout(recyclerView);
- setupSnapHelper();
-
- // Record the current center view.
- View view = findCenterView();
- assertCenterAligned(view);
- int scrollDistance = (getViewDimension(view) / 2) - 1;
- int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
- mGlm.expectIdleState(2);
- smoothScrollBy(scrollDist);
- mGlm.waitForSnap(25);
-
- // Views have not changed
- View viewAfterFling = findCenterView();
- assertSame("The view should have scrolled", view, viewAfterFling);
- assertCenterAligned(viewAfterFling);
- }
-
- @SdkSuppress(minSdkVersion = 22) // b/271599012
- @Test
- public void snapOnScrollNextItem() throws Throwable {
- final Config config = (Config) mConfig.clone();
- RecyclerView recyclerView = setupBasic(config);
- waitForFirstLayout(recyclerView);
- setupSnapHelper();
-
- // Record the current center view.
- View view = findCenterView();
- assertCenterAligned(view);
- CharSequence viewText = ((TextView) view).getText();
-
- int scrollDistance = getViewDimension(view) + 1;
- int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
-
- smoothScrollBy(scrollDist);
- waitForIdleScroll(mRecyclerView);
- waitForIdleScroll(mRecyclerView);
-
- View viewAfterScroll = findCenterView();
- CharSequence viewAfterFlingText = ((TextView) viewAfterScroll).getText();
-
- assertNotEquals("The view should have scrolled!", viewText, viewAfterFlingText);
- assertCenterAligned(viewAfterScroll);
- }
-
- @SdkSuppress(minSdkVersion = 22) // b/271599012
- @Test
- public void snapOnFlingSameView() throws Throwable {
- final Config config = (Config) mConfig.clone();
- RecyclerView recyclerView = setupBasic(config);
- waitForFirstLayout(recyclerView);
- setupSnapHelper();
-
- // Record the current center view.
- View view = findCenterView();
- assertCenterAligned(view);
-
- // Velocity small enough to not scroll to the next view.
- int velocity = (int) (1.000001 * mRecyclerView.getMinFlingVelocity());
- int velocityDir = mReverseScroll ? -velocity : velocity;
- mGlm.expectIdleState(2);
- assertTrue(fling(velocityDir, velocityDir));
- // Wait for two settling scrolls: the initial one and the corrective one.
- waitForIdleScroll(mRecyclerView);
- mGlm.waitForSnap(100);
-
- View viewAfterFling = findCenterView();
-
- assertSame("The view should NOT have scrolled", view, viewAfterFling);
- assertCenterAligned(viewAfterFling);
- }
-
- @SdkSuppress(minSdkVersion = 22) // b/271599012
- @Test
- public void snapOnFlingNextView() throws Throwable {
- final Config config = (Config) mConfig.clone();
- RecyclerView recyclerView = setupBasic(config);
- waitForFirstLayout(recyclerView);
- setupSnapHelper();
-
- // Record the current center view.
- View view = findCenterView();
- assertCenterAligned(view);
- CharSequence viewText = ((TextView) view).getText();
-
- // Velocity high enough to scroll beyond the current view.
- int velocity = (int) (0.25 * mRecyclerView.getMaxFlingVelocity());
- int velocityDir = mReverseScroll ? -velocity : velocity;
-
- mGlm.expectIdleState(1);
- assertTrue(fling(velocityDir, velocityDir));
- mGlm.waitForSnap(100);
- getInstrumentation().waitForIdleSync();
-
- View viewAfterFling = findCenterView();
- CharSequence viewAfterFlingText = ((TextView) viewAfterFling).getText();
-
- assertNotEquals("The view should have scrolled!", viewText, viewAfterFlingText);
- assertCenterAligned(viewAfterFling);
- }
-
- private void setupSnapHelper() throws Throwable {
- SnapHelper snapHelper = new LinearSnapHelper();
- mGlm.expectIdleState(1);
- snapHelper.attachToRecyclerView(mRecyclerView);
- mGlm.waitForSnap(25);
-
- mGlm.expectLayout(1);
- scrollToPosition(mConfig.mItemCount / 2);
- mGlm.waitForLayout(2);
-
- View view = findCenterView();
- int scrollDistance = distFromCenter(view) / 2;
- if (scrollDistance == 0) {
- return;
- }
-
- int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
-
- mGlm.expectIdleState(2);
- smoothScrollBy(scrollDist);
- mGlm.waitForSnap(25);
- }
-
- @Nullable
- private View findCenterView() {
- return mRecyclerView.findChildViewUnder(getRvCenterX(), getRvCenterY());
- }
-
- private int getViewDimension(View view) {
- OrientationHelper helper;
- if (mGlm.canScrollHorizontally()) {
- helper = OrientationHelper.createHorizontalHelper(mGlm);
- } else {
- helper = OrientationHelper.createVerticalHelper(mGlm);
- }
- return helper.getDecoratedMeasurement(view);
- }
-
- private int getWidthMinusPadding(View view) {
- return view.getWidth() - view.getPaddingLeft() - view.getPaddingRight();
- }
-
- private int getHeightMinusPadding(View view) {
- return view.getHeight() - view.getPaddingTop() - view.getPaddingBottom();
- }
-
- private int getRvCenterX() {
- return getWidthMinusPadding(mRecyclerView) / 2 + mRecyclerView.getPaddingLeft();
- }
-
- private int getRvCenterY() {
- return getHeightMinusPadding(mRecyclerView) / 2 + mRecyclerView.getPaddingTop();
- }
-
- private int getViewCenterX(View view) {
- return mGlm.getViewBounds(view).centerX();
- }
-
- private int getViewCenterY(View view) {
- return mGlm.getViewBounds(view).centerY();
- }
-
- private void assertCenterAligned(View view) {
- if(mGlm.canScrollHorizontally()) {
- assertEquals("The child should align with the center of the parent",
- getRvCenterX(), getViewCenterX(view), 1);
- } else {
- assertEquals("The child should align with the center of the parent",
- getRvCenterY(), getViewCenterY(view), 1);
- }
- }
-
- private int distFromCenter(View view) {
- if (mGlm.canScrollHorizontally()) {
- return Math.abs(getRvCenterX() - getViewCenterX(view));
- } else {
- return Math.abs(getRvCenterY() - getViewCenterY(view));
- }
- }
-
- private boolean fling(final int velocityX, final int velocityY)
- throws Throwable {
- final AtomicBoolean didStart = new AtomicBoolean(false);
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- boolean result = mRecyclerView.fling(velocityX, velocityY);
- didStart.set(result);
- }
- });
- if (!didStart.get()) {
- return false;
- }
- waitForIdleScroll(mRecyclerView);
- return true;
- }
-}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.kt b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.kt
new file mode 100644
index 0000000..5849f9e
--- /dev/null
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/GridLayoutManagerSnappingTest.kt
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2018 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.widget
+
+import android.view.View
+import android.widget.TextView
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.math.abs
+import org.junit.Assert
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+internal class GridLayoutManagerSnappingTest(
+ val mConfig: Config,
+ private val mReverseScroll: Boolean,
+ private val mApplyPadding: Boolean
+) : BaseGridLayoutManagerTest() {
+ @Throws(Throwable::class)
+ override fun setupBasic(config: Config, testAdapter: GridTestAdapter): RecyclerView {
+ val rv = super.setupBasic(config, testAdapter)
+ if (mApplyPadding) {
+ rv.setPadding(17, 23, 0, 0)
+ }
+ return rv
+ }
+
+ @Ignore // b/244324972
+ @Test
+ @Throws(Throwable::class)
+ fun snapOnScrollSameView() {
+ val config = mConfig.clone() as Config
+ val recyclerView = setupBasic(config)
+ waitForFirstLayout(recyclerView)
+ setupSnapHelper()
+
+ // Record the current center view.
+ val view = findCenterView()
+ assertCenterAligned(view)
+ val scrollDistance = getViewDimension(view) / 2 - 1
+ val scrollDist = if (mReverseScroll) -scrollDistance else scrollDistance
+ mGlm.expectIdleState(2)
+ smoothScrollBy(scrollDist)
+ mGlm.waitForSnap(25)
+
+ // Views have not changed
+ val viewAfterFling = findCenterView()
+ Assert.assertSame("The view should have scrolled", view, viewAfterFling)
+ assertCenterAligned(viewAfterFling)
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/271599012
+ @Test
+ @Throws(Throwable::class)
+ fun snapOnScrollNextItem() {
+ val config = mConfig.clone() as Config
+ val recyclerView = setupBasic(config)
+ waitForFirstLayout(recyclerView)
+ setupSnapHelper()
+
+ // Record the current center view.
+ val view = findCenterView()
+ assertCenterAligned(view)
+ val viewText = (view as TextView?)!!.getText()
+ val scrollDistance = getViewDimension(view) + 1
+ val scrollDist = if (mReverseScroll) -scrollDistance else scrollDistance
+ smoothScrollBy(scrollDist)
+ waitForIdleScroll(mRecyclerView)
+ waitForIdleScroll(mRecyclerView)
+ val viewAfterScroll = findCenterView()
+ val viewAfterFlingText = (viewAfterScroll as TextView?)!!.getText()
+ Assert.assertNotEquals("The view should have scrolled!", viewText, viewAfterFlingText)
+ assertCenterAligned(viewAfterScroll)
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/271599012
+ @Test
+ @Throws(Throwable::class)
+ fun snapOnFlingSameView() {
+ val config = mConfig.clone() as Config
+ val recyclerView = setupBasic(config)
+ waitForFirstLayout(recyclerView)
+ setupSnapHelper()
+
+ // Record the current center view.
+ val view = findCenterView()
+ assertCenterAligned(view)
+
+ // Velocity small enough to not scroll to the next view.
+ val velocity = (1.000001 * mRecyclerView.minFlingVelocity).toInt()
+ val velocityDir = if (mReverseScroll) -velocity else velocity
+ mGlm.expectIdleState(2)
+ Assert.assertTrue(fling(velocityDir, velocityDir))
+ // Wait for two settling scrolls: the initial one and the corrective one.
+ waitForIdleScroll(mRecyclerView)
+ mGlm.waitForSnap(100)
+ val viewAfterFling = findCenterView()
+ Assert.assertSame("The view should NOT have scrolled", view, viewAfterFling)
+ assertCenterAligned(viewAfterFling)
+ }
+
+ @SdkSuppress(minSdkVersion = 22) // b/271599012
+ @Test
+ @Throws(Throwable::class)
+ fun snapOnFlingNextView() {
+ val config = mConfig.clone() as Config
+ val recyclerView = setupBasic(config)
+ waitForFirstLayout(recyclerView)
+ setupSnapHelper()
+
+ // Record the current center view.
+ val view = findCenterView()
+ assertCenterAligned(view)
+ val viewText = (view as TextView?)!!.getText()
+
+ // Velocity high enough to scroll beyond the current view.
+ val velocity = (0.25 * mRecyclerView.maxFlingVelocity).toInt()
+ val velocityDir = if (mReverseScroll) -velocity else velocity
+ mGlm.expectIdleState(1)
+ Assert.assertTrue(fling(velocityDir, velocityDir))
+ mGlm.waitForSnap(100)
+ instrumentation.waitForIdleSync()
+ val viewAfterFling = findCenterView()
+ val viewAfterFlingText = (viewAfterFling as TextView?)!!.getText()
+ Assert.assertNotEquals("The view should have scrolled!", viewText, viewAfterFlingText)
+ assertCenterAligned(viewAfterFling)
+ }
+
+ @Throws(Throwable::class)
+ private fun setupSnapHelper() {
+ val snapHelper: SnapHelper = LinearSnapHelper()
+ mGlm.expectIdleState(1)
+ snapHelper.attachToRecyclerView(mRecyclerView)
+ mGlm.waitForSnap(25)
+ mGlm.expectLayout(1)
+ scrollToPosition(mConfig.mItemCount / 2)
+ mGlm.waitForLayout(2)
+ val view = findCenterView()
+ val scrollDistance = distFromCenter(view) / 2
+ if (scrollDistance == 0) {
+ return
+ }
+ val scrollDist = if (mReverseScroll) -scrollDistance else scrollDistance
+ mGlm.expectIdleState(2)
+ smoothScrollBy(scrollDist)
+ mGlm.waitForSnap(25)
+ }
+
+ private fun findCenterView(): View? {
+ return mRecyclerView.findChildViewUnder(rvCenterX.toFloat(), rvCenterY.toFloat())
+ }
+
+ private fun getViewDimension(view: View?): Int {
+ val helper: OrientationHelper = if (mGlm.canScrollHorizontally()) {
+ OrientationHelper.createHorizontalHelper(mGlm)
+ } else {
+ OrientationHelper.createVerticalHelper(mGlm)
+ }
+ return helper.getDecoratedMeasurement(view)
+ }
+
+ private fun getWidthMinusPadding(view: View): Int {
+ return view.width - view.getPaddingLeft() - view.getPaddingRight()
+ }
+
+ private fun getHeightMinusPadding(view: View): Int {
+ return view.height - view.paddingTop - view.paddingBottom
+ }
+
+ private val rvCenterX: Int
+ get() = getWidthMinusPadding(mRecyclerView) / 2 + mRecyclerView.getPaddingLeft()
+ private val rvCenterY: Int
+ get() = getHeightMinusPadding(mRecyclerView) / 2 + mRecyclerView.paddingTop
+
+ private fun getViewCenterX(view: View?): Int {
+ return mGlm.getViewBounds(view).centerX()
+ }
+
+ private fun getViewCenterY(view: View?): Int {
+ return mGlm.getViewBounds(view).centerY()
+ }
+
+ private fun assertCenterAligned(view: View?) {
+ if (mGlm.canScrollHorizontally()) {
+ Assert.assertEquals(
+ "The child should align with the center of the parent",
+ rvCenterX.toFloat(), getViewCenterX(view).toFloat(), 1f
+ )
+ } else {
+ Assert.assertEquals(
+ "The child should align with the center of the parent",
+ rvCenterY.toFloat(), getViewCenterY(view).toFloat(), 1f
+ )
+ }
+ }
+
+ private fun distFromCenter(view: View?): Int {
+ return if (mGlm.canScrollHorizontally()) {
+ abs((rvCenterX - getViewCenterX(view)).toDouble()).toInt()
+ } else {
+ abs((rvCenterY - getViewCenterY(view)).toDouble()).toInt()
+ }
+ }
+
+ @Throws(Throwable::class)
+ private fun fling(velocityX: Int, velocityY: Int): Boolean {
+ val didStart = AtomicBoolean(false)
+ mActivityRule.runOnUiThread(Runnable {
+ val result = mRecyclerView.fling(velocityX, velocityY)
+ didStart.set(result)
+ })
+ if (!didStart.get()) {
+ return false
+ }
+ waitForIdleScroll(mRecyclerView)
+ return true
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "config:{0},reverseScroll:{1},applyPadding:{2}")
+ @JvmStatic
+ fun params(): List<Array<Any>> {
+ val result: MutableList<Array<Any>> = ArrayList()
+ val configs = createBaseVariations()
+ for (config in configs) {
+ for (reverseScroll in booleanArrayOf(true, false)) {
+ for (applyPadding in booleanArrayOf(true, false)) {
+ result.add(arrayOf(config, reverseScroll, applyPadding))
+ }
+ }
+ }
+ return result
+ }
+ }
+}