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; 23c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 2435232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikasimport android.support.test.filters.LargeTest; 25c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.view.View; 26c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 27c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.Nullable; 28c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas 29e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.Test; 30e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runner.RunWith; 31e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runners.Parameterized; 32e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas 33c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.ArrayList; 34c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.List; 35c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport java.util.concurrent.atomic.AtomicBoolean; 36c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 3735232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikas@LargeTest 38c587f7dba5a337169e854e235da59f595255d6ccAga Madurska@RunWith(Parameterized.class) 39c587f7dba5a337169e854e235da59f595255d6ccAga Madurskapublic class LinearLayoutManagerSnappingTest extends BaseLinearLayoutManagerTest { 40c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 41c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Config mConfig; 42c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final boolean mReverseScroll; 43c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 44c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public LinearLayoutManagerSnappingTest(Config config, boolean reverseScroll) { 45c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mConfig = config; 46c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mReverseScroll = reverseScroll; 47c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 48c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 49e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas @Parameterized.Parameters(name = "config:{0},reverseScroll:{1}") 50c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public static List<Object[]> getParams() { 51c587f7dba5a337169e854e235da59f595255d6ccAga Madurska List<Object[]> result = new ArrayList<>(); 52c587f7dba5a337169e854e235da59f595255d6ccAga Madurska List<Config> configs = createBaseVariations(); 53c587f7dba5a337169e854e235da59f595255d6ccAga Madurska for (Config config : configs) { 54c587f7dba5a337169e854e235da59f595255d6ccAga Madurska for (boolean reverseScroll : new boolean[] {true, false}) { 55c587f7dba5a337169e854e235da59f595255d6ccAga Madurska result.add(new Object[]{config, reverseScroll}); 56c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 57c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 58c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return result; 59c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 60c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 61c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Test 623911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska public void snapOnScrollSameViewEdge() throws Throwable { 633911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska final Config config = (Config) mConfig.clone(); 643911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska // Ensure that the views are big enough to reach the pathological case when the view closest 653911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska // to the center is an edge view, but it cannot scroll further in order to snap. 663911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska setupByConfig(config, true, new RecyclerView.LayoutParams(1000, 1000), 673911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska new RecyclerView.LayoutParams(1500, 1500)); 683911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska SnapHelper snapHelper = new LinearSnapHelper(); 693911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.expectIdleState(1); 703911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska snapHelper.attachToRecyclerView(mRecyclerView); 713911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.waitForSnap(10); 723911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska 733911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska // Record the current center view. 743911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska View view = findCenterView(mLayoutManager); 753911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska 763911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska int scrollDistance = (getViewDimension(view) / 2) - 1; 773911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska int scrollDist = config.mStackFromEnd == config.mReverseLayout 783911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska ? -scrollDistance : scrollDistance; 793911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.expectIdleState(1); 803911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska smoothScrollBy(scrollDist); 813911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.waitForSnap(10); 823911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.expectCallbacks(5); 833911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.assertNoCallbacks("There should be no callbacks after some time", 3); 843911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska } 853911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska 863911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska @Test 87c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void snapOnScrollSameView() throws Throwable { 88c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Config config = (Config) mConfig.clone(); 89c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupByConfig(config, true); 90c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupSnapHelper(); 91c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 92c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Record the current center view. 93c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View view = findCenterView(mLayoutManager); 94c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(view); 95c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 96c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int scrollDistance = (getViewDimension(view) / 2) - 1; 97c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance; 98c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(2); 99c587f7dba5a337169e854e235da59f595255d6ccAga Madurska smoothScrollBy(scrollDist); 100c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(10); 101c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 102c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Views have not changed 103c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View viewAfterFling = findCenterView(mLayoutManager); 1043911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska assertSame("The view should NOT have scrolled", view, viewAfterFling); 105c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(viewAfterFling); 106c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 107c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 108c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Test 109c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void snapOnScrollNextView() throws Throwable { 110c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Config config = (Config) mConfig.clone(); 111c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupByConfig(config, true); 112c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupSnapHelper(); 113c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 114c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Record the current center view. 115c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View view = findCenterView(mLayoutManager); 116c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(view); 117c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 118c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int scrollDistance = (getViewDimension(view) / 2) + 1; 119c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance; 120c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(2); 121c587f7dba5a337169e854e235da59f595255d6ccAga Madurska smoothScrollBy(scrollDist); 122c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(10); 123c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 124c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Views have not changed 125c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View viewAfterFling = findCenterView(mLayoutManager); 126c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertNotSame("The view should have scrolled", view, viewAfterFling); 127c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(viewAfterFling); 128c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 129c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 130c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Test 131c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void snapOnFlingSameView() throws Throwable { 132c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Config config = (Config) mConfig.clone(); 133c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupByConfig(config, true); 134c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupSnapHelper(); 135c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 136c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Record the current center view. 137c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View view = findCenterView(mLayoutManager); 138c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(view); 139c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 140c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Velocity small enough to not scroll to the next view. 141c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int velocity = (int) (1.000001 * mRecyclerView.getMinFlingVelocity()); 142c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int velocityDir = mReverseScroll ? -velocity : velocity; 143c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(2); 144c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertTrue(fling(velocityDir, velocityDir)); 145c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Wait for two settling scrolls: the initial one and the corrective one. 146c587f7dba5a337169e854e235da59f595255d6ccAga Madurska waitForIdleScroll(mRecyclerView); 147c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(100); 148c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 149c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View viewAfterFling = findCenterView(mLayoutManager); 150c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 151c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertSame("The view should NOT have scrolled", view, viewAfterFling); 152c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(viewAfterFling); 153c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 154c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 155c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Test 156c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void snapOnFlingNextView() throws Throwable { 157c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Config config = (Config) mConfig.clone(); 158c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupByConfig(config, true); 159c587f7dba5a337169e854e235da59f595255d6ccAga Madurska setupSnapHelper(); 160c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 161c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Record the current center view. 162c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View view = findCenterView(mLayoutManager); 163c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(view); 164c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 165c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Velocity high enough to scroll beyond the current view. 166c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int velocity = (int) (0.2 * mRecyclerView.getMaxFlingVelocity()); 167c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int velocityDir = mReverseScroll ? -velocity : velocity; 168c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(1); 169c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertTrue(fling(velocityDir, velocityDir)); 170c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(100); 171c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getInstrumentation().waitForIdleSync(); 172c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 173c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View viewAfterFling = findCenterView(mLayoutManager); 174c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 175c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertNotSame("The view should have scrolled", view, viewAfterFling); 176c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertCenterAligned(viewAfterFling); 177c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 178c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 179c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private void setupSnapHelper() throws Throwable { 180c587f7dba5a337169e854e235da59f595255d6ccAga Madurska SnapHelper snapHelper = new LinearSnapHelper(); 181c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(1); 182c587f7dba5a337169e854e235da59f595255d6ccAga Madurska snapHelper.attachToRecyclerView(mRecyclerView); 183c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(10); 184c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 185c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectLayouts(1); 186c587f7dba5a337169e854e235da59f595255d6ccAga Madurska scrollToPosition(mConfig.mItemCount / 2); 187c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForLayout(2); 188c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 189c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View view = findCenterView(mLayoutManager); 1903911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska int scrollDistance = distFromCenter(view) / 2; 1913911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska if (scrollDistance == 0) { 1923911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska return; 1933911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska } 1943911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska 195c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance; 196c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 197c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.expectIdleState(2); 198c587f7dba5a337169e854e235da59f595255d6ccAga Madurska smoothScrollBy(scrollDist); 199c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.waitForSnap(10); 200c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 201c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 202c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Nullable private View findCenterView(RecyclerView.LayoutManager layoutManager) { 203c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollHorizontally()) { 204c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return mRecyclerView.findChildViewUnder(mRecyclerView.getWidth() / 2, 0); 205c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 206c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return mRecyclerView.findChildViewUnder(0, mRecyclerView.getHeight() / 2); 207c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 208c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 209c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 210c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private int getViewDimension(View view) { 211c587f7dba5a337169e854e235da59f595255d6ccAga Madurska OrientationHelper helper; 212c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (mLayoutManager.canScrollHorizontally()) { 213c587f7dba5a337169e854e235da59f595255d6ccAga Madurska helper = OrientationHelper.createHorizontalHelper(mLayoutManager); 214c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 215c587f7dba5a337169e854e235da59f595255d6ccAga Madurska helper = OrientationHelper.createVerticalHelper(mLayoutManager); 216c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 217c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return helper.getDecoratedMeasurement(view); 218c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 219c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 220c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private void assertCenterAligned(View view) { 221c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (mLayoutManager.canScrollHorizontally()) { 222c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertEquals(mRecyclerView.getWidth() / 2, 223c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.getViewBounds(view).centerX()); 224c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 225c587f7dba5a337169e854e235da59f595255d6ccAga Madurska assertEquals(mRecyclerView.getHeight() / 2, 226c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mLayoutManager.getViewBounds(view).centerY()); 227c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 228c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 229c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 2303911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska private int distFromCenter(View view) { 2313911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska if (mLayoutManager.canScrollHorizontally()) { 2323911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska return Math.abs(mRecyclerView.getWidth() / 2 - 2333911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.getViewBounds(view).centerX()); 2343911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska } else { 2353911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska return Math.abs(mRecyclerView.getHeight() / 2 - 2363911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska mLayoutManager.getViewBounds(view).centerY()); 2373911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska } 2383911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska } 2393911e1c2d38e301d5ffbdf11f808fdc593dd83e9Aga Madurska 240c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private boolean fling(final int velocityX, final int velocityY) throws Throwable { 241c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final AtomicBoolean didStart = new AtomicBoolean(false); 24242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 243c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 244c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void run() { 245c587f7dba5a337169e854e235da59f595255d6ccAga Madurska boolean result = mRecyclerView.fling(velocityX, velocityY); 246c587f7dba5a337169e854e235da59f595255d6ccAga Madurska didStart.set(result); 247c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 248c587f7dba5a337169e854e235da59f595255d6ccAga Madurska }); 249c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (!didStart.get()) { 250c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return false; 251c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 252c587f7dba5a337169e854e235da59f595255d6ccAga Madurska waitForIdleScroll(mRecyclerView); 253c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return true; 254c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 255c587f7dba5a337169e854e235da59f595255d6ccAga Madurska} 256