10a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar/*
20a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
30a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar *
40a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
50a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * you may not use this file except in compliance with the License.
60a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * You may obtain a copy of the License at
70a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar *
80a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
90a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar *
100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * Unless required by applicable law or agreed to in writing, software
110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * See the License for the specific language governing permissions and
140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * limitations under the License.
150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar */
160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarpackage android.support.v7.widget;
180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
19e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertEquals;
200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.graphics.Rect;
220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.os.Parcel;
230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.os.Parcelable;
24754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.LargeTest;
250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.util.Log;
260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
27e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.Test;
28e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runner.RunWith;
29e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runners.Parameterized;
30e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas
310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.ArrayList;
320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.List;
330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.Map;
340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.UUID;
350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(Parameterized.class)
37dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar@LargeTest
380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarpublic class StaggeredGridLayoutManagerSavedStateTest extends BaseStaggeredGridLayoutManagerTest {
390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    private final Config mConfig;
400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    private final boolean mWaitForLayout;
410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    private final boolean mLoadDataAfterRestore;
420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    private final PostLayoutRunnable mPostLayoutOperations;
430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public StaggeredGridLayoutManagerSavedStateTest(
450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            Config config, boolean waitForLayout, boolean loadDataAfterRestore,
460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            PostLayoutRunnable postLayoutOperations) throws CloneNotSupportedException {
470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        this.mConfig = (Config) config.clone();
480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        this.mWaitForLayout = waitForLayout;
490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        this.mLoadDataAfterRestore = loadDataAfterRestore;
500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        this.mPostLayoutOperations = postLayoutOperations;
510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (postLayoutOperations != null) {
520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            postLayoutOperations.mTest = this;
530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    }
550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
56e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas    @Parameterized.Parameters(name = "config={0},waitForLayout={1},loadDataAfterRestore={2}"
57e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas            + ",postLayoutRunnable={3}")
580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public static List<Object[]> getParams() throws CloneNotSupportedException {
590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        List<Config> variations = createBaseVariations();
600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        PostLayoutRunnable[] postLayoutOptions = new PostLayoutRunnable[]{
620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                new PostLayoutRunnable() {
630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public void run() throws Throwable {
650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        // do nothing
660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public String describe() {
70142ca4048bd0de39ddbc0e8981914bdff103ead3Aurimas Liutikas                        return "doing_nothing";
710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                },
730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                new PostLayoutRunnable() {
740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public void run() throws Throwable {
760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().expectLayouts(1);
770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        scrollToPosition(adapter().getItemCount() * 3 / 4);
780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().waitForLayout(2);
790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public String describe() {
83142ca4048bd0de39ddbc0e8981914bdff103ead3Aurimas Liutikas                        return "scroll_to_position_item_count*3/4";
840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                },
860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                new PostLayoutRunnable() {
870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public void run() throws Throwable {
890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().expectLayouts(1);
900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        scrollToPositionWithOffset(adapter().getItemCount() / 3,
910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                                50);
920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().waitForLayout(2);
930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public String describe() {
97142ca4048bd0de39ddbc0e8981914bdff103ead3Aurimas Liutikas                        return "scroll_to_position_item_count/3_with_positive_offset";
980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                },
1000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                new PostLayoutRunnable() {
1010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
1020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public void run() throws Throwable {
1030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().expectLayouts(1);
1040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        scrollToPositionWithOffset(adapter().getItemCount() * 2 / 3,
1050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                                -50);
1060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        layoutManager().waitForLayout(2);
1070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
1080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    @Override
1100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    public String describe() {
111142ca4048bd0de39ddbc0e8981914bdff103ead3Aurimas Liutikas                        return "scroll_to_position_with_negative_offset";
1120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
1130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                }
1140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        };
1150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        boolean[] waitForLayoutOptions = new boolean[]{false, true};
1160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        boolean[] loadDataAfterRestoreOptions = new boolean[]{false, true};
1170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        List<Config> testVariations = new ArrayList<Config>();
1180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        testVariations.addAll(variations);
1190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        for (Config config : variations) {
1200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            if (config.mSpanCount < 2) {
1210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                continue;
1220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            }
1230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            final Config clone = (Config) config.clone();
1240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            clone.mItemCount = clone.mSpanCount - 1;
1250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            testVariations.add(clone);
1260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        List<Object[]> params = new ArrayList<>();
1290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        for (Config config : testVariations) {
1300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            for (PostLayoutRunnable runnable : postLayoutOptions) {
1310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                for (boolean waitForLayout : waitForLayoutOptions) {
1320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    for (boolean loadDataAfterRestore : loadDataAfterRestoreOptions) {
1330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        params.add(new Object[]{config, waitForLayout, loadDataAfterRestore,
1340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                                runnable});
1350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    }
1360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                }
1370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            }
1380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        return params;
1400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    }
1410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void savedState() throws Throwable {
1440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (DEBUG) {
1450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            Log.d(TAG, "testing saved state with wait for layout = " + mWaitForLayout + " config "
1460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    + mConfig + " post layout action " + mPostLayoutOperations.describe());
1470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        setupByConfig(mConfig);
1490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (mLoadDataAfterRestore) {
1500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            // We are going to re-create items, force non-random item size.
1510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mAdapter.mOnBindCallback = new OnBindCallback() {
1520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                @Override
1530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                void onBoundItem(TestViewHolder vh, int position) {
1540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                }
1550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
156e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas                @Override
1570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                boolean assignRandomSize() {
1580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    return false;
1590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                }
1600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            };
1610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        waitFirstLayout();
1630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (mWaitForLayout) {
1640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mPostLayoutOperations.run();
1650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        getInstrumentation().waitForIdleSync();
1670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        final int firstCompletelyVisiblePosition = mLayoutManager.findFirstVisibleItemPositionInt();
1680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
1690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        Parcelable savedState = mRecyclerView.onSaveInstanceState();
1700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        // we append a suffix to the parcelable to test out of bounds
1710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        String parcelSuffix = UUID.randomUUID().toString();
1720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        Parcel parcel = Parcel.obtain();
1730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        savedState.writeToParcel(parcel, 0);
1740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        parcel.writeString(parcelSuffix);
1750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        removeRecyclerView();
1760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        // reset for reading
1770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        parcel.setDataPosition(0);
1780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        // re-create
1790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
1800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        removeRecyclerView();
1810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        final int itemCount = mAdapter.getItemCount();
183959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        List<Item> mItems = new ArrayList<>();
1840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (mLoadDataAfterRestore) {
185959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            mItems.addAll(mAdapter.mItems);
1860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mAdapter.deleteAndNotify(0, itemCount);
1870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
1880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        RecyclerView restored = new RecyclerView(getActivity());
1900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        mLayoutManager = new WrappedLayoutManager(mConfig.mSpanCount, mConfig.mOrientation);
1910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        mLayoutManager.setGapStrategy(mConfig.mGapStrategy);
1920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        restored.setLayoutManager(mLayoutManager);
1930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        // use the same adapter for Rect matching
1940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        restored.setAdapter(mAdapter);
1950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        restored.onRestoreInstanceState(savedState);
1960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
1970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (mLoadDataAfterRestore) {
198959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            mAdapter.resetItemsTo(mItems);
1990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
2020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                parcel.readString());
2030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        mLayoutManager.expectLayouts(1);
2040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        setRecyclerView(restored);
2050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        mLayoutManager.waitForLayout(2);
2060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals(mConfig + " on saved state, reverse layout should be preserved",
2070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                mConfig.mReverseLayout, mLayoutManager.getReverseLayout());
2080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals(mConfig + " on saved state, orientation should be preserved",
2090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                mConfig.mOrientation, mLayoutManager.getOrientation());
2100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals(mConfig + " on saved state, span count should be preserved",
2110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                mConfig.mSpanCount, mLayoutManager.getSpanCount());
2120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals(mConfig + " on saved state, gap strategy should be preserved",
2130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                mConfig.mGapStrategy, mLayoutManager.getGapStrategy());
2140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        assertEquals(mConfig + " on saved state, first completely visible child position should"
2150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                        + " be preserved", firstCompletelyVisiblePosition,
2160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                mLayoutManager.findFirstVisibleItemPositionInt());
2170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        if (mWaitForLayout) {
2180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            final boolean strictItemEquality = !mLoadDataAfterRestore;
2190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            assertRectSetsEqual(mConfig + "\npost layout op:" + mPostLayoutOperations.describe()
2200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                            + ": on restore, previous view positions should be preserved",
2210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar                    before, mLayoutManager.collectChildCoordinates(), strictItemEquality);
2220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        // TODO add tests for changing values after restore before layout
2240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    }
2250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    static abstract class PostLayoutRunnable {
2270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        StaggeredGridLayoutManagerSavedStateTest mTest;
2280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public void setup(StaggeredGridLayoutManagerSavedStateTest test) {
2290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mTest = test;
2300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public GridTestAdapter adapter() {
2330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            return mTest.mAdapter;
2340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public WrappedLayoutManager layoutManager() {
2370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            return mTest.mLayoutManager;
2380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public void scrollToPositionWithOffset(int position, int offset) throws Throwable {
2410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mTest.scrollToPositionWithOffset(position, offset);
2420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public void scrollToPosition(int position) throws Throwable {
2450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            mTest.scrollToPosition(position);
2460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        abstract void run() throws Throwable;
2490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        abstract String describe();
2510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
2520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        @Override
2530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        public String toString() {
2540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            return describe();
2550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        }
2560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    }
2570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar}
258