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