161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * 461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * Licensed under the Apache License, Version 2.0 (the "License"); 561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * you may not use this file except in compliance with the License. 661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * You may obtain a copy of the License at 761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * 861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * http://www.apache.org/licenses/LICENSE-2.0 961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * 1061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * Unless required by applicable law or agreed to in writing, software 1161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * distributed under the License is distributed on an "AS IS" BASIS, 1261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * See the License for the specific language governing permissions and 1461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin * limitations under the License. 1561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin */ 1661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget; 1861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.recyclerview.widget.RecyclerView.VERTICAL; 2061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 2161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport static org.junit.Assert.assertFalse; 2261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport static org.junit.Assert.assertNotNull; 2361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport static org.junit.Assert.assertTrue; 2461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 2561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.app.Activity; 2661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.content.res.Resources; 2761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.graphics.Color; 2861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.graphics.drawable.StateListDrawable; 2961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.support.test.InstrumentationRegistry; 3061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.support.test.annotation.UiThreadTest; 3161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.support.test.filters.LargeTest; 3261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.support.test.runner.AndroidJUnit4; 33a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapardimport android.view.LayoutInflater; 3461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.view.MotionEvent; 3561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.view.View; 3661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.view.ViewGroup; 3761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.view.ViewGroup.LayoutParams; 3861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport android.widget.TextView; 3961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 40c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.NonNull; 41c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.recyclerview.R; 42c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas 4361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport org.junit.Test; 4461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport org.junit.runner.RunWith; 4561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 4661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport java.util.concurrent.CountDownLatch; 4761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linimport java.util.concurrent.TimeUnit; 4861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 4961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin@LargeTest 5061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin@RunWith(AndroidJUnit4.class) 5161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Linpublic class RecyclerViewFastScrollerTest extends BaseRecyclerViewInstrumentationTest { 5261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private static final int FLAG_HORIZONTAL = 1; 5361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private static final int FLAG_VERTICAL = 1 << 1; 5461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private int mScrolledByY = -1000; 5561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private int mScrolledByX = -1000; 5661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private FastScroller mScroller; 5761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private boolean mHide; 5861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 5961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private void setContentView(final int layoutId) throws Throwable { 6061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final Activity activity = mActivityRule.getActivity(); 6161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mActivityRule.runOnUiThread(new Runnable() { 6261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 6361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void run() { 6461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin activity.setContentView(layoutId); 6561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 6661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }); 6761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 6861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 69a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Test 70a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void xml_fastScrollEnabled_startsInvisibleAndAtTop() throws Throwable { 71a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithXml(); 7261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 73a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard assertTrue("Expected centerY to start == 0", mScroller.mVerticalThumbCenterY == 0); 74a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard assertFalse("Expected thumb to start invisible", mScroller.isVisible()); 7561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 7661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 7761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 78a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void scrollBy_displaysAndMovesFastScrollerThumb() throws Throwable { 79a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithXml(); 80a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 8161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mActivityRule.runOnUiThread(new Runnable() { 8261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 8361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void run() { 84a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.scrollBy(0, 400); 8561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 8661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }); 87a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 88a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard assertTrue("Expected centerY to be > 0" + mScroller.mVerticalThumbCenterY, 89a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScroller.mVerticalThumbCenterY > 0); 90a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard assertTrue("Expected thumb to be visible", mScroller.isVisible()); 91a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 92a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 93a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Test 94a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void ui_dragsThumb_scrollsRecyclerView() throws Throwable { 95a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithXml(); 96a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 97a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard // RecyclerView#scrollBy(int, int) used to cause the scroller thumb to show up. 9861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mActivityRule.runOnUiThread(new Runnable() { 9961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 10061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void run() { 101a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.scrollBy(0, 1); 102a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.scrollBy(0, -1); 10361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 10461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }); 10513d1783c718ca2d7493d9656f58a0878ac504d8bBen Lin int[] absoluteCoords = new int[2]; 10613d1783c718ca2d7493d9656f58a0878ac504d8bBen Lin mRecyclerView.getLocationOnScreen(absoluteCoords); 10761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin TouchUtils.drag(InstrumentationRegistry.getInstrumentation(), mRecyclerView.getWidth() - 10, 10813d1783c718ca2d7493d9656f58a0878ac504d8bBen Lin mRecyclerView.getWidth() - 10, mScroller.mVerticalThumbCenterY + absoluteCoords[1], 10913d1783c718ca2d7493d9656f58a0878ac504d8bBen Lin mRecyclerView.getHeight() + absoluteCoords[1], 100); 110a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 11161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected dragging thumb to move recyclerView", 112a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.computeVerticalScrollOffset() > 0); 11361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 11461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 11561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 11661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void properCleanUp() throws Throwable { 11761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView = new RecyclerView(getActivity()); 11861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final Activity activity = mActivityRule.getActivity(); 11961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final CountDownLatch latch = new CountDownLatch(1); 12061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mActivityRule.runOnUiThread(new Runnable() { 12161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 12261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void run() { 12361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin activity.setContentView( 124ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.layout.fast_scrollbar_test_rv); 12561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView = (RecyclerView) activity.findViewById( 126ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.id.recycler_view); 12761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext()); 12861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin layout.setOrientation(VERTICAL); 12961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView.setLayoutManager(layout); 13061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView.setAdapter(new TestAdapter(50)); 13161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin Resources res = getActivity().getResources(); 13261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable( 133ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable.fast_scroll_thumb_drawable), 13461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin res.getDrawable( 135ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable 13661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin .fast_scroll_track_drawable), 13761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin (StateListDrawable) res.getDrawable( 138ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable 13961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin .fast_scroll_thumb_drawable), 14061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin res.getDrawable( 141ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable 14261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin .fast_scroll_track_drawable), 14361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness), 14461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range), 14561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) { 14661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 14761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void show() { 14861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin // Overriden to avoid animation calls in instrumentation thread 14961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 15061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 15161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 15261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void hide(int duration) { 15361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin latch.countDown(); 15461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mHide = true; 15561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 15661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }; 15761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 15861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 15961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }); 16061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin waitForIdleScroll(mRecyclerView); 16161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 16261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mActivityRule.runOnUiThread(new Runnable() { 16361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 16461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void run() { 16561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView.scrollBy(0, 400); 16661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.attachToRecyclerView(new RecyclerView(getActivity())); 16761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 16861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin }); 16961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertFalse(latch.await(2, TimeUnit.SECONDS)); 17061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertFalse(mHide); 17161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 17261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 17361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 17461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void inflationTest() throws Throwable { 175ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas setContentView(androidx.recyclerview.test.R.layout.fast_scrollbar_test_rv); 17661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin getInstrumentation().waitForIdleSync(); 17761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin RecyclerView view = (RecyclerView) getActivity().findViewById( 178ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.id.recycler_view); 179ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin assertTrue(view.getItemDecorationCount() == 1); 18061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(view.getItemDecorationAt(0) instanceof FastScroller); 18161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin FastScroller scroller = (FastScroller) view.getItemDecorationAt(0); 18261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertNotNull(scroller.getHorizontalThumbDrawable()); 18361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertNotNull(scroller.getHorizontalTrackDrawable()); 18461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertNotNull(scroller.getVerticalThumbDrawable()); 18561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertNotNull(scroller.getVerticalTrackDrawable()); 18661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 18761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 188ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin @Test 189ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin public void removeFastScrollerSuccessful() throws Throwable { 190ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas setContentView(androidx.recyclerview.test.R.layout.fast_scrollbar_test_rv); 191ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin getInstrumentation().waitForIdleSync(); 192ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin final RecyclerView view = (RecyclerView) getActivity().findViewById( 193ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.id.recycler_view); 194ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin assertTrue(view.getItemDecorationCount() == 1); 195ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin mActivityRule.runOnUiThread(new Runnable() { 196ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin @Override 197ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin public void run() { 198ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin view.removeItemDecorationAt(0); 199ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin assertTrue(view.getItemDecorationCount() == 0); 200ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin } 201ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin }); 202ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin } 203ba15381ff60d028716343c033eedbc38bed3fa3fBen Lin 20461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @UiThreadTest 20561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 20661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void initWithBadDrawables() throws Throwable { 207a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithCode(); 208a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 20961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin Throwable exception = null; 21061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin try { 21161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mRecyclerView.initFastScroller(null, null, null, null); 21261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } catch (Throwable t) { 21361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin exception = t; 21461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 21561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(exception instanceof IllegalArgumentException); 21661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 21761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 21861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 21961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void verticalScrollUpdatesFastScrollThumb() throws Throwable { 22061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin scrollUpdatesFastScrollThumb(FLAG_VERTICAL); 22161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 22261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 22361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 22461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void horizontalScrollUpdatesFastScrollThumb() throws Throwable { 22561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin scrollUpdatesFastScrollThumb(FLAG_HORIZONTAL); 22661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 22761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 22861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private void scrollUpdatesFastScrollThumb(int direction) throws Throwable { 229a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithCode(); 23061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250, 23161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin direction == FLAG_VERTICAL ? 250 : 0); 23261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin if (direction == FLAG_VERTICAL) { 23361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for centerY, got " + mScroller.mVerticalThumbCenterY, 23461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mVerticalThumbCenterY == 250); 23561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight, 23661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mVerticalThumbHeight == 250); 23761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } else if (direction == FLAG_HORIZONTAL) { 23861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for centerX, got " + mScroller.mHorizontalThumbCenterX, 23961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mHorizontalThumbCenterX == 250); 24061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth, 24161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mHorizontalThumbWidth == 250); 24261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 24361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(mScroller.isVisible()); 24461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 24561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 42, 24661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin direction == FLAG_VERTICAL ? 42 : 0); 24761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin if (direction == FLAG_VERTICAL) { 24861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 146 for centerY, got " + mScroller.mVerticalThumbCenterY, 24961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mVerticalThumbCenterY == 146); 25061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight, 25161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mVerticalThumbHeight == 250); 25261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } else if (direction == FLAG_HORIZONTAL) { 25361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 146 for centerX, got " + mScroller.mHorizontalThumbCenterX, 25461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mHorizontalThumbCenterX == 146); 25561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth, 25661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.mHorizontalThumbWidth == 250); 25761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 25861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(mScroller.isVisible()); 25961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 26061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 26161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 26261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void draggingDoesNotTriggerFastScrollIfNotInThumb() throws Throwable { 263a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithCode(); 26461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.updateScrollPosition(0, 250); 26561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN, 250, 250, 26661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 0); 26761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent)); 26861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE, 250, 275, 26961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 0); 27061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, moveEvent)); 27161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 27261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 27361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 27461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void verticalDraggingFastScrollThumbDoesActualScrolling() throws Throwable { 27561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin draggingFastScrollThumbDoesActualScrolling(FLAG_VERTICAL); 27661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 27761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 27861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Test 27961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public void horizontalDraggingFastScrollThumbDoesActualScrolling() throws Throwable { 28061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin draggingFastScrollThumbDoesActualScrolling(FLAG_HORIZONTAL); 28161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 28261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 28361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private void draggingFastScrollThumbDoesActualScrolling(int direction) throws Throwable { 284a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard arrangeWithCode(); 28561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250, 28661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin direction == FLAG_VERTICAL ? 250 : 0); 28761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN, 28861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin direction == FLAG_VERTICAL ? 500 : 250, direction == FLAG_VERTICAL ? 250 : 500, 0); 28961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent)); 29061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue(mScroller.isDragging()); 29161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE, 29261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin direction == FLAG_VERTICAL ? 500 : 221, direction == FLAG_VERTICAL ? 221 : 500, 0); 29361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mScroller.onTouchEvent(mRecyclerView, moveEvent); 29461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin if (direction == FLAG_VERTICAL) { 29561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected to get -29, but got " + mScrolledByY, mScrolledByY == -29); 29661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } else { 29761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin assertTrue("Expected to get -29, but got " + mScrolledByX, mScrolledByX == -29); 29861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 29961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 30061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 301a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard private void arrangeWithXml() throws Throwable { 302a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 303a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard final TestActivity activity = mActivityRule.getActivity(); 304a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard final TestedFrameLayout testedFrameLayout = activity.getContainer(); 305a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 306a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard RecyclerView recyclerView = (RecyclerView) LayoutInflater.from(activity).inflate( 307ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.layout.fast_scrollbar_test_rv, 308a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard testedFrameLayout, 309a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard false); 310a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 311a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext()); 312a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard layout.setOrientation(VERTICAL); 313a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard recyclerView.setLayoutManager(layout); 314a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 315a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard recyclerView.setAdapter(new TestAdapter(50)); 316a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 317a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScroller = (FastScroller) recyclerView.getItemDecorationAt(0); 318a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 3197b926c6cb92ecc663439b200559d3c0fcfa86980shepshapard testedFrameLayout.expectLayouts(1); 320a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard testedFrameLayout.expectDraws(1); 321a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard setRecyclerView(recyclerView); 3227b926c6cb92ecc663439b200559d3c0fcfa86980shepshapard testedFrameLayout.waitForLayout(2); 323a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard testedFrameLayout.waitForDraw(2); 324a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 325a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 326a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard private void arrangeWithCode() throws Exception { 327a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard final int width = 500; 328a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard final int height = 500; 329a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 330a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView = new RecyclerView(getActivity()) { 331a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 332a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeVerticalScrollRange() { 333a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 1000; 334a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 335a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 336a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 337a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeVerticalScrollExtent() { 338a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 500; 339a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 340a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 341a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 342a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeVerticalScrollOffset() { 343a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 250; 344a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 345a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 346a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 347a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeHorizontalScrollRange() { 348a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 1000; 349a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 350a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 351a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 352a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeHorizontalScrollExtent() { 353a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 500; 354a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 355a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 356a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 357a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public int computeHorizontalScrollOffset() { 358a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard return 250; 359a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 360a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 361a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 362a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void scrollBy(int x, int y) { 363a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScrolledByY = y; 364a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScrolledByX = x; 365a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 366a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard }; 367a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.setAdapter(new TestAdapter(50)); 368a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.measure( 369a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), 370a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); 371a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.layout(0, 0, width, height); 372a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 373a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard Resources res = getActivity().getResources(); 374a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable( 375ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable.fast_scroll_thumb_drawable), 376a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard res.getDrawable( 377ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable.fast_scroll_track_drawable), 378a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard (StateListDrawable) res.getDrawable( 379ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable.fast_scroll_thumb_drawable), 380a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard res.getDrawable( 381ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas androidx.recyclerview.test.R.drawable.fast_scroll_track_drawable), 382a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness), 383a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range), 384a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) { 385a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 386a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void show() { 387a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard // Overriden to avoid animation calls in instrumentation thread 388a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 389a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 390a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard @Override 391a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard public void hide(int duration) { 392a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mHide = true; 393a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 394a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard }; 395a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mRecyclerView.mEnableFastScroller = true; 396a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 397a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard // Draw it once so height/width gets updated 398a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard mScroller.onDrawOver(null, mRecyclerView, null); 399a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard } 400a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard 401a6b6d5e71c7b73e7d3f5cc55877a34e534b4046fshepshapard private static class TestAdapter extends RecyclerView.Adapter { 40261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin private int mItemCount; 40361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 40461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public static class ViewHolder extends RecyclerView.ViewHolder { 40561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public TextView mTextView; 40661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 40761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin ViewHolder(TextView v) { 40861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin super(v); 40961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mTextView = v; 41061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 41161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 41261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 41361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public String toString() { 41461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin return super.toString() + " '" + mTextView.getText(); 41561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 41661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 41761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 41861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin TestAdapter(int itemCount) { 41961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin mItemCount = itemCount; 42061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 42161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 42261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 4238a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 42461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin int viewType) { 42561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin final ViewHolder h = new ViewHolder(new TextView(parent.getContext())); 42661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin h.mTextView.setMinimumHeight(128); 42761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin h.mTextView.setPadding(20, 0, 20, 0); 42861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin h.mTextView.setFocusable(true); 42961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin h.mTextView.setBackgroundColor(Color.BLUE); 43061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams( 43161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin LayoutParams.MATCH_PARENT, 43261b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin ViewGroup.LayoutParams.WRAP_CONTENT); 43361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin lp.leftMargin = 10; 43461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin lp.rightMargin = 5; 43561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin lp.topMargin = 20; 43661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin lp.bottomMargin = 15; 43761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin h.mTextView.setLayoutParams(lp); 43861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin return h; 43961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 44061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 44161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 4428a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 44361b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin holder.itemView.setTag("pos " + position); 44461b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 44561b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin 44661b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin @Override 44761b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin public int getItemCount() { 44861b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin return mItemCount; 44961b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 45061b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin } 45161b34aa12ae8188f617bab4c9e6a0e59e08f9d26Ben Lin} 452