1c587f7dba5a337169e854e235da59f595255d6ccAga Madurska/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
3c587f7dba5a337169e854e235da59f595255d6ccAga Madurska *
4c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Licensed under the Apache License, Version 2.0 (the "License");
5c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * you may not use this file except in compliance with the License.
6c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * You may obtain a copy of the License at
7c587f7dba5a337169e854e235da59f595255d6ccAga Madurska *
8c587f7dba5a337169e854e235da59f595255d6ccAga Madurska *      http://www.apache.org/licenses/LICENSE-2.0
9c587f7dba5a337169e854e235da59f595255d6ccAga Madurska *
10c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Unless required by applicable law or agreed to in writing, software
11c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * distributed under the License is distributed on an "AS IS" BASIS,
12c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * See the License for the specific language governing permissions and
14c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * limitations under the License.
15c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */
16c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget;
18c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
19fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertEquals;
20fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertNotSame;
21fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertSame;
22fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertTrue;
23e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas
2435232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikasimport android.support.test.filters.LargeTest;
25c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.view.View;
2624e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurskaimport android.widget.TextView;
27c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
28c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.Nullable;
29c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas
30c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport org.junit.Test;
31c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport org.junit.runner.RunWith;
32c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport org.junit.runners.Parameterized;
33c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
34c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.ArrayList;
35c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.List;
36c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.concurrent.atomic.AtomicBoolean;
37c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
3835232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikas@LargeTest
39c587f7dba5a337169e854e235da59f595255d6ccAga Madurska@RunWith(Parameterized.class)
40c587f7dba5a337169e854e235da59f595255d6ccAga Madurskapublic class GridLayoutManagerSnappingTest extends BaseGridLayoutManagerTest {
41c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
42c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    final Config mConfig;
43c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    final boolean mReverseScroll;
44c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
45c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public GridLayoutManagerSnappingTest(Config config, boolean reverseScroll) {
46c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mConfig = config;
47c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mReverseScroll = reverseScroll;
48c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
49c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
50e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas    @Parameterized.Parameters(name = "config:{0},reverseScroll:{1}")
51c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public static List<Object[]> getParams() {
52c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        List<Object[]> result = new ArrayList<>();
53c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        List<Config> configs = createBaseVariations();
54c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        for (Config config : configs) {
55c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            for (boolean reverseScroll : new boolean[] {true, false}) {
56c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                result.add(new Object[]{config, reverseScroll});
57c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            }
58c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
59c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        return result;
60c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
61c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
62c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Test
63c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public void snapOnScrollSameView() throws Throwable {
64c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final Config config = (Config) mConfig.clone();
65c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        RecyclerView recyclerView = setupBasic(config);
66c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForFirstLayout(recyclerView);
67c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        setupSnapHelper();
68c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
69c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Record the current center view.
70c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View view = findCenterView(mGlm);
71c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(view);
72c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int scrollDistance = (getViewDimension(view) / 2) - 1;
73c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
74c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectIdleState(2);
75c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        smoothScrollBy(scrollDist);
76c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForSnap(10);
77c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
78c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Views have not changed
79c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View viewAfterFling = findCenterView(mGlm);
80c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertSame("The view should have scrolled", view, viewAfterFling);
81c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(viewAfterFling);
82c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
83c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
84c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Test
85c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public void snapOnScrollNextItem() throws Throwable {
86c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final Config config = (Config) mConfig.clone();
87c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        RecyclerView recyclerView = setupBasic(config);
88c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForFirstLayout(recyclerView);
89c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        setupSnapHelper();
90c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
91c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Record the current center view.
92c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View view = findCenterView(mGlm);
93c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(view);
94c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int scrollDistance = getViewDimension(view) + 1;
95c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
96c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
97c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        smoothScrollBy(scrollDist);
98c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForIdleScroll(mRecyclerView);
99c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForIdleScroll(mRecyclerView);
100c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
101c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View viewAfterScroll = findCenterView(mGlm);
102c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
103c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertNotSame("The view should have scrolled", view, viewAfterScroll);
104c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(viewAfterScroll);
105c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
106c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
107c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Test
108c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public void snapOnFlingSameView() throws Throwable {
109c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final Config config = (Config) mConfig.clone();
110c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        RecyclerView recyclerView = setupBasic(config);
111c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForFirstLayout(recyclerView);
112c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        setupSnapHelper();
113c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
114c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Record the current center view.
115c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View view = findCenterView(mGlm);
116c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(view);
117c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
118c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Velocity small enough to not scroll to the next view.
119c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int velocity = (int) (1.000001 * mRecyclerView.getMinFlingVelocity());
120c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int velocityDir = mReverseScroll ? -velocity : velocity;
121c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectIdleState(2);
122c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertTrue(fling(velocityDir, velocityDir));
123c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Wait for two settling scrolls: the initial one and the corrective one.
124c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForIdleScroll(mRecyclerView);
125c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForSnap(100);
126c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
127c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View viewAfterFling = findCenterView(mGlm);
128c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
129c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertSame("The view should NOT have scrolled", view, viewAfterFling);
130c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(viewAfterFling);
131c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
132c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
133c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Test
134c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public void snapOnFlingNextView() throws Throwable {
135c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final Config config = (Config) mConfig.clone();
136c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        RecyclerView recyclerView = setupBasic(config);
137c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForFirstLayout(recyclerView);
138c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        setupSnapHelper();
139c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
140c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Record the current center view.
141c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View view = findCenterView(mGlm);
142c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(view);
143c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
144c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        // Velocity high enough to scroll beyond the current view.
14524e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurska        int velocity = (int) (0.25 * mRecyclerView.getMaxFlingVelocity());
146c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int velocityDir = mReverseScroll ? -velocity : velocity;
147c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
148c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectIdleState(1);
149c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertTrue(fling(velocityDir, velocityDir));
150c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForSnap(100);
151c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        getInstrumentation().waitForIdleSync();
152c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
153c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View viewAfterFling = findCenterView(mGlm);
154c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
15524e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurska        assertNotSame("The view should have scrolled!",
15624e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurska                ((TextView) view).getText(),((TextView) viewAfterFling).getText());
157c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        assertCenterAligned(viewAfterFling);
158c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
159c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
160c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    private void setupSnapHelper() throws Throwable {
161c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        SnapHelper snapHelper = new LinearSnapHelper();
162c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectIdleState(1);
163c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        snapHelper.attachToRecyclerView(mRecyclerView);
164c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForSnap(10);
165c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
166c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectLayout(1);
167c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        scrollToPosition(mConfig.mItemCount / 2);
168c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForLayout(2);
169c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
170c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        View view = findCenterView(mGlm);
1713911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        int scrollDistance = distFromCenter(view) / 2;
1723911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        if (scrollDistance == 0) {
1733911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska            return;
1743911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        }
1753911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska
176c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
177c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
178c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.expectIdleState(2);
179c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        smoothScrollBy(scrollDist);
180c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        mGlm.waitForSnap(10);
181c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
182c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
183c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Nullable View findCenterView(RecyclerView.LayoutManager layoutManager) {
184c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if (layoutManager.canScrollHorizontally()) {
185c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            return mRecyclerView.findChildViewUnder(mRecyclerView.getWidth() / 2, 0);
186c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        } else {
187c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            return mRecyclerView.findChildViewUnder(0, mRecyclerView.getHeight() / 2);
188c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
189c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
190c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
191c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    private int getViewDimension(View view) {
192c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        OrientationHelper helper;
193c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if (mGlm.canScrollHorizontally()) {
194c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            helper = OrientationHelper.createHorizontalHelper(mGlm);
195c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        } else {
196c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            helper = OrientationHelper.createVerticalHelper(mGlm);
197c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
198c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        return helper.getDecoratedMeasurement(view);
199c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
200c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
201c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    private void assertCenterAligned(View view) {
202c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if(mGlm.canScrollHorizontally()) {
203c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            assertEquals("The child should align with the center of the parent",
204c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                    mRecyclerView.getWidth() / 2,
205c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                    mGlm.getDecoratedLeft(view) +
20624e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurska                            mGlm.getDecoratedMeasuredWidth(view) / 2, 1);
207c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        } else {
208c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            assertEquals("The child should align with the center of the parent",
209c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                    mRecyclerView.getHeight() / 2,
210c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                    mGlm.getDecoratedTop(view) +
21124e2d006cef58a0e36a738e0a62a58d0f47e74b6Aga Madurska                            mGlm.getDecoratedMeasuredHeight(view) / 2, 1);
212c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
213c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
214c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
2153911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska    private int distFromCenter(View view) {
2163911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        if (mGlm.canScrollHorizontally()) {
2173911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska            return Math.abs(mRecyclerView.getWidth() / 2 - mGlm.getViewBounds(view).centerX());
2183911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        } else {
2193911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska            return Math.abs(mRecyclerView.getHeight() / 2 - mGlm.getViewBounds(view).centerY());
2203911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska        }
2213911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska    }
2223911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska
223c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    private boolean fling(final int velocityX, final int velocityY)
224c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            throws Throwable {
225c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final AtomicBoolean didStart = new AtomicBoolean(false);
22642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas        mActivityRule.runOnUiThread(new Runnable() {
227c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            @Override
228c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            public void run() {
229c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                boolean result = mRecyclerView.fling(velocityX, velocityY);
230c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                didStart.set(result);
231c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            }
232c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        });
233c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if (!didStart.get()) {
234c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            return false;
235c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
236c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        waitForIdleScroll(mRecyclerView);
237c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        return true;
238c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
239c587f7dba5a337169e854e235da59f595255d6ccAga Madurska}
240