GridLayoutManagerTest.java revision 888093b0a071a99d65c01116cf703d46b21f9918
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; 201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyarimport android.os.Debug; 21a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.AccessibilityDelegateCompat; 22a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 23061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.util.Log; 24888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyarimport android.util.SparseIntArray; 25061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.View; 26061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.ViewGroup; 27061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 28061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.ArrayList; 29061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Arrays; 30061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.BitSet; 31afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.HashMap; 32061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.HashSet; 33061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.List; 34afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.Map; 35061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Set; 36061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.concurrent.CountDownLatch; 37888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 38061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 39061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; 40061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL; 41061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static java.util.concurrent.TimeUnit.SECONDS; 42061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 4373304eff156157f62075215e795e774803a6f96aYigit Boyarpublic class GridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest { 44061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 45061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final String TAG = "GridLayoutManagerTest"; 46061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 47061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final boolean DEBUG = false; 48061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 49061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar WrappedGridLayoutManager mGlm; 50061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 51061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter mAdapter; 52061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 53061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final List<Config> mBaseVariations = new ArrayList<Config>(); 54061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 55061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 56061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar protected void setUp() throws Exception { 57061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.setUp(); 58061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 59061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (boolean reverseLayout : new boolean[]{false, true}) { 60061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int spanCount : new int[]{1, 3, 4}) { 61061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mBaseVariations.add(new Config(spanCount, orientation, reverseLayout)); 62061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 63061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 64061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 65061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 66061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 67061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config) throws Throwable { 68061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return setupBasic(config, new GridTestAdapter(config.mItemCount)); 69061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 70061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 71061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable { 72061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 73061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter = testAdapter; 74061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation, 75061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mReverseLayout); 76061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.assignSpanSizeLookup(mGlm); 77061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setAdapter(mAdapter); 78061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setLayoutManager(mGlm); 79061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return recyclerView; 80061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 81061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 82061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForFirstLayout(RecyclerView recyclerView) throws Throwable { 83061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(1); 84061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar setRecyclerView(recyclerView); 85061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 86061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 87061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 8842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomWidthInHorizontal() throws Throwable { 8942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, HORIZONTAL, false)); 9042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 9142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 9242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomHeightInVertical() throws Throwable { 9342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, VERTICAL, false)); 9442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 9542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 9642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void customSizeInScrollDirectionTest(final Config config) throws Throwable { 9742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] sizePerPosition = new int[]{3, 5, 9, 21, 3, 5, 9, 6, 9, 1}; 9842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] expectedSizePerPosition = new int[]{9, 9, 9, 21, 3, 5, 9, 9, 9, 1}; 9942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final GridTestAdapter testAdapter = new GridTestAdapter(10) { 10042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar @Override 10142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 10242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar int position) { 10342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar super.onBindViewHolder(holder, position); 10442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); 10542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (layoutParams == null) { 10642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 10742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 10842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar holder.itemView.setLayoutParams(layoutParams); 10942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 11042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = sizePerPosition[position]; 11142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (config.mOrientation == HORIZONTAL) { 11242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.width = size; 11342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } else { 11442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.height = size; 11542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 11642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 11742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar }; 11842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar testAdapter.setFullSpan(3, 5); 11942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final RecyclerView rv = setupBasic(config, testAdapter); 12042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar waitForFirstLayout(rv); 12142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 12242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertTrue("[test sanity] some views should be laid out", mRecyclerView.getChildCount() > 0); 12342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 12442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar View child = mRecyclerView.getChildAt(i); 12542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = config.mOrientation == HORIZONTAL ? child.getWidth() 12642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar : child.getHeight(); 12742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertEquals("child " + i + " should have the size specified in its layout params", 12842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar expectedSizePerPosition[i], size); 12942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 13042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar checkForMainThreadException(); 13142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 13242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 133871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar public void testRTL() throws Throwable { 134871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (boolean changeRtlAfter : new boolean[]{false, true}) { 135871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (boolean oneLine : new boolean[]{false, true}) { 136871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (Config config : mBaseVariations) { 137871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar rtlTest(config, changeRtlAfter, oneLine); 138871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar removeRecyclerView(); 139871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 140871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 141871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 142871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 143871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 144871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar void rtlTest(Config config, boolean changeRtlAfter, boolean oneLine) throws Throwable { 145871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (oneLine && config.mOrientation != VERTICAL) { 146871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar return;// nothing to test 147871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 148871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (config.mSpanCount == 1) { 149871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = 2; 150871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 151871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar String logPrefix = config + ", changeRtlAfterLayout:" + changeRtlAfter + ", oneLine:" + oneLine; 152871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mItemCount = 5; 153871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (oneLine) { 154871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = config.mItemCount + 1; 155871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 156871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = Math.min(config.mItemCount - 1, config.mSpanCount); 157871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 158871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 159871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar RecyclerView rv = setupBasic(config); 160871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (changeRtlAfter) { 161871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar waitForFirstLayout(rv); 162871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.expectLayout(1); 163871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.setFakeRtl(true); 164871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.waitForLayout(2); 165871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 166871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.mFakeRTL = true; 167871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar waitForFirstLayout(rv); 168871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 169871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 170871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals("view should become rtl", true, mGlm.isLayoutRTL()); 171871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar OrientationHelper helper = OrientationHelper.createHorizontalHelper(mGlm); 172871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar View child0 = mGlm.findViewByPosition(0); 173871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar final int secondChildPos = config.mOrientation == VERTICAL ? 1 174871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar : config.mSpanCount; 175871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar View child1 = mGlm.findViewByPosition(secondChildPos); 176871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertNotNull(logPrefix + " child position 0 should be laid out", child0); 177871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertNotNull( 178871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar logPrefix + " second child position " + (secondChildPos) + " should be laid out", 179871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar child1); 180871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (config.mOrientation == VERTICAL || !config.mReverseLayout) { 181871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertTrue(logPrefix + " second child should be to the left of first child", 182871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child0) >= helper.getDecoratedEnd(child1)); 183871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals(logPrefix + " first child should be right aligned", 184871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedEnd(child0), helper.getEndAfterPadding()); 185871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 186871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertTrue(logPrefix + " first child should be to the left of second child", 187871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child1) >= helper.getDecoratedEnd(child0)); 188871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals(logPrefix + " first child should be left aligned", 189871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child0), helper.getStartAfterPadding()); 190871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 191871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar checkForMainThreadException(); 192871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 193871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 194888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar public void testMovingAGroupOffScreenForAddedItems() throws Throwable { 195888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 196888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int[] maxId = new int[1]; 197888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar maxId[0] = -1; 198888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final SparseIntArray spanLookups = new SparseIntArray(); 199888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final AtomicBoolean enableSpanLookupLogging = new AtomicBoolean(false); 200888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 201888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 202888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar public int getSpanSize(int position) { 203888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar if (maxId[0] > 0 && mAdapter.getItemAt(position).mId > maxId[0]) { 204888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return 1; 205888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } else if (enableSpanLookupLogging.get() && !rv.mState.isPreLayout()) { 206888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar spanLookups.put(position, spanLookups.get(position, 0) + 1); 207888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 208888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return 3; 209888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 210888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar }); 211888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar rv.getItemAnimator().setSupportsChangeAnimations(true); 212888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar waitForFirstLayout(rv); 213888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View lastView = rv.getChildAt(rv.getChildCount() - 1); 214888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int lastPos = rv.getChildAdapterPosition(lastView); 215888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar maxId[0] = mAdapter.getItemAt(mAdapter.getItemCount() - 1).mId; 216888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar // now add a lot of items below this and those new views should have span size 3 217888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar enableSpanLookupLogging.set(true); 218888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.expectLayout(2); 219888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mAdapter.addAndNotify(lastPos - 2, 30); 220888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.waitForLayout(2); 221888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar checkForMainThreadException(); 222888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 223888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("last items span count should be queried twice", 2, 224888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar spanLookups.get(lastPos + 30)); 225888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 226888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 227888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 2287e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko public void testCachedBorders() throws Throwable { 2297e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko List<Config> testConfigurations = new ArrayList<Config>(mBaseVariations); 2307e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko testConfigurations.addAll(cachedBordersTestConfigs()); 2317e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (Config config : testConfigurations) { 2327e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko gridCachedBorderstTest(config); 2337e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2347e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2357e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 2367e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko private void gridCachedBorderstTest(Config config) throws Throwable { 2377e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko RecyclerView recyclerView = setupBasic(config); 2387e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko waitForFirstLayout(recyclerView); 2397e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final boolean vertical = config.mOrientation == GridLayoutManager.VERTICAL; 2407e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int expectedSizeSum = vertical ? recyclerView.getWidth() : recyclerView.getHeight(); 2417e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int lastVisible = mGlm.findLastVisibleItemPosition(); 2427e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int i = 0; i < lastVisible; i += config.mSpanCount) { 2437e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko if ((i+1)*config.mSpanCount - 1 < lastVisible) { 2447e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int childrenSizeSum = 0; 2457e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int j = 0; j < config.mSpanCount; j++) { 2467e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko View child = recyclerView.getChildAt(i * config.mSpanCount + j); 2477e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko childrenSizeSum += vertical ? child.getWidth() : child.getHeight(); 2487e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2497e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko assertEquals(expectedSizeSum, childrenSizeSum); 2507e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2517e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2527e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko removeRecyclerView(); 2537e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2547e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 2557e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko private List<Config> cachedBordersTestConfigs() { 2567e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko ArrayList<Config> configs = new ArrayList<Config>(); 2577e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int [] spanCounts = new int[]{88, 279, 741}; 2587e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int [] spanPerItem = new int[]{11, 9, 13}; 2597e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 2607e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (boolean reverseLayout : new boolean[]{false, true}) { 2617e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int i = 0 ; i < spanCounts.length; i++) { 2627e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko Config config = new Config(spanCounts[i], orientation, reverseLayout); 2637e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko config.mSpanPerItem = spanPerItem[i]; 2647e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko configs.add(config); 2657e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2667e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2677e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2687e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko return configs; 2697e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2707e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 271061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testLayoutParams() throws Throwable { 272061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.HORIZONTAL); 273061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 274061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.VERTICAL); 275061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 276061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 277a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testHorizontalAccessibilitySpanIndices() throws Throwable { 278a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(HORIZONTAL); 279a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 280a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 281a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testVerticalAccessibilitySpanIndices() throws Throwable { 282a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(VERTICAL); 283a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 284a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 285a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void accessibilitySpanIndicesTest(int orientation) throws Throwable { 286a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, orientation, false)); 287a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar waitForFirstLayout(recyclerView); 288a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityDelegateCompat delegateCompat = mRecyclerView 289a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCompatAccessibilityDelegate().getItemDelegate(); 290a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 291a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final View chosen = recyclerView.getChildAt(recyclerView.getChildCount() - 2); 292115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int position = recyclerView.getChildLayoutPosition(chosen); 293a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar runTestOnUiThread(new Runnable() { 294a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 295a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 296a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(chosen, info); 297a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 298a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 299a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 300a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo = info 301a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCollectionItemInfo(); 302a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertNotNull(itemInfo); 303a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span group position", 304a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanGroupIndex(position, mGlm.getSpanCount()), 305a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getColumnIndex() : itemInfo.getRowIndex()); 306a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span index", 307a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanIndex(position, mGlm.getSpanCount()), 308a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowIndex() : itemInfo.getColumnIndex()); 309a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span size", 310a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanSize(position), 311a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowSpan() : itemInfo.getColumnSpan()); 312a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 313a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 314afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public GridLayoutManager.LayoutParams ensureGridLp(View view) { 315afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar ViewGroup.LayoutParams lp = view.getLayoutParams(); 316afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp; 317afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar if (lp instanceof GridLayoutManager.LayoutParams) { 318afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) lp; 319afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else if (lp == null) { 320afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm 321afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar .generateDefaultLayoutParams(); 322afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 323afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else { 324afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp); 325afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 326afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 327afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar return glp; 328afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 329afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 330061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void layoutParamsTest(final int orientation) throws Throwable { 331061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation), 332061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar new GridTestAdapter(100) { 333061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 334061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBindViewHolder(TestViewHolder holder, 335061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int position) { 336061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onBindViewHolder(holder, position); 337afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 338061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int val = 0; 339061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar switch (position % 5) { 340061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 0: 341061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 10; 342061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 343061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 1: 344061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 30; 345061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 346061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 2: 347061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.WRAP_CONTENT; 348061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 349061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 3: 350061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.FILL_PARENT; 351061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 352061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 4: 353061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 200; 354061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 355061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 356061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (orientation == GridLayoutManager.VERTICAL) { 357061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.height = val; 358061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 359061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.width = val; 360061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 361061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar holder.itemView.setLayoutParams(glp); 362061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 363061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 364061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 365061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final OrientationHelper helper = mGlm.mOrientationHelper; 366061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2))); 367115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 368115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(0))); 369115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 370115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(1))); 371115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 372115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(2))); 373061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0))); 374061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1))); 375061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2))); 376061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 377061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3))); 378115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 379115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(3))); 380115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 381115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(4))); 382115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 383115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(5))); 384061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3))); 385061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4))); 386061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5))); 387061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 388061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 389061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private int getSize(View view) { 390061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (mGlm.getOrientation() == GridLayoutManager.HORIZONTAL) { 391061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getWidth(); 392061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 393061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getHeight(); 394061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 395061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 39673304eff156157f62075215e795e774803a6f96aYigit Boyar public void testAnchorUpdate() throws InterruptedException { 39773304eff156157f62075215e795e774803a6f96aYigit Boyar GridLayoutManager glm = new GridLayoutManager(getActivity(), 11); 39873304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup spanSizeLookup 39973304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 40073304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 40173304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 40273304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 40373304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 40473304eff156157f62075215e795e774803a6f96aYigit Boyar } 40573304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 20) { 40673304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 40773304eff156157f62075215e795e774803a6f96aYigit Boyar } 40873304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 40973304eff156157f62075215e795e774803a6f96aYigit Boyar } 41073304eff156157f62075215e795e774803a6f96aYigit Boyar }; 41173304eff156157f62075215e795e774803a6f96aYigit Boyar glm.setSpanSizeLookup(spanSizeLookup); 41273304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 11; 41342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state = new RecyclerView.State(); 414061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar state.mItemCount = 1000; 4159ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 41673304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition); 41773304eff156157f62075215e795e774803a6f96aYigit Boyar 41873304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 13; 4199ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 42073304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition); 42173304eff156157f62075215e795e774803a6f96aYigit Boyar 42273304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 23; 4239ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 42473304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition); 42573304eff156157f62075215e795e774803a6f96aYigit Boyar 42673304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 35; 4279ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar glm.onAnchorReady(state, glm.mAnchorInfo); 42873304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition); 42973304eff156157f62075215e795e774803a6f96aYigit Boyar } 43073304eff156157f62075215e795e774803a6f96aYigit Boyar 43173304eff156157f62075215e795e774803a6f96aYigit Boyar public void testSpanLookup() { 432061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(false); 433061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 434061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 435061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupWithCache() { 436061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(true); 437061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 438061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 439061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupCache() { 440061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 441061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 442061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 443061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 444061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (position > 6) { 445061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 2; 446061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 447061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 1; 448061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 449061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 450061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 451061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2)); 452061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(4, 5); 453061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3)); 454061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // this should not happen and if happens, it is better to return -1 455061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 456061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5)); 457061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100)); 458061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(6, 5); 459061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 460061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6)); 461061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 462061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(12, 5); 463061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13)); 464061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12)); 465061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 466061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < 6; i++) { 467061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(i, 5); 468061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 469061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 470061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < 7; i++) { 471061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child right before " + i, i - 1, 472061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.findReferenceIndexFromCache(i)); 473061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 474061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0)); 475061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 476061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 477061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void spanLookupTest(boolean enableCache) { 47873304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 47973304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 48073304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 48173304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 48273304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 48373304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 48473304eff156157f62075215e795e774803a6f96aYigit Boyar } 48573304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 6) { 48673304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 48773304eff156157f62075215e795e774803a6f96aYigit Boyar } 48873304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 48973304eff156157f62075215e795e774803a6f96aYigit Boyar } 49073304eff156157f62075215e795e774803a6f96aYigit Boyar }; 491061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(enableCache); 492061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(0, 5)); 493061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(4, ssl.getCachedSpanIndex(4, 5)); 494061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(5, 5)); 495061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(1, ssl.getCachedSpanIndex(6, 5)); 496061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(7, 5)); 497061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(9, 5)); 498061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(8, 5)); 499061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 500061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 5011f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItem() throws Throwable { 5021f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 5031f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(VERTICAL).reverseLayout(false), 100, 0); 5041f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5051f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 5061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverse() throws Throwable { 5071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 5081f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(VERTICAL).reverseLayout(true), 100, 5091f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 0); 5101f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5111f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 5121f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemHorizontal() throws Throwable { 5131f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 5141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(HORIZONTAL).reverseLayout( 5151f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar false), 100, 0); 5161f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5171f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 5181f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverseHorizontal() throws Throwable { 5191f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 5201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(HORIZONTAL).reverseLayout(true), 5211f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 100, 0); 5221f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5231f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 5241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar /** 5251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * This tests a regression where predictive animations were not working as expected when the 5261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * first item is removed and there aren't any more items to add from that direction. 5271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * First item refers to the default anchor item. 5281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar */ 5291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void removeAnchorItemTest(final Config config, int adapterSize, 5301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int removePos) throws Throwable { 5311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar GridTestAdapter adapter = new GridTestAdapter(adapterSize) { 5321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 5331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 5341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar int position) { 5351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar super.onBindViewHolder(holder, position); 5361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 5371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (!(lp instanceof ViewGroup.MarginLayoutParams)) { 5381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar lp = new ViewGroup.MarginLayoutParams(0, 0); 5391f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar holder.itemView.setLayoutParams(lp); 5401f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5411f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp; 5421f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int maxSize; 5431f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 5441f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getWidth(); 5451f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = ViewGroup.MarginLayoutParams.FILL_PARENT; 5461f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 5471f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getHeight(); 5481f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = ViewGroup.MarginLayoutParams.FILL_PARENT; 5491f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5501f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 5511f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int desiredSize; 5521f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (position == removePos) { 5531f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it large 5541f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 4; 5551f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 5561f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it small 5571f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 8; 5581f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5591f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 5601f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = desiredSize; 5611f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 5621f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = desiredSize; 5631f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5641f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5651f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar }; 5661f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView recyclerView = setupBasic(config, adapter); 5671f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar waitForFirstLayout(recyclerView); 5681f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int childCount = mGlm.getChildCount(); 5691f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder toBeRemoved = null; 5701f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>(); 5711f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < childCount; i++) { 5721f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mGlm.getChildAt(i); 5731f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 5741f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (holder.getAdapterPosition() == removePos) { 5751f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeRemoved = holder; 5761f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 5771f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeMoved.add(holder); 5781f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5791f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5801f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertNotNull("test sanity", toBeRemoved); 5811f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("test sanity", childCount - 1, toBeMoved.size()); 5821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator(); 5831f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.setItemAnimator(loggingItemAnimator); 5841f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.reset(); 5851f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.expectRunPendingAnimationsCall(1); 5861f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mGlm.expectLayout(2); 5871f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar adapter.deleteAndNotify(removePos, 1); 5881f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mGlm.waitForLayout(1); 5891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.waitForPendingAnimationsCall(2); 5901f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("removed child should receive remove animation", 5911f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mRemoveVHs.contains(toBeRemoved)); 5921f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder vh : toBeMoved) { 5931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("view holder should be in moved list", 5941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(vh)); 5951f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 5961f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>(); 5971f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < mGlm.getChildCount(); i++) { 5981f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mGlm.getChildAt(i); 5991f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 6001f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (toBeRemoved != holder && !toBeMoved.contains(holder)) { 6011f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar newHolders.add(holder); 6021f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6031f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6041f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("some new children should show up for the new space", newHolders.size() > 0); 6051f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("no items should receive animate add since they are not new", 0, 6061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mAddVHs.size()); 6071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder holder : newHolders) { 6081f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("new holder should receive a move animation", 6091f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(holder)); 6101f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6111f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // for removed view, 3 for new row 6121f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("control against adding too many children due to bad layout state preparation." 6131f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(), 6141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.getChildCount() <= childCount + 1 + 3); 6151f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6161f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 617a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testSpanGroupIndex() { 618a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 619a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 620a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 621a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getSpanSize(int position) { 622a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 200) { 623a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 100; 624a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 625a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 6) { 626a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 2; 627a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 628a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 1; 629a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 630a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }; 631a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(0, 5)); 632a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(4, 5)); 633a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(5, 5)); 634a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(6, 5)); 635a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(7, 5)); 636a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(9, 5)); 637a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(8, 5)); 638a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 639a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 640061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testNotifyDataSetChange() throws Throwable { 641061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, 100)); 642061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup(); 643061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 644061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(recyclerView); 645061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0); 646061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final Callback callback = new Callback() { 647061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 648061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 649061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 650061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size()); 651061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 652061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 653061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 654061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 655061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 656061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 657061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0); 658061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 659061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 660061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 661061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mCallbacks.add(callback); 662061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 663061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.deleteAndNotify(2, 3); 664061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 665061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 666061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 667061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 668afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenHeights() throws Throwable { 669afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 670afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 671afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, 3), new GridTestAdapter(3) { 672afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 673afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 674afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 675afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 676afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 677afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.height = 50 + position * 50; 678afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 679afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 680afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 681afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 682afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 683afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max height", 150, 684afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getHeight()); 685afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 686afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 687afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 688afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max height", 150, 689afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredHeight()); 690afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 691afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 692afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 693afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenWidths() throws Throwable { 694afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 695afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 696afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, HORIZONTAL, false), 697afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new GridTestAdapter(3) { 698afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 699afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 700afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 701afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 702afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 703afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.width = 50 + position * 50; 704afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 705afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 706afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 707afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 708afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 709afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max width", 150, 710afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getWidth()); 711afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 712afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 713afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 714afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max width", 150, 715afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredWidth()); 716afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 717afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 718afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 719061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testScrollBackAndPreservePositions() throws Throwable { 720061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Config config : mBaseVariations) { 721061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mItemCount = 150; 722061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollBackAndPreservePositionsTest(config); 723061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 724061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 725061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 726061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 727204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar public void testSpanSizeChange() throws Throwable { 728204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 729204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar waitForFirstLayout(rv); 730204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertTrue(mGlm.supportsPredictiveItemAnimations()); 731204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.expectLayout(1); 732204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar runTestOnUiThread(new Runnable() { 733204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar @Override 734204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar public void run() { 735204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.setSpanCount(5); 736204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertFalse(mGlm.supportsPredictiveItemAnimations()); 737204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar } 738204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar }); 739204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar checkForMainThreadException(); 740204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.waitForLayout(2); 741204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.expectLayout(2); 742204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mAdapter.deleteAndNotify(3, 2); 743204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.waitForLayout(2); 744204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertTrue(mGlm.supportsPredictiveItemAnimations()); 745204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar } 746204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar 747061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testCacheSpanIndices() throws Throwable { 748061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 749061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true); 750061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 751061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 752061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0); 753061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 2, 754061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 755061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 756061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.mFullSpanItems.add(4); 757061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.changeAndNotify(4, 1); 758061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 759061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 0, 760061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 761061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 762061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 763061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams getLp(View view) { 764061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return (GridLayoutManager.LayoutParams) view.getLayoutParams(); 765061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 766061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 767061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable { 768061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(config); 769061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) { 770061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.setFullSpan(i); 771061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 772061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 773061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPositions = new int[mAdapter.getItemCount()]; 774061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Arrays.fill(globalPositions, Integer.MIN_VALUE); 775061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20) 776061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * (config.mReverseLayout ? -1 : 1); 777061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final String logPrefix = config.toString(); 778061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPos = new int[1]; 779061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 780061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 781061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 7821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertSame("test sanity", mRecyclerView, rv); 783061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = 0; 784061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int visited = 0; 785061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (visited < mAdapter.getItemCount()) { 786061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 787061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 788115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int pos = mRecyclerView.getChildLayoutPosition(child); 789061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (globalPositions[pos] != Integer.MIN_VALUE) { 790061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 791061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 792061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited++; 793061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 794061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 795061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 796061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 797061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 798061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 799061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 800061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 801061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 802061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(logPrefix + " span index should match", 803061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 804061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 805061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 806061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrolled = mGlm.scrollBy(scrollStep, 807061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 808061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrolled; 809061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (scrolled == 0) { 810061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals( 811061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar logPrefix + " If scroll is complete, all views should be visited", 812061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited, mAdapter.getItemCount()); 813061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 814061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 815061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (DEBUG) { 816061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions)); 817061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 818061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos[0] = globalScrollPosition; 819061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 820061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 821061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 8221f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // test sanity, ensure scroll happened 8231f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar runTestOnUiThread(new Runnable() { 8241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 8251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void run() { 8261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int childCount = mGlm.getChildCount(); 8271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final BitSet expectedPositions = new BitSet(); 8281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < childCount; i ++) { 8291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar expectedPositions.set(mAdapter.getItemCount() - i - 1); 8301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 8311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i <childCount; i ++) { 8321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final View view = mGlm.getChildAt(i); 8331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar int position = mGlm.getPosition(view); 8341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("child position should be in last page", expectedPositions.get(position)); 8351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 8361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 8371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar }); 8381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar getInstrumentation().waitForIdleSync(); 839061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 840061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 841061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 842061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = globalPos[0]; 843061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // now scroll back and make sure global positions match 844061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar BitSet shouldTest = new BitSet(mAdapter.getItemCount()); 845061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.set(0, mAdapter.getItemCount() - 1, true); 846061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar String assertPrefix = config 847061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar + " global pos must match when scrolling in reverse for position "; 848061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrollAmount = Integer.MAX_VALUE; 849061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (!shouldTest.isEmpty() && scrollAmount != 0) { 850061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 851061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 852115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int pos = mRecyclerView.getChildLayoutPosition(child); 853061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!shouldTest.get(pos)) { 854061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 855061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 856061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 857061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 858061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.clear(pos); 859061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalPos; 860061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 861061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 862061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 863061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 864061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 865061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 866061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 867061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(assertPrefix + pos, 868061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos], globalPos); 869061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("span index should match", 870061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 871061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 872061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 873061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollAmount = mGlm.scrollBy(-scrollStep, 874061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 875061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrollAmount; 876061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 877061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("all views should be seen", shouldTest.isEmpty()); 878061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 879061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 880061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 881061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 882061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 883061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class WrappedGridLayoutManager extends GridLayoutManager { 884061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 885061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar CountDownLatch mLayoutLatch; 886061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 887061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar List<Callback> mCallbacks = new ArrayList<Callback>(); 888061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 889871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar Boolean mFakeRTL; 890871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 891061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount) { 892061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount); 893061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 894061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 895061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount, int orientation, 896061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean reverseLayout) { 897061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount, orientation, reverseLayout); 898061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 899061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 900061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 901871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar protected boolean isLayoutRTL() { 902871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar return mFakeRTL == null ? super.isLayoutRTL() : mFakeRTL; 903871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 904871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 905871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar public void setFakeRtl(Boolean fakeRtl) { 906871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mFakeRTL = fakeRtl; 907871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar try { 908871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar requestLayoutOnUIThread(mRecyclerView); 909871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } catch (Throwable throwable) { 910871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar postExceptionToInstrumentation(throwable); 911871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 912871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 913871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 914871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar @Override 915061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 916061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar try { 917061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 918061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onBeforeLayout(recycler, state); 919061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 920061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onLayoutChildren(recycler, state); 921061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 922061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onAfterLayout(recycler, state); 923061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 924061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } catch (Throwable t) { 925061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar postExceptionToInstrumentation(t); 926061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 927061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.countDown(); 928061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 929061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 930888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 931888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar LayoutState createLayoutState() { 932888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return new LayoutState() { 933888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 934888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View next(RecyclerView.Recycler recycler) { 935888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final boolean hadMore = hasMore(mRecyclerView.mState); 936888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int position = mCurrentPosition; 937888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View next = super.next(recycler); 938888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("if has more, should return a view", hadMore, next != null); 939888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("position of the returned view must match current position", 940888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar position, RecyclerView.getChildViewHolderInt(next).getLayoutPosition()); 941888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return next; 942888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 943888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar }; 944888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 945888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 946061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void expectLayout(int layoutCount) { 947061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch = new CountDownLatch(layoutCount); 948061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 949061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 950061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForLayout(int seconds) throws InterruptedException { 951061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.await(seconds, SECONDS); 952061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 953061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 954061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 955061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Config { 956061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 957061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mSpanCount; 958061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mOrientation = GridLayoutManager.VERTICAL; 959061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mItemCount = 1000; 9607e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int mSpanPerItem = 1; 961061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean mReverseLayout = false; 962061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 963061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config(int spanCount, int itemCount) { 964061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 965061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mItemCount = itemCount; 966061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 967061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 968061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public Config(int spanCount, int orientation, boolean reverseLayout) { 969061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 970061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 971061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mReverseLayout = reverseLayout; 972061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 973061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 974061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config orientation(int orientation) { 975061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 976061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return this; 977061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 978061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 979061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 980061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public String toString() { 981061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return "Config{" + 982061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar "mSpanCount=" + mSpanCount + 983061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v") + 984061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mItemCount=" + mItemCount + 985061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mReverseLayout=" + mReverseLayout + 986061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar '}'; 987061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 9881f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 9891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public Config reverseLayout(boolean reverseLayout) { 9901f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mReverseLayout = reverseLayout; 9911f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar return this; 9921f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 9931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 9941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 995061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 996061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 997061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class GridTestAdapter extends TestAdapter { 998061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 999061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Set<Integer> mFullSpanItems = new HashSet<Integer>(); 10007e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int mSpanPerItem = 1; 1001061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1002061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter(int count) { 1003061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(count); 1004061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1005061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 10067e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko GridTestAdapter(int count, int spanPerItem) { 10077e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko super(count); 10087e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mSpanPerItem = spanPerItem; 10097e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 10107e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 1011061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void setFullSpan(int... items) { 1012061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i : items) { 1013061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mFullSpanItems.add(i); 1014061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1015061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1016061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1017061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void assignSpanSizeLookup(final GridLayoutManager glm) { 1018061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 1019061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 1020061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 10217e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko return mFullSpanItems.contains(position) ? glm.getSpanCount() : mSpanPerItem; 1022061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1023061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 1024061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1025061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1026061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1027061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Callback { 1028061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1029061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 1030061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1031061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1032061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 1033061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 103473304eff156157f62075215e795e774803a6f96aYigit Boyar } 103573304eff156157f62075215e795e774803a6f96aYigit Boyar} 1036