GridLayoutManagerTest.java revision 061c3284cf284424ae084799dd7ba5c8d6d59faa
173304eff156157f62075215e795e774803a6f96aYigit Boyar/*
273304eff156157f62075215e795e774803a6f96aYigit Boyar * Copyright (C) 2014 The Android Open Source Project
373304eff156157f62075215e795e774803a6f96aYigit Boyar *
473304eff156157f62075215e795e774803a6f96aYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
573304eff156157f62075215e795e774803a6f96aYigit Boyar * you may not use this file except in compliance with the License.
673304eff156157f62075215e795e774803a6f96aYigit Boyar * You may obtain a copy of the License at
773304eff156157f62075215e795e774803a6f96aYigit Boyar *
873304eff156157f62075215e795e774803a6f96aYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
973304eff156157f62075215e795e774803a6f96aYigit Boyar *
1073304eff156157f62075215e795e774803a6f96aYigit Boyar * Unless required by applicable law or agreed to in writing, software
1173304eff156157f62075215e795e774803a6f96aYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1273304eff156157f62075215e795e774803a6f96aYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1373304eff156157f62075215e795e774803a6f96aYigit Boyar * See the License for the specific language governing permissions and
1473304eff156157f62075215e795e774803a6f96aYigit Boyar * limitations under the License.
1573304eff156157f62075215e795e774803a6f96aYigit Boyar */
1673304eff156157f62075215e795e774803a6f96aYigit Boyar
1773304eff156157f62075215e795e774803a6f96aYigit Boyarpackage android.support.v7.widget;
1873304eff156157f62075215e795e774803a6f96aYigit Boyar
19061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.content.Context;
20061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.util.Log;
21061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.View;
22061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.ViewGroup;
23061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
24061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.ArrayList;
25061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Arrays;
26061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.BitSet;
27061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.HashSet;
28061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.List;
29061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Set;
30061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.concurrent.CountDownLatch;
31061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
32061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
33061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL;
34061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static java.util.concurrent.TimeUnit.SECONDS;
35061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
3673304eff156157f62075215e795e774803a6f96aYigit Boyarpublic class GridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
37061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
38061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    static final String TAG = "GridLayoutManagerTest";
39061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
40061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    static final boolean DEBUG = false;
41061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
42061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    WrappedGridLayoutManager mGlm;
43061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
44061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    GridTestAdapter mAdapter;
45061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
46061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    final List<Config> mBaseVariations = new ArrayList<Config>();
47061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
48061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    @Override
49061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    protected void setUp() throws Exception {
50061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        super.setUp();
51061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
52061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            for (boolean reverseLayout : new boolean[]{false, true}) {
53061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                for (int spanCount : new int[]{1, 3, 4}) {
54061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    mBaseVariations.add(new Config(spanCount, orientation, reverseLayout));
55061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
56061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
57061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
58061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
59061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
60061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public RecyclerView setupBasic(Config config) throws Throwable {
61061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        return setupBasic(config, new GridTestAdapter(config.mItemCount));
62061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
63061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
64061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable {
65061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
66061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mAdapter = testAdapter;
67061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
68061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                config.mReverseLayout);
69061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mAdapter.assignSpanSizeLookup(mGlm);
70061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        recyclerView.setAdapter(mAdapter);
71061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        recyclerView.setLayoutManager(mGlm);
72061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        return recyclerView;
73061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
74061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
75061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void waitForFirstLayout(RecyclerView recyclerView) throws Throwable {
76061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.expectLayout(1);
77061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        setRecyclerView(recyclerView);
78061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.waitForLayout(2);
79061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
80061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
81061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testLayoutParams() throws Throwable {
82061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        layoutParamsTest(GridLayoutManager.HORIZONTAL);
83061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        removeRecyclerView();
84061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        layoutParamsTest(GridLayoutManager.VERTICAL);
85061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
86061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
87061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void layoutParamsTest(final int orientation) throws Throwable {
88061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation),
89061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                new GridTestAdapter(100) {
90061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    @Override
91061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    public void onBindViewHolder(TestViewHolder holder,
92061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            int position) {
93061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        super.onBindViewHolder(holder, position);
94061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
95061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        GridLayoutManager.LayoutParams glp = null;
96061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (lp == null) {
97061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            glp = (GridLayoutManager.LayoutParams) mGlm
98061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                    .generateDefaultLayoutParams();
99061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        } else {
100061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp);
101061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
102061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        int val = 0;
103061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        switch (position % 5) {
104061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            case 0:
105061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                val = 10;
106061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                break;
107061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            case 1:
108061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                val = 30;
109061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                break;
110061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            case 2:
111061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                val = GridLayoutManager.LayoutParams.WRAP_CONTENT;
112061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                break;
113061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            case 3:
114061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                val = GridLayoutManager.LayoutParams.FILL_PARENT;
115061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                break;
116061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            case 4:
117061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                val = 200;
118061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                break;
119061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
120061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (orientation == GridLayoutManager.VERTICAL) {
121061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            glp.height = val;
122061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        } else {
123061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            glp.width = val;
124061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
125061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        holder.itemView.setLayoutParams(glp);
126061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    }
127061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                });
128061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        waitForFirstLayout(rv);
129061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final OrientationHelper helper = mGlm.mOrientationHelper;
130061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2)));
131061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(10, helper.getDecoratedMeasurement(mGlm.findViewByPosition(0)));
132061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(30, helper.getDecoratedMeasurement(mGlm.findViewByPosition(1)));
133061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0)));
134061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1)));
135061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2)));
136061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
137061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3)));
138061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(200, helper.getDecoratedMeasurement(mGlm.findViewByPosition(4)));
139061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3)));
140061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4)));
141061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5)));
142061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
143061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
144061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    private int getSize(View view) {
145061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        if (mGlm.getOrientation() == GridLayoutManager.HORIZONTAL) {
146061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            return view.getWidth();
147061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
148061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        return view.getHeight();
149061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
150061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
15173304eff156157f62075215e795e774803a6f96aYigit Boyar    public void testAnchorUpdate() throws InterruptedException {
15273304eff156157f62075215e795e774803a6f96aYigit Boyar        GridLayoutManager glm = new GridLayoutManager(getActivity(), 11);
15373304eff156157f62075215e795e774803a6f96aYigit Boyar        final GridLayoutManager.SpanSizeLookup spanSizeLookup
15473304eff156157f62075215e795e774803a6f96aYigit Boyar                = new GridLayoutManager.SpanSizeLookup() {
15573304eff156157f62075215e795e774803a6f96aYigit Boyar            @Override
15673304eff156157f62075215e795e774803a6f96aYigit Boyar            public int getSpanSize(int position) {
15773304eff156157f62075215e795e774803a6f96aYigit Boyar                if (position > 200) {
15873304eff156157f62075215e795e774803a6f96aYigit Boyar                    return 100;
15973304eff156157f62075215e795e774803a6f96aYigit Boyar                }
16073304eff156157f62075215e795e774803a6f96aYigit Boyar                if (position > 20) {
16173304eff156157f62075215e795e774803a6f96aYigit Boyar                    return 2;
16273304eff156157f62075215e795e774803a6f96aYigit Boyar                }
16373304eff156157f62075215e795e774803a6f96aYigit Boyar                return 1;
16473304eff156157f62075215e795e774803a6f96aYigit Boyar            }
16573304eff156157f62075215e795e774803a6f96aYigit Boyar        };
16673304eff156157f62075215e795e774803a6f96aYigit Boyar        glm.setSpanSizeLookup(spanSizeLookup);
16773304eff156157f62075215e795e774803a6f96aYigit Boyar        glm.mAnchorInfo.mPosition = 11;
16842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        RecyclerView.State state = new RecyclerView.State();
169061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        state.mItemCount = 1000;
1709ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar        glm.onAnchorReady(state, glm.mAnchorInfo);
17173304eff156157f62075215e795e774803a6f96aYigit Boyar        assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition);
17273304eff156157f62075215e795e774803a6f96aYigit Boyar
17373304eff156157f62075215e795e774803a6f96aYigit Boyar        glm.mAnchorInfo.mPosition = 13;
1749ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar        glm.onAnchorReady(state, glm.mAnchorInfo);
17573304eff156157f62075215e795e774803a6f96aYigit Boyar        assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition);
17673304eff156157f62075215e795e774803a6f96aYigit Boyar
17773304eff156157f62075215e795e774803a6f96aYigit Boyar        glm.mAnchorInfo.mPosition = 23;
1789ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar        glm.onAnchorReady(state, glm.mAnchorInfo);
17973304eff156157f62075215e795e774803a6f96aYigit Boyar        assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition);
18073304eff156157f62075215e795e774803a6f96aYigit Boyar
18173304eff156157f62075215e795e774803a6f96aYigit Boyar        glm.mAnchorInfo.mPosition = 35;
1829ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar        glm.onAnchorReady(state, glm.mAnchorInfo);
18373304eff156157f62075215e795e774803a6f96aYigit Boyar        assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition);
18473304eff156157f62075215e795e774803a6f96aYigit Boyar    }
18573304eff156157f62075215e795e774803a6f96aYigit Boyar
18673304eff156157f62075215e795e774803a6f96aYigit Boyar    public void testSpanLookup() {
187061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        spanLookupTest(false);
188061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
189061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
190061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testSpanLookupWithCache() {
191061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        spanLookupTest(true);
192061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
193061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
194061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testSpanLookupCache() {
195061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final GridLayoutManager.SpanSizeLookup ssl
196061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                = new GridLayoutManager.SpanSizeLookup() {
197061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            @Override
198061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            public int getSpanSize(int position) {
199061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                if (position > 6) {
200061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    return 2;
201061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
202061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                return 1;
203061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
204061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        };
205061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.setSpanIndexCacheEnabled(true);
206061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2));
207061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.getCachedSpanIndex(4, 5);
208061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3));
209061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        // this should not happen and if happens, it is better to return -1
210061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
211061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5));
212061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100));
213061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.getCachedSpanIndex(6, 5);
214061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
215061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6));
216061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
217061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.getCachedSpanIndex(12, 5);
218061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13));
219061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12));
220061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
221061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        for (int i = 0; i < 6; i++) {
222061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            ssl.getCachedSpanIndex(i, 5);
223061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
224061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
225061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        for (int i = 1; i < 7; i++) {
226061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            assertEquals("reference child right before " + i, i - 1,
227061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    ssl.findReferenceIndexFromCache(i));
228061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
229061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0));
230061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
231061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
232061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void spanLookupTest(boolean enableCache) {
23373304eff156157f62075215e795e774803a6f96aYigit Boyar        final GridLayoutManager.SpanSizeLookup ssl
23473304eff156157f62075215e795e774803a6f96aYigit Boyar                = new GridLayoutManager.SpanSizeLookup() {
23573304eff156157f62075215e795e774803a6f96aYigit Boyar            @Override
23673304eff156157f62075215e795e774803a6f96aYigit Boyar            public int getSpanSize(int position) {
23773304eff156157f62075215e795e774803a6f96aYigit Boyar                if (position > 200) {
23873304eff156157f62075215e795e774803a6f96aYigit Boyar                    return 100;
23973304eff156157f62075215e795e774803a6f96aYigit Boyar                }
24073304eff156157f62075215e795e774803a6f96aYigit Boyar                if (position > 6) {
24173304eff156157f62075215e795e774803a6f96aYigit Boyar                    return 2;
24273304eff156157f62075215e795e774803a6f96aYigit Boyar                }
24373304eff156157f62075215e795e774803a6f96aYigit Boyar                return 1;
24473304eff156157f62075215e795e774803a6f96aYigit Boyar            }
24573304eff156157f62075215e795e774803a6f96aYigit Boyar        };
246061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.setSpanIndexCacheEnabled(enableCache);
247061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(0, ssl.getCachedSpanIndex(0, 5));
248061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(4, ssl.getCachedSpanIndex(4, 5));
249061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(0, ssl.getCachedSpanIndex(5, 5));
250061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(1, ssl.getCachedSpanIndex(6, 5));
251061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(2, ssl.getCachedSpanIndex(7, 5));
252061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(2, ssl.getCachedSpanIndex(9, 5));
253061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals(0, ssl.getCachedSpanIndex(8, 5));
254061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
255061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
256061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testNotifyDataSetChange() throws Throwable {
257061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
258061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup();
259061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        ssl.setSpanIndexCacheEnabled(true);
260061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        waitForFirstLayout(recyclerView);
261061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0);
262061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final Callback callback = new Callback() {
263061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            @Override
264061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
265061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                if (!state.isPreLayout()) {
266061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size());
267061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
268061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
269061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
270061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            @Override
271061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
272061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                if (!state.isPreLayout()) {
273061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0);
274061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
275061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
276061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        };
277061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.mCallbacks.add(callback);
278061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.expectLayout(2);
279061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mAdapter.deleteAndNotify(2, 3);
280061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.waitForLayout(2);
281061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        checkForMainThreadException();
282061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
283061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
284061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testScrollBackAndPreservePositions() throws Throwable {
285061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        for (Config config : mBaseVariations) {
286061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            config.mItemCount = 150;
287061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            scrollBackAndPreservePositionsTest(config);
288061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            removeRecyclerView();
289061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
290061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
291061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
292061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void testCacheSpanIndices() throws Throwable {
293061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final RecyclerView rv = setupBasic(new Config(3, 100));
294061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true);
295061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        waitForFirstLayout(rv);
296061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup;
297061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0);
298061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("item index 5 should be in span 2", 2,
299061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
300061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.expectLayout(2);
301061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mAdapter.mFullSpanItems.add(4);
302061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mAdapter.changeAndNotify(4, 1);
303061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        mGlm.waitForLayout(2);
304061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        assertEquals("item index 5 should be in span 2", 0,
305061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
306061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
307061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
308061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    GridLayoutManager.LayoutParams getLp(View view) {
309061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        return (GridLayoutManager.LayoutParams) view.getLayoutParams();
310061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
311061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
312061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable {
313061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final RecyclerView rv = setupBasic(config);
314061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) {
315061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mAdapter.setFullSpan(i);
316061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
317061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        waitForFirstLayout(rv);
318061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final int[] globalPositions = new int[mAdapter.getItemCount()];
319061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        Arrays.fill(globalPositions, Integer.MIN_VALUE);
320061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20)
321061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                * (config.mReverseLayout ? -1 : 1);
322061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final String logPrefix = config.toString();
323061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        final int[] globalPos = new int[1];
324061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        runTestOnUiThread(new Runnable() {
325061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            @Override
326061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            public void run() {
327061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                int globalScrollPosition = 0;
328061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                int visited = 0;
329061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                while (visited < mAdapter.getItemCount()) {
330061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
331061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        View child = mRecyclerView.getChildAt(i);
332061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        final int pos = mRecyclerView.getChildPosition(child);
333061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (globalPositions[pos] != Integer.MIN_VALUE) {
334061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            continue;
335061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
336061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        visited++;
337061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
338061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                child.getLayoutParams();
339061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (config.mReverseLayout) {
340061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            globalPositions[pos] = globalScrollPosition +
341061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                    mGlm.mOrientationHelper.getDecoratedEnd(child);
342061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        } else {
343061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            globalPositions[pos] = globalScrollPosition +
344061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                    mGlm.mOrientationHelper.getDecoratedStart(child);
345061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
346061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        assertEquals(logPrefix + " span index should match",
347061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()),
348061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                lp.getSpanIndex());
349061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    }
350061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    int scrolled = mGlm.scrollBy(scrollStep,
351061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            mRecyclerView.mRecycler, mRecyclerView.mState);
352061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    globalScrollPosition += scrolled;
353061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    if (scrolled == 0) {
354061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        assertEquals(
355061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                logPrefix + " If scroll is complete, all views should be visited",
356061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                visited, mAdapter.getItemCount());
357061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    }
358061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
359061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                if (DEBUG) {
360061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions));
361061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
362061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                globalPos[0] = globalScrollPosition;
363061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
364061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        });
365061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        checkForMainThreadException();
366061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        runTestOnUiThread(new Runnable() {
367061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            @Override
368061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            public void run() {
369061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                int globalScrollPosition = globalPos[0];
370061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                // now scroll back and make sure global positions match
371061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                BitSet shouldTest = new BitSet(mAdapter.getItemCount());
372061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                shouldTest.set(0, mAdapter.getItemCount() - 1, true);
373061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                String assertPrefix = config
374061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        + " global pos must match when scrolling in reverse for position ";
375061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                int scrollAmount = Integer.MAX_VALUE;
376061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                while (!shouldTest.isEmpty() && scrollAmount != 0) {
377061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
378061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        View child = mRecyclerView.getChildAt(i);
379061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        int pos = mRecyclerView.getChildPosition(child);
380061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (!shouldTest.get(pos)) {
381061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            continue;
382061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
383061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
384061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                child.getLayoutParams();
385061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        shouldTest.clear(pos);
386061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        int globalPos;
387061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        if (config.mReverseLayout) {
388061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            globalPos = globalScrollPosition +
389061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                    mGlm.mOrientationHelper.getDecoratedEnd(child);
390061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        } else {
391061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            globalPos = globalScrollPosition +
392061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                    mGlm.mOrientationHelper.getDecoratedStart(child);
393061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        }
394061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        assertEquals(assertPrefix + pos,
395061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                globalPositions[pos], globalPos);
396061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                        assertEquals("span index should match",
397061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()),
398061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                                lp.getSpanIndex());
399061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    }
400061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    scrollAmount = mGlm.scrollBy(-scrollStep,
401061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                            mRecyclerView.mRecycler, mRecyclerView.mState);
402061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    globalScrollPosition += scrollAmount;
403061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
404061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                assertTrue("all views should be seen", shouldTest.isEmpty());
405061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
406061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        });
407061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        checkForMainThreadException();
408061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
409061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
410061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    class WrappedGridLayoutManager extends GridLayoutManager {
411061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
412061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        CountDownLatch mLayoutLatch;
413061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
414061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        List<Callback> mCallbacks = new ArrayList<Callback>();
415061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
416061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public WrappedGridLayoutManager(Context context, int spanCount) {
417061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            super(context, spanCount);
418061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
419061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
420061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public WrappedGridLayoutManager(Context context, int spanCount, int orientation,
421061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                boolean reverseLayout) {
422061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            super(context, spanCount, orientation, reverseLayout);
423061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
424061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
425061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        @Override
426061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
427061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            try {
428061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                for (Callback callback : mCallbacks) {
429061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    callback.onBeforeLayout(recycler, state);
430061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
431061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                super.onLayoutChildren(recycler, state);
432061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                for (Callback callback : mCallbacks) {
433061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    callback.onAfterLayout(recycler, state);
434061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
435061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            } catch (Throwable t) {
436061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                postExceptionToInstrumentation(t);
437061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
438061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mLayoutLatch.countDown();
439061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
440061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
441061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public void expectLayout(int layoutCount) {
442061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mLayoutLatch = new CountDownLatch(layoutCount);
443061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
444061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
445061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public void waitForLayout(int seconds) throws InterruptedException {
446061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mLayoutLatch.await(seconds, SECONDS);
447061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
448061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
449061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
450061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    class Config {
451061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
452061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        int mSpanCount;
453061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        int mOrientation = GridLayoutManager.VERTICAL;
454061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        int mItemCount = 1000;
455061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        boolean mReverseLayout = false;
456061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
457061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        Config(int spanCount, int itemCount) {
458061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mSpanCount = spanCount;
459061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mItemCount = itemCount;
460061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
461061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
462061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public Config(int spanCount, int orientation, boolean reverseLayout) {
463061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mSpanCount = spanCount;
464061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mOrientation = orientation;
465061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mReverseLayout = reverseLayout;
466061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
467061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
468061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        Config orientation(int orientation) {
469061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            mOrientation = orientation;
470061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            return this;
471061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
472061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
473061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        @Override
474061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public String toString() {
475061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            return "Config{" +
476061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    "mSpanCount=" + mSpanCount +
477061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    ", mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v") +
478061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    ", mItemCount=" + mItemCount +
479061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    ", mReverseLayout=" + mReverseLayout +
480061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    '}';
481061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
482061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
483061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
484061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    class GridTestAdapter extends TestAdapter {
485061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
486061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        Set<Integer> mFullSpanItems = new HashSet<Integer>();
487061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
488061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        GridTestAdapter(int count) {
489061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            super(count);
490061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
491061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
492061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        void setFullSpan(int... items) {
493061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            for (int i : items) {
494061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                mFullSpanItems.add(i);
495061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            }
496061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
497061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
498061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        void assignSpanSizeLookup(final GridLayoutManager glm) {
499061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
500061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                @Override
501061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                public int getSpanSize(int position) {
502061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                    return mFullSpanItems.contains(position) ? glm.getSpanCount() : 1;
503061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar                }
504061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar            });
505061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
506061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    }
507061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
508061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    class Callback {
509061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
510061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
511061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
512061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar
513061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
514061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar        }
51573304eff156157f62075215e795e774803a6f96aYigit Boyar    }
51673304eff156157f62075215e795e774803a6f96aYigit Boyar}
517