12998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte/*
22998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * Copyright (C) 2017 The Android Open Source Project
32998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte *
42998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * Licensed under the Apache License, Version 2.0 (the "License");
52998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * you may not use this file except in compliance with the License.
62998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * You may obtain a copy of the License at
72998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte *
82998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte *      http://www.apache.org/licenses/LICENSE-2.0
92998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte *
102998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * Unless required by applicable law or agreed to in writing, software
112998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * distributed under the License is distributed on an "AS IS" BASIS,
122998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * See the License for the specific language governing permissions and
142998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte * limitations under the License.
152998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte */
162998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
172998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whytepackage android.support.v7.widget;
182998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
192998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport static org.junit.Assert.assertEquals;
202998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport static org.junit.Assert.assertNotEquals;
212998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
222998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.content.Context;
232998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.test.InstrumentationRegistry;
242998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.test.filters.SmallTest;
252998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.test.runner.AndroidJUnit4;
262998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.v4.view.InputDeviceCompat;
272998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.v4.view.MotionEventCompat;
282998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.support.v4.view.ViewConfigurationCompat;
292998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.view.MotionEvent;
302998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.view.View;
312998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.view.ViewConfiguration;
322998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.view.ViewGroup;
332998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport android.widget.TextView;
342998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
352998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport org.junit.Before;
362998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport org.junit.Test;
372998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyteimport org.junit.runner.RunWith;
382998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
392998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte@SmallTest
402998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte@RunWith(AndroidJUnit4.class)
412998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whytepublic class RecyclerViewOnGenericMotionEventTest {
422998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
432998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    TestRecyclerView mRecyclerView;
442998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
452998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Before
462998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void setUp() throws Exception {
472998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView = new TestRecyclerView(getContext());
482998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
492998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
502998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private Context getContext() {
512998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        return InstrumentationRegistry.getContext();
522998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
532998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
542998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private void layout() {
552998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.layout(0, 0, 320, 320);
562998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
572998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
582998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
592998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void rotaryEncoderVerticalScroll() {
602998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
612998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.setLayoutManager(layoutManager);
622998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        layout();
632998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent e = obtainScrollMotionEvent(
642998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                MotionEventCompat.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER);
652998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.onGenericMotionEvent(e);
662998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
672998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
682998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
692998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
702998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void rotaryEncoderHorizontalScroll() {
712998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        // The encoder is one-dimensional, and can only scroll horizontally if vertical scrolling
722998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        // is not enabled.
732998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockLayoutManager layoutManager = new MockLayoutManager(true, false);
742998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.setLayoutManager(layoutManager);
752998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        layout();
762998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent e = obtainScrollMotionEvent(
772998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                MotionEventCompat.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER);
782998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.onGenericMotionEvent(e);
792998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
802998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
812998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
822998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
832998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void pointerVerticalScroll() {
842998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
852998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.setLayoutManager(layoutManager);
862998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        layout();
872998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent e = obtainScrollMotionEvent(
882998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                MotionEventCompat.AXIS_VSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER);
892998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.onGenericMotionEvent(e);
902998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
912998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
922998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
932998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
942998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void pointerHorizontalScroll() {
952998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
962998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.setLayoutManager(layoutManager);
972998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        layout();
982998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent e = obtainScrollMotionEvent(
992998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                MotionEventCompat.AXIS_HSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER);
1002998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        mRecyclerView.onGenericMotionEvent(e);
1012998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
1022998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1032998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1042998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
1052998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void nonZeroScaledVerticalScrollFactor() {
1062998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertNotEquals(0, getScaledVerticalScrollFactor());
1072998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1082998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1092998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    @Test
1102998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    public void nonZeroScaledHorizontalScrollFactor() {
1112998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertNotEquals(0, getScaledHorizontalScrollFactor());
1122998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1132998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1142998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private void assertTotalScroll(int x, int y) {
1152998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertEquals("x total scroll", x, mRecyclerView.mTotalX);
1162998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        assertEquals("y total scroll", y, mRecyclerView.mTotalY);
1172998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1182998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1192998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private static MotionEvent obtainScrollMotionEvent(int axis, int axisValue, int inputDevice) {
1202998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent.PointerProperties[] pointerProperties = { new MotionEvent.PointerProperties() };
1212998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
1222998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        coords.setAxisValue(axis, axisValue);
1232998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MotionEvent.PointerCoords[] pointerCoords = { coords };
1242998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        float xPrecision = 1;
1252998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        float yPrecision = 1;
1262998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        int deviceId = 0;
1272998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        int edgeFlags = 0;
1282998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        int flags = 0;
1292998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        return MotionEvent.obtain(0, System.currentTimeMillis(), MotionEvent.ACTION_SCROLL,
1302998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                1, pointerProperties, pointerCoords, 0, 0, xPrecision, yPrecision, deviceId,
1312998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                edgeFlags, inputDevice, flags);
1322998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1332998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1342998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private float getScaledVerticalScrollFactor() {
1352998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        return ViewConfigurationCompat.getScaledVerticalScrollFactor(
1362998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                ViewConfiguration.get(getContext()), getContext());
1372998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1382998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1392998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private float getScaledHorizontalScrollFactor() {
1402998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        return ViewConfigurationCompat.getScaledHorizontalScrollFactor(
1412998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                ViewConfiguration.get(getContext()), getContext());
1422998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1432998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1442998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    static class MockLayoutManager extends RecyclerView.LayoutManager {
1452998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1462998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        private final boolean mCanScrollHorizontally;
1472998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1482998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        private final boolean mCanScrollVertically;
1492998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1502998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockLayoutManager(boolean canScrollHorizontally, boolean canScrollVertically) {
1512998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            mCanScrollHorizontally = canScrollHorizontally;
1522998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            mCanScrollVertically = canScrollVertically;
1532998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1542998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1552998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1562998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
1572998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
1582998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                    ViewGroup.LayoutParams.WRAP_CONTENT);
1592998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1602998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1612998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1622998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
1632998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                RecyclerView.State state) {
1642998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return dx;
1652998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1662998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1672998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1682998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
1692998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte                RecyclerView.State state) {
1702998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return dy;
1712998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1722998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1732998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1742998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public boolean canScrollHorizontally() {
1752998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return mCanScrollHorizontally;
1762998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1772998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1782998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1792998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public boolean canScrollVertically() {
1802998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return mCanScrollVertically;
1812998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1822998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
1832998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1842998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    static class MockAdapter extends RecyclerView.Adapter {
1852998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1862998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        private int mCount = 0;
1872998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1882998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockAdapter(int count) {
1892998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            this.mCount = count;
1902998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1912998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1922998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1932998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
1942998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return new MockViewHolder(new TextView(parent.getContext()));
1952998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
1962998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
1972998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
1982998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
1992998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2002998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
2012998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2022998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        @Override
2032998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        public int getItemCount() {
2042998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return mCount;
2052998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
2062998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
2072998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2082998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    static class MockViewHolder extends RecyclerView.ViewHolder {
2092998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        MockViewHolder(View itemView) {
2102998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            super(itemView);
2112998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
2122998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
2132998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2142998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    private static class TestRecyclerView extends RecyclerView {
2152998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        int mTotalX = 0;
2162998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        int mTotalY = 0;
2172998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2182998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        TestRecyclerView(Context context) {
2192998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            super(context);
2202998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
2212998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte
2222998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        boolean scrollByInternal(int x, int y, MotionEvent ev) {
2232998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            mTotalX += x;
2242998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            mTotalY += y;
2252998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte            return super.scrollByInternal(x, y, ev);
2262998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte        }
2272998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte    }
2282998aa5b8adb4e54a9fcd8f76298110879c677f5Aaron Whyte}
229