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