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