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 194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport org.junit.Test; 204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport org.junit.runner.RunWith; 214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport org.junit.runners.Parameterized; 22f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar 234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.util.Log; 244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.view.View; 254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.Arrays; 274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.BitSet; 284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport java.util.List; 294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static org.junit.Assert.assertEquals; 314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static org.junit.Assert.assertSame; 324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static org.junit.Assert.assertTrue; 334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar@RunWith(Parameterized.class) 354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarpublic class GridLayoutManagerBaseConfigSetTest extends BaseGridLayoutManagerTest { 364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Parameterized.Parameters(name = "{0}") 374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public static List<Config> params() { 384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return createBaseVariations(); 394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar private final Config mConfig; 424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public GridLayoutManagerBaseConfigSetTest(Config config) { 444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mConfig = config; 454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Test 484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void scrollBackAndPreservePositions() throws Throwable { 494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Config config = (Config) mConfig.clone(); 504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar config.mItemCount = 150; 514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar scrollBackAndPreservePositionsTest(config); 524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable { 554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final RecyclerView rv = setupBasic(config); 564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) { 574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mAdapter.setFullSpan(i); 584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar waitForFirstLayout(rv); 604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int[] globalPositions = new int[mAdapter.getItemCount()]; 614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Arrays.fill(globalPositions, Integer.MIN_VALUE); 624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20) 634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar * (config.mReverseLayout ? -1 : 1); 644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final String logPrefix = config.toString(); 654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int[] globalPos = new int[1]; 664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertSame("test sanity", mRecyclerView, rv); 704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalScrollPosition = 0; 714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int visited = 0; 724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar while (visited < mAdapter.getItemCount()) { 734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar View child = mRecyclerView.getChildAt(i); 754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int pos = mRecyclerView.getChildLayoutPosition(child); 764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (globalPositions[pos] != Integer.MIN_VALUE) { 774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar continue; 784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar visited++; 804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar child.getLayoutParams(); 824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (config.mReverseLayout) { 834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos] = globalScrollPosition + 844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } else { 864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos] = globalScrollPosition + 874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(logPrefix + " span index should match", 904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar lp.getSpanIndex()); 924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int scrolled = mGlm.scrollBy(scrollStep, 944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalScrollPosition += scrolled; 964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (scrolled == 0) { 974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals( 984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar logPrefix + " If scroll is complete, all views should be visited", 994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar visited, mAdapter.getItemCount()); 1004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (DEBUG) { 1034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions)); 1044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos[0] = globalScrollPosition; 1064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar checkForMainThreadException(); 1094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar // test sanity, ensure scroll happened 1104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 1114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 1124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 1134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final int childCount = mGlm.getChildCount(); 1144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final BitSet expectedPositions = new BitSet(); 1154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < childCount; i ++) { 1164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar expectedPositions.set(mAdapter.getItemCount() - i - 1); 1174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1184143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i <childCount; i ++) { 1194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final View view = mGlm.getChildAt(i); 1204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int position = mGlm.getPosition(view); 1214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertTrue("child position should be in last page", expectedPositions.get(position)); 1224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1244143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar getInstrumentation().waitForIdleSync(); 1264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 1274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 1284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 1294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalScrollPosition = globalPos[0]; 1304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar // now scroll back and make sure global positions match 1314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar BitSet shouldTest = new BitSet(mAdapter.getItemCount()); 1324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar shouldTest.set(0, mAdapter.getItemCount() - 1, true); 1334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar String assertPrefix = config 1344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar + " global pos must match when scrolling in reverse for position "; 1354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int scrollAmount = Integer.MAX_VALUE; 1364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar while (!shouldTest.isEmpty() && scrollAmount != 0) { 1374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 1384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar View child = mRecyclerView.getChildAt(i); 1394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int pos = mRecyclerView.getChildLayoutPosition(child); 1404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (!shouldTest.get(pos)) { 1414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar continue; 1424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 1444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar child.getLayoutParams(); 1454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar shouldTest.clear(pos); 1464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar int globalPos; 1474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (config.mReverseLayout) { 1484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos = globalScrollPosition + 1494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 1504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } else { 1514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPos = globalScrollPosition + 1524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 1534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(assertPrefix + pos, 1554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalPositions[pos], globalPos); 1564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals("span index should match", 1574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 1584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar lp.getSpanIndex()); 1594143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar scrollAmount = mGlm.scrollBy(-scrollStep, 1614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 1624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar globalScrollPosition += scrollAmount; 1634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertTrue("all views should be seen", shouldTest.isEmpty()); 1654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 1674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar checkForMainThreadException(); 1684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar} 170