14143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar/* 24143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 34143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * 44143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 54143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * you may not use this file except in compliance with the License. 64143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * You may obtain a copy of the License at 74143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * 84143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 94143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * 104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * Unless required by applicable law or agreed to in writing, software 114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * See the License for the specific language governing permissions and 144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * limitations under the License. 154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar */ 164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarpackage android.support.v7.widget; 184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 19754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertEquals; 20754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertSame; 21754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertTrue; 22f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar 23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest; 244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.util.Log; 254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.View; 264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 27754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.junit.Test; 28754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.junit.runner.RunWith; 29754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.junit.runners.Parameterized; 30754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.Arrays; 324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.BitSet; 334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.List; 344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 35754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas@MediumTest 364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar@RunWith(Parameterized.class) 374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarpublic class GridLayoutManagerBaseConfigSetTest extends BaseGridLayoutManagerTest { 384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Parameterized.Parameters(name = "{0}") 394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public static List<Config> params() { 404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return createBaseVariations(); 414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar private final Config mConfig; 444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public GridLayoutManagerBaseConfigSetTest(Config config) { 464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mConfig = config; 474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Test 504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void scrollBackAndPreservePositions() throws Throwable { 514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Config config = (Config) mConfig.clone(); 524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar config.mItemCount = 150; 534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar scrollBackAndPreservePositionsTest(config); 544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable { 574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final RecyclerView rv = setupBasic(config); 584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) { 594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mAdapter.setFullSpan(i); 604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar waitForFirstLayout(rv); 624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int[] globalPositions = new int[mAdapter.getItemCount()]; 634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Arrays.fill(globalPositions, Integer.MIN_VALUE); 644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20) 654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * (config.mReverseLayout ? -1 : 1); 664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final String logPrefix = config.toString(); 674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int[] globalPos = new int[1]; 6842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertSame("test sanity", mRecyclerView, rv); 724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalScrollPosition = 0; 734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int visited = 0; 744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar while (visited < mAdapter.getItemCount()) { 754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar View child = mRecyclerView.getChildAt(i); 774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int pos = mRecyclerView.getChildLayoutPosition(child); 784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (globalPositions[pos] != Integer.MIN_VALUE) { 794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar continue; 804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar visited++; 824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar child.getLayoutParams(); 844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (config.mReverseLayout) { 854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos] = globalScrollPosition + 864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } else { 884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos] = globalScrollPosition + 894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(logPrefix + " span index should match", 924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar lp.getSpanIndex()); 944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int scrolled = mGlm.scrollBy(scrollStep, 964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalScrollPosition += scrolled; 984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (scrolled == 0) { 994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals( 1004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar logPrefix + " If scroll is complete, all views should be visited", 1014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar visited, mAdapter.getItemCount()); 1024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (DEBUG) { 1054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions)); 1064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos[0] = globalScrollPosition; 1084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar checkForMainThreadException(); 1114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar // test sanity, ensure scroll happened 11242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 1144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 1154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int childCount = mGlm.getChildCount(); 1164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final BitSet expectedPositions = new BitSet(); 1174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < childCount; i ++) { 1184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar expectedPositions.set(mAdapter.getItemCount() - i - 1); 1194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i <childCount; i ++) { 1214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final View view = mGlm.getChildAt(i); 1224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int position = mGlm.getPosition(view); 1234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertTrue("child position should be in last page", expectedPositions.get(position)); 1244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar getInstrumentation().waitForIdleSync(); 12842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 1304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 1314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalScrollPosition = globalPos[0]; 1324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar // now scroll back and make sure global positions match 1334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar BitSet shouldTest = new BitSet(mAdapter.getItemCount()); 1344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar shouldTest.set(0, mAdapter.getItemCount() - 1, true); 1354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar String assertPrefix = config 1364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar + " global pos must match when scrolling in reverse for position "; 1374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int scrollAmount = Integer.MAX_VALUE; 1384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar while (!shouldTest.isEmpty() && scrollAmount != 0) { 1394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 1404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar View child = mRecyclerView.getChildAt(i); 1414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int pos = mRecyclerView.getChildLayoutPosition(child); 1424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (!shouldTest.get(pos)) { 1434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar continue; 1444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 1464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar child.getLayoutParams(); 1474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar shouldTest.clear(pos); 1484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalPos; 1494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (config.mReverseLayout) { 1504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos = globalScrollPosition + 1514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 1524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } else { 1534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos = globalScrollPosition + 1544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 1554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(assertPrefix + pos, 1574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos], globalPos); 1584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals("span index should match", 1594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 1604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar lp.getSpanIndex()); 1614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar scrollAmount = mGlm.scrollBy(-scrollStep, 1634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 1644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalScrollPosition += scrollAmount; 1654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertTrue("all views should be seen", shouldTest.isEmpty()); 1674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar checkForMainThreadException(); 1704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar} 172