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; 20a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.AccessibilityDelegateCompat; 21a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 22061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.util.Log; 23061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.View; 24061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.ViewGroup; 25061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 26061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.ArrayList; 27061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Arrays; 28061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.BitSet; 29afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.HashMap; 30061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.HashSet; 31061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.List; 32afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.Map; 33061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Set; 34061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.concurrent.CountDownLatch; 35061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 36061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; 37061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL; 38061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static java.util.concurrent.TimeUnit.SECONDS; 39061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 4073304eff156157f62075215e795e774803a6f96aYigit Boyarpublic class GridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest { 41061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 42061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final String TAG = "GridLayoutManagerTest"; 43061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 44061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final boolean DEBUG = false; 45061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 46061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar WrappedGridLayoutManager mGlm; 47061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 48061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter mAdapter; 49061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 50061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final List<Config> mBaseVariations = new ArrayList<Config>(); 51061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 52061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 53061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar protected void setUp() throws Exception { 54061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.setUp(); 55061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 56061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (boolean reverseLayout : new boolean[]{false, true}) { 57061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int spanCount : new int[]{1, 3, 4}) { 58061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mBaseVariations.add(new Config(spanCount, orientation, reverseLayout)); 59061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 60061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 61061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 62061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 63061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 64061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config) throws Throwable { 65061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return setupBasic(config, new GridTestAdapter(config.mItemCount)); 66061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 67061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 68061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable { 69061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 70061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter = testAdapter; 71061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation, 72061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mReverseLayout); 73061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.assignSpanSizeLookup(mGlm); 74061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setAdapter(mAdapter); 75061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setLayoutManager(mGlm); 76061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return recyclerView; 77061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 78061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 79061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForFirstLayout(RecyclerView recyclerView) throws Throwable { 80061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(1); 81061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar setRecyclerView(recyclerView); 82061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 83061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 84061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 8542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomWidthInHorizontal() throws Throwable { 8642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, HORIZONTAL, false)); 8742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 8842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 8942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomHeightInVertical() throws Throwable { 9042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, VERTICAL, false)); 9142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 9242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 9342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void customSizeInScrollDirectionTest(final Config config) throws Throwable { 9442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] sizePerPosition = new int[]{3, 5, 9, 21, 3, 5, 9, 6, 9, 1}; 9542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] expectedSizePerPosition = new int[]{9, 9, 9, 21, 3, 5, 9, 9, 9, 1}; 9642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final GridTestAdapter testAdapter = new GridTestAdapter(10) { 9742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar @Override 9842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 9942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar int position) { 10042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar super.onBindViewHolder(holder, position); 10142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); 10242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (layoutParams == null) { 10342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 10442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 10542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar holder.itemView.setLayoutParams(layoutParams); 10642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 10742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = sizePerPosition[position]; 10842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (config.mOrientation == HORIZONTAL) { 10942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.width = size; 11042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } else { 11142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.height = size; 11242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 11342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 11442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar }; 11542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar testAdapter.setFullSpan(3, 5); 11642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final RecyclerView rv = setupBasic(config, testAdapter); 11742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar waitForFirstLayout(rv); 11842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 11942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertTrue("[test sanity] some views should be laid out", mRecyclerView.getChildCount() > 0); 12042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 12142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar View child = mRecyclerView.getChildAt(i); 12242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = config.mOrientation == HORIZONTAL ? child.getWidth() 12342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar : child.getHeight(); 12442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertEquals("child " + i + " should have the size specified in its layout params", 12542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar expectedSizePerPosition[i], size); 12642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 12742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar checkForMainThreadException(); 12842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 12942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 130061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testLayoutParams() throws Throwable { 131061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.HORIZONTAL); 132061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 133061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.VERTICAL); 134061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 135061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 136a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testHorizontalAccessibilitySpanIndices() throws Throwable { 137a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(HORIZONTAL); 138a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 139a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 140a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testVerticalAccessibilitySpanIndices() throws Throwable { 141a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(VERTICAL); 142a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 143a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 144a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void accessibilitySpanIndicesTest(int orientation) throws Throwable { 145a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, orientation, false)); 146a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar waitForFirstLayout(recyclerView); 147a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityDelegateCompat delegateCompat = mRecyclerView 148a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCompatAccessibilityDelegate().getItemDelegate(); 149a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 150a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final View chosen = recyclerView.getChildAt(recyclerView.getChildCount() - 2); 151115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int position = recyclerView.getChildLayoutPosition(chosen); 152a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar runTestOnUiThread(new Runnable() { 153a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 154a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 155a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(chosen, info); 156a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 157a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 158a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 159a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo = info 160a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCollectionItemInfo(); 161a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertNotNull(itemInfo); 162a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span group position", 163a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanGroupIndex(position, mGlm.getSpanCount()), 164a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getColumnIndex() : itemInfo.getRowIndex()); 165a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span index", 166a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanIndex(position, mGlm.getSpanCount()), 167a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowIndex() : itemInfo.getColumnIndex()); 168a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span size", 169a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanSize(position), 170a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowSpan() : itemInfo.getColumnSpan()); 171a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 172a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 173afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public GridLayoutManager.LayoutParams ensureGridLp(View view) { 174afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar ViewGroup.LayoutParams lp = view.getLayoutParams(); 175afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp; 176afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar if (lp instanceof GridLayoutManager.LayoutParams) { 177afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) lp; 178afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else if (lp == null) { 179afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm 180afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar .generateDefaultLayoutParams(); 181afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 182afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else { 183afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp); 184afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 185afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 186afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar return glp; 187afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 188afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 189061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void layoutParamsTest(final int orientation) throws Throwable { 190061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation), 191061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar new GridTestAdapter(100) { 192061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 193061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBindViewHolder(TestViewHolder holder, 194061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int position) { 195061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onBindViewHolder(holder, position); 196afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 197061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int val = 0; 198061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar switch (position % 5) { 199061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 0: 200061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 10; 201061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 202061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 1: 203061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 30; 204061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 205061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 2: 206061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.WRAP_CONTENT; 207061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 208061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 3: 209061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.FILL_PARENT; 210061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 211061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 4: 212061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 200; 213061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 214061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 215061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (orientation == GridLayoutManager.VERTICAL) { 216061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.height = val; 217061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 218061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.width = val; 219061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 220061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar holder.itemView.setLayoutParams(glp); 221061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 222061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 223061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 224061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final OrientationHelper helper = mGlm.mOrientationHelper; 225061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2))); 226115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 227115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(0))); 228115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 229115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(1))); 230115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 231115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(2))); 232061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0))); 233061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1))); 234061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2))); 235061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 236061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3))); 237115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 238115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(3))); 239115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 240115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(4))); 241115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 242115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(5))); 243061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3))); 244061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4))); 245061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5))); 246061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 247061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 248061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private int getSize(View view) { 249061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (mGlm.getOrientation() == GridLayoutManager.HORIZONTAL) { 250061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getWidth(); 251061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 252061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getHeight(); 253061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 254061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 25573304eff156157f62075215e795e774803a6f96aYigit Boyar public void testAnchorUpdate() throws InterruptedException { 25673304eff156157f62075215e795e774803a6f96aYigit Boyar GridLayoutManager glm = new GridLayoutManager(getActivity(), 11); 25773304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup spanSizeLookup 25873304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 25973304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 26073304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 26173304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 26273304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 26373304eff156157f62075215e795e774803a6f96aYigit Boyar } 26473304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 20) { 26573304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 26673304eff156157f62075215e795e774803a6f96aYigit Boyar } 26773304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 26873304eff156157f62075215e795e774803a6f96aYigit Boyar } 26973304eff156157f62075215e795e774803a6f96aYigit Boyar }; 27073304eff156157f62075215e795e774803a6f96aYigit Boyar glm.setSpanSizeLookup(spanSizeLookup); 27173304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 11; 27242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state = new RecyclerView.State(); 273061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar state.mItemCount = 1000; 2749ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 27573304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition); 27673304eff156157f62075215e795e774803a6f96aYigit Boyar 27773304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 13; 2789ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 27973304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition); 28073304eff156157f62075215e795e774803a6f96aYigit Boyar 28173304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 23; 2829ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 28373304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition); 28473304eff156157f62075215e795e774803a6f96aYigit Boyar 28573304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 35; 2869ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 28773304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition); 28873304eff156157f62075215e795e774803a6f96aYigit Boyar } 28973304eff156157f62075215e795e774803a6f96aYigit Boyar 29073304eff156157f62075215e795e774803a6f96aYigit Boyar public void testSpanLookup() { 291061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(false); 292061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 293061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 294061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupWithCache() { 295061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(true); 296061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 297061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 298061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupCache() { 299061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 300061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 301061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 302061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 303061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (position > 6) { 304061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 2; 305061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 306061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 1; 307061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 308061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 309061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 310061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2)); 311061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(4, 5); 312061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3)); 313061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // this should not happen and if happens, it is better to return -1 314061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 315061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5)); 316061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100)); 317061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(6, 5); 318061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 319061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6)); 320061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 321061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(12, 5); 322061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13)); 323061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12)); 324061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 325061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < 6; i++) { 326061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(i, 5); 327061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 328061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 329061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < 7; i++) { 330061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child right before " + i, i - 1, 331061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.findReferenceIndexFromCache(i)); 332061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 333061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0)); 334061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 335061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 336061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void spanLookupTest(boolean enableCache) { 33773304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 33873304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 33973304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 34073304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 34173304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 34273304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 34373304eff156157f62075215e795e774803a6f96aYigit Boyar } 34473304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 6) { 34573304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 34673304eff156157f62075215e795e774803a6f96aYigit Boyar } 34773304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 34873304eff156157f62075215e795e774803a6f96aYigit Boyar } 34973304eff156157f62075215e795e774803a6f96aYigit Boyar }; 350061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(enableCache); 351061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(0, 5)); 352061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(4, ssl.getCachedSpanIndex(4, 5)); 353061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(5, 5)); 354061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(1, ssl.getCachedSpanIndex(6, 5)); 355061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(7, 5)); 356061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(9, 5)); 357061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(8, 5)); 358061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 359061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 360a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testSpanGroupIndex() { 361a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 362a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 363a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 364a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getSpanSize(int position) { 365a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 200) { 366a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 100; 367a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 368a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 6) { 369a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 2; 370a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 371a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 1; 372a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 373a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }; 374a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(0, 5)); 375a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(4, 5)); 376a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(5, 5)); 377a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(6, 5)); 378a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(7, 5)); 379a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(9, 5)); 380a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(8, 5)); 381a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 382a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 383061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testNotifyDataSetChange() throws Throwable { 384061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, 100)); 385061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup(); 386061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 387061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(recyclerView); 388061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0); 389061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final Callback callback = new Callback() { 390061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 391061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 392061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 393061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size()); 394061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 395061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 396061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 397061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 398061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 399061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 400061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0); 401061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 402061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 403061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 404061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mCallbacks.add(callback); 405061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 406061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.deleteAndNotify(2, 3); 407061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 408061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 409061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 410061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 411afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenHeights() throws Throwable { 412afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 413afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 414afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, 3), new GridTestAdapter(3) { 415afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 416afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 417afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 418afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 419afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 420afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.height = 50 + position * 50; 421afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 422afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 423afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 424afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 425afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 426afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max height", 150, 427afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getHeight()); 428afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 429afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 430afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 431afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max height", 150, 432afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredHeight()); 433afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 434afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 435afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 436afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenWidths() throws Throwable { 437afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 438afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 439afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, HORIZONTAL, false), 440afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new GridTestAdapter(3) { 441afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 442afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 443afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 444afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 445afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 446afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.width = 50 + position * 50; 447afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 448afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 449afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 450afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 451afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 452afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max width", 150, 453afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getWidth()); 454afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 455afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 456afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 457afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max width", 150, 458afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredWidth()); 459afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 460afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 461afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 462061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testScrollBackAndPreservePositions() throws Throwable { 463061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Config config : mBaseVariations) { 464061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mItemCount = 150; 465061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollBackAndPreservePositionsTest(config); 466061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 467061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 468061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 469061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 470061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testCacheSpanIndices() throws Throwable { 471061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 472061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true); 473061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 474061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 475061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0); 476061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 2, 477061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 478061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 479061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.mFullSpanItems.add(4); 480061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.changeAndNotify(4, 1); 481061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 482061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 0, 483061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 484061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 485061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 486061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams getLp(View view) { 487061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return (GridLayoutManager.LayoutParams) view.getLayoutParams(); 488061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 489061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 490061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable { 491061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(config); 492061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) { 493061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.setFullSpan(i); 494061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 495061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 496061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPositions = new int[mAdapter.getItemCount()]; 497061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Arrays.fill(globalPositions, Integer.MIN_VALUE); 498061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20) 499061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * (config.mReverseLayout ? -1 : 1); 500061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final String logPrefix = config.toString(); 501061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPos = new int[1]; 502061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 503061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 504061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 505061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = 0; 506061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int visited = 0; 507061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (visited < mAdapter.getItemCount()) { 508061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 509061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 510115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int pos = mRecyclerView.getChildLayoutPosition(child); 511061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (globalPositions[pos] != Integer.MIN_VALUE) { 512061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 513061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 514061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited++; 515061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 516061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 517061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 518061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 519061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 520061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 521061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 522061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 523061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 524061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(logPrefix + " span index should match", 525061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 526061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 527061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 528061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrolled = mGlm.scrollBy(scrollStep, 529061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 530061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrolled; 531061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (scrolled == 0) { 532061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals( 533061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar logPrefix + " If scroll is complete, all views should be visited", 534061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited, mAdapter.getItemCount()); 535061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 536061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 537061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (DEBUG) { 538061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions)); 539061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 540061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos[0] = globalScrollPosition; 541061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 542061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 543061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 544061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 545061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 546061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 547061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = globalPos[0]; 548061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // now scroll back and make sure global positions match 549061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar BitSet shouldTest = new BitSet(mAdapter.getItemCount()); 550061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.set(0, mAdapter.getItemCount() - 1, true); 551061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar String assertPrefix = config 552061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar + " global pos must match when scrolling in reverse for position "; 553061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrollAmount = Integer.MAX_VALUE; 554061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (!shouldTest.isEmpty() && scrollAmount != 0) { 555061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 556061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 557115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int pos = mRecyclerView.getChildLayoutPosition(child); 558061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!shouldTest.get(pos)) { 559061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 560061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 561061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 562061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 563061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.clear(pos); 564061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalPos; 565061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 566061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 567061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 568061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 569061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 570061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 571061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 572061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(assertPrefix + pos, 573061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos], globalPos); 574061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("span index should match", 575061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 576061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 577061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 578061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollAmount = mGlm.scrollBy(-scrollStep, 579061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 580061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrollAmount; 581061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 582061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("all views should be seen", shouldTest.isEmpty()); 583061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 584061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 585061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 586061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 587061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 588061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class WrappedGridLayoutManager extends GridLayoutManager { 589061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 590061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar CountDownLatch mLayoutLatch; 591061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 592061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar List<Callback> mCallbacks = new ArrayList<Callback>(); 593061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 594061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount) { 595061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount); 596061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 597061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 598061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount, int orientation, 599061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean reverseLayout) { 600061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount, orientation, reverseLayout); 601061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 602061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 603061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 604061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 605061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar try { 606061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 607061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onBeforeLayout(recycler, state); 608061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 609061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onLayoutChildren(recycler, state); 610061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 611061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onAfterLayout(recycler, state); 612061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 613061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } catch (Throwable t) { 614061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar postExceptionToInstrumentation(t); 615061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 616061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.countDown(); 617061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 618061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 619061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void expectLayout(int layoutCount) { 620061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch = new CountDownLatch(layoutCount); 621061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 622061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 623061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForLayout(int seconds) throws InterruptedException { 624061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.await(seconds, SECONDS); 625061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 626061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 627061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 628061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Config { 629061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 630061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mSpanCount; 631061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mOrientation = GridLayoutManager.VERTICAL; 632061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mItemCount = 1000; 633061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean mReverseLayout = false; 634061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 635061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config(int spanCount, int itemCount) { 636061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 637061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mItemCount = itemCount; 638061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 639061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 640061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public Config(int spanCount, int orientation, boolean reverseLayout) { 641061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 642061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 643061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mReverseLayout = reverseLayout; 644061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 645061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 646061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config orientation(int orientation) { 647061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 648061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return this; 649061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 650061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 651061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 652061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public String toString() { 653061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return "Config{" + 654061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar "mSpanCount=" + mSpanCount + 655061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v") + 656061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mItemCount=" + mItemCount + 657061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mReverseLayout=" + mReverseLayout + 658061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar '}'; 659061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 660061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 661061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 662061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class GridTestAdapter extends TestAdapter { 663061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 664061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Set<Integer> mFullSpanItems = new HashSet<Integer>(); 665061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 666061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter(int count) { 667061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(count); 668061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 669061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 670061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void setFullSpan(int... items) { 671061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i : items) { 672061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mFullSpanItems.add(i); 673061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 674061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 675061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 676061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void assignSpanSizeLookup(final GridLayoutManager glm) { 677061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 678061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 679061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 680061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return mFullSpanItems.contains(position) ? glm.getSpanCount() : 1; 681061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 682061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 683061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 684061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 685061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 686061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Callback { 687061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 688061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 689061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 690061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 691061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 692061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 69373304eff156157f62075215e795e774803a6f96aYigit Boyar } 69473304eff156157f62075215e795e774803a6f96aYigit Boyar} 695