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
+        }
+    }
+}