GridLayoutManagerTest.java revision bb2163aca1052da169c15625c9afca7b85491ebf
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; 203bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyarimport android.graphics.Rect; 21a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.AccessibilityDelegateCompat; 22a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 23bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyarimport android.test.UiThreadTest; 24061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.util.Log; 25888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyarimport android.util.SparseIntArray; 26061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.View; 27061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport android.view.ViewGroup; 28061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 29061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.ArrayList; 30061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Arrays; 31061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.BitSet; 32afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.HashMap; 33061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.HashSet; 34061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.List; 35afa0494a97687b705feb3659385578f33f697ea9Yigit Boyarimport java.util.Map; 36061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.Set; 37061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport java.util.concurrent.CountDownLatch; 38888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 39061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 40061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; 41061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL; 42061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyarimport static java.util.concurrent.TimeUnit.SECONDS; 43061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 4473304eff156157f62075215e795e774803a6f96aYigit Boyarpublic class GridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest { 45061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 46061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final String TAG = "GridLayoutManagerTest"; 47061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 48061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final boolean DEBUG = false; 49061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 50061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar WrappedGridLayoutManager mGlm; 51061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 52061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter mAdapter; 53061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 54061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final List<Config> mBaseVariations = new ArrayList<Config>(); 55061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 56061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 57061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar protected void setUp() throws Exception { 58061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.setUp(); 59061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 60061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (boolean reverseLayout : new boolean[]{false, true}) { 61061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int spanCount : new int[]{1, 3, 4}) { 62061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mBaseVariations.add(new Config(spanCount, orientation, reverseLayout)); 63061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 64061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 65061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 66061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 67061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 68061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config) throws Throwable { 69061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return setupBasic(config, new GridTestAdapter(config.mItemCount)); 70061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 71061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 72061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable { 73061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 74061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter = testAdapter; 75061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation, 76061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mReverseLayout); 77061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.assignSpanSizeLookup(mGlm); 78061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setAdapter(mAdapter); 79061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar recyclerView.setLayoutManager(mGlm); 80061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return recyclerView; 81061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 82061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 83061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForFirstLayout(RecyclerView recyclerView) throws Throwable { 84061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(1); 85061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar setRecyclerView(recyclerView); 86061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 87061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 88061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 89bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar @UiThreadTest 90bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar public void testScrollWithoutLayout() throws Throwable { 91bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, 100)); 92bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar mGlm.expectLayout(1); 93bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar setRecyclerView(recyclerView); 94bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar mGlm.setSpanCount(5); 95bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar recyclerView.scrollBy(0, 10); 96bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar } 97bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar 98bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar public void testScrollWithoutLayoutAfterInvalidate() throws Throwable { 99bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, 100)); 100bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar waitForFirstLayout(recyclerView); 101bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar runTestOnUiThread(new Runnable() { 102bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar @Override 103bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar public void run() { 104bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar mGlm.setSpanCount(5); 105bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar recyclerView.scrollBy(0, 10); 106bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar } 107bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar }); 108bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar } 109bb2163aca1052da169c15625c9afca7b85491ebfYigit Boyar 110cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public void testPredictiveSpanLookup1() throws Throwable { 111cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar predictiveSpanLookupTest(0, false); 112cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 113cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 114cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public void testPredictiveSpanLookup2() throws Throwable { 115cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar predictiveSpanLookupTest(0, true); 116cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 117cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 118cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public void testPredictiveSpanLookup3() throws Throwable { 119cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar predictiveSpanLookupTest(1, false); 120cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 121cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 122cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public void testPredictiveSpanLookup4() throws Throwable { 123cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar predictiveSpanLookupTest(1, true); 124cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 125cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 126cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public void predictiveSpanLookupTest(int remaining, boolean removeFromStart) throws Throwable { 127cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, 10)); 128cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 129cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar @Override 130cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public int getSpanSize(int position) { 131cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar if (position < 0 || position >= mAdapter.getItemCount()) { 132cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar postExceptionToInstrumentation(new AssertionError("position is not within " + 133cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar "adapter range. pos:" + position + ", adapter size:" + 134cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mAdapter.getItemCount())); 135cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 136cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar return 1; 137cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 138cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 139cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar @Override 140cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar public int getSpanIndex(int position, int spanCount) { 141cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar if (position < 0 || position >= mAdapter.getItemCount()) { 142cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar postExceptionToInstrumentation(new AssertionError("position is not within " + 143cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar "adapter range. pos:" + position + ", adapter size:" + 144cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mAdapter.getItemCount())); 145cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 146cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar return super.getSpanIndex(position, spanCount); 147cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 148cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar }); 149cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar waitForFirstLayout(recyclerView); 150cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar checkForMainThreadException(); 151cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar assertTrue("test sanity", mGlm.supportsPredictiveItemAnimations()); 152cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mGlm.expectLayout(2); 153cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar int deleteCnt = 10 - remaining; 154cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar int deleteStart = removeFromStart ? 0 : remaining; 155cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mAdapter.deleteAndNotify(deleteStart, deleteCnt); 156cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mGlm.waitForLayout(2); 157cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar checkForMainThreadException(); 158cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar } 159cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar 16042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomWidthInHorizontal() throws Throwable { 16142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, HORIZONTAL, false)); 16242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 16342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 16442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void testCustomHeightInVertical() throws Throwable { 16542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar customSizeInScrollDirectionTest(new Config(3, VERTICAL, false)); 16642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 16742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 16842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void customSizeInScrollDirectionTest(final Config config) throws Throwable { 1693bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar Boolean[] options = new Boolean[]{true, false}; 1703bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar for (boolean addMargins : options) { 1713bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar for (boolean addDecorOffsets : options) { 1723bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar customSizeInScrollDirectionTest(config, addDecorOffsets, addMargins); 1733bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 1743bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 1753bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 1763bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar 1773bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar public void customSizeInScrollDirectionTest(final Config config, boolean addDecorOffsets, 1783bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar boolean addMarigns) throws Throwable { 1793bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar final int decorOffset = addDecorOffsets ? 7 : 0; 1803bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar final int margin = addMarigns ? 11 : 0; 18142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] sizePerPosition = new int[]{3, 5, 9, 21, 3, 5, 9, 6, 9, 1}; 18242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int[] expectedSizePerPosition = new int[]{9, 9, 9, 21, 3, 5, 9, 9, 9, 1}; 1833bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar 18442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final GridTestAdapter testAdapter = new GridTestAdapter(10) { 18542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar @Override 18642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 18742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar int position) { 18842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar super.onBindViewHolder(holder, position); 1893bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) 1903bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar holder.itemView.getLayoutParams(); 19142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (layoutParams == null) { 1923bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar layoutParams = new ViewGroup.MarginLayoutParams( 1933bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT, 19442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 19542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar holder.itemView.setLayoutParams(layoutParams); 19642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 19742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = sizePerPosition[position]; 19842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (config.mOrientation == HORIZONTAL) { 19942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.width = size; 2003bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar layoutParams.leftMargin = margin; 2013bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar layoutParams.rightMargin = margin; 20242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } else { 20342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar layoutParams.height = size; 2043bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar layoutParams.topMargin = margin; 2053bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar layoutParams.bottomMargin = margin; 20642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 20742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 20842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar }; 20942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar testAdapter.setFullSpan(3, 5); 21042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final RecyclerView rv = setupBasic(config, testAdapter); 2113bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar if (addDecorOffsets) { 2123bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar rv.addItemDecoration(new RecyclerView.ItemDecoration() { 2133bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar @Override 2143bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 2153bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar RecyclerView.State state) { 2163bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar if (config.mOrientation == HORIZONTAL) { 2173bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar outRect.set(decorOffset, 0, decorOffset, 0); 2183bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } else { 2193bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar outRect.set(0, decorOffset, 0, decorOffset); 2203bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 2213bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 2223bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar }); 2233bc9692bd8ee36a1eced339564ea6eaa4c8261dbYigit Boyar } 22442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar waitForFirstLayout(rv); 22542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 22642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertTrue("[test sanity] some views should be laid out", mRecyclerView.getChildCount() > 0); 22742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 22842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar View child = mRecyclerView.getChildAt(i); 22942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar final int size = config.mOrientation == HORIZONTAL ? child.getWidth() 23042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar : child.getHeight(); 23142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar assertEquals("child " + i + " should have the size specified in its layout params", 23242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar expectedSizePerPosition[i], size); 23342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 23442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar checkForMainThreadException(); 23542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 23642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 237871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar public void testRTL() throws Throwable { 238871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (boolean changeRtlAfter : new boolean[]{false, true}) { 239871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (boolean oneLine : new boolean[]{false, true}) { 240871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar for (Config config : mBaseVariations) { 241871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar rtlTest(config, changeRtlAfter, oneLine); 242871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar removeRecyclerView(); 243871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 244871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 245871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 246871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 247871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 248871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar void rtlTest(Config config, boolean changeRtlAfter, boolean oneLine) throws Throwable { 249871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (oneLine && config.mOrientation != VERTICAL) { 250871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar return;// nothing to test 251871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 252871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (config.mSpanCount == 1) { 253871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = 2; 254871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 255871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar String logPrefix = config + ", changeRtlAfterLayout:" + changeRtlAfter + ", oneLine:" + oneLine; 256871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mItemCount = 5; 257871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (oneLine) { 258871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = config.mItemCount + 1; 259871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 260871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar config.mSpanCount = Math.min(config.mItemCount - 1, config.mSpanCount); 261871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 262871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 263871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar RecyclerView rv = setupBasic(config); 264871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (changeRtlAfter) { 265871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar waitForFirstLayout(rv); 266871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.expectLayout(1); 267871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.setFakeRtl(true); 268871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.waitForLayout(2); 269871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 270871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mGlm.mFakeRTL = true; 271871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar waitForFirstLayout(rv); 272871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 273871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 274871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals("view should become rtl", true, mGlm.isLayoutRTL()); 275871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar OrientationHelper helper = OrientationHelper.createHorizontalHelper(mGlm); 276871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar View child0 = mGlm.findViewByPosition(0); 277871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar final int secondChildPos = config.mOrientation == VERTICAL ? 1 278871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar : config.mSpanCount; 279871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar View child1 = mGlm.findViewByPosition(secondChildPos); 280871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertNotNull(logPrefix + " child position 0 should be laid out", child0); 281871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertNotNull( 282871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar logPrefix + " second child position " + (secondChildPos) + " should be laid out", 283871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar child1); 284871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar if (config.mOrientation == VERTICAL || !config.mReverseLayout) { 285871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertTrue(logPrefix + " second child should be to the left of first child", 286871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child0) >= helper.getDecoratedEnd(child1)); 287871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals(logPrefix + " first child should be right aligned", 288871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedEnd(child0), helper.getEndAfterPadding()); 289871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } else { 290871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertTrue(logPrefix + " first child should be to the left of second child", 291871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child1) >= helper.getDecoratedEnd(child0)); 292871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar assertEquals(logPrefix + " first child should be left aligned", 293871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar helper.getDecoratedStart(child0), helper.getStartAfterPadding()); 294871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 295871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar checkForMainThreadException(); 296871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 297871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 298888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar public void testMovingAGroupOffScreenForAddedItems() throws Throwable { 299888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 300888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int[] maxId = new int[1]; 301888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar maxId[0] = -1; 302888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final SparseIntArray spanLookups = new SparseIntArray(); 303888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final AtomicBoolean enableSpanLookupLogging = new AtomicBoolean(false); 304888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 305888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 306888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar public int getSpanSize(int position) { 307888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar if (maxId[0] > 0 && mAdapter.getItemAt(position).mId > maxId[0]) { 308888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return 1; 309888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } else if (enableSpanLookupLogging.get() && !rv.mState.isPreLayout()) { 310888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar spanLookups.put(position, spanLookups.get(position, 0) + 1); 311888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 312888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return 3; 313888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 314888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar }); 315121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ((SimpleItemAnimator)rv.getItemAnimator()).setSupportsChangeAnimations(true); 316888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar waitForFirstLayout(rv); 317888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View lastView = rv.getChildAt(rv.getChildCount() - 1); 318888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int lastPos = rv.getChildAdapterPosition(lastView); 319888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar maxId[0] = mAdapter.getItemAt(mAdapter.getItemCount() - 1).mId; 320888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar // now add a lot of items below this and those new views should have span size 3 321888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar enableSpanLookupLogging.set(true); 322888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.expectLayout(2); 323888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mAdapter.addAndNotify(lastPos - 2, 30); 324888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar mGlm.waitForLayout(2); 325888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar checkForMainThreadException(); 326888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 327888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("last items span count should be queried twice", 2, 328888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar spanLookups.get(lastPos + 30)); 329888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 330888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 331888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 3327e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko public void testCachedBorders() throws Throwable { 3337e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko List<Config> testConfigurations = new ArrayList<Config>(mBaseVariations); 3347e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko testConfigurations.addAll(cachedBordersTestConfigs()); 3357e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (Config config : testConfigurations) { 3367e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko gridCachedBorderstTest(config); 3377e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3387e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3397e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 3407e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko private void gridCachedBorderstTest(Config config) throws Throwable { 3417e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko RecyclerView recyclerView = setupBasic(config); 3427e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko waitForFirstLayout(recyclerView); 3437e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final boolean vertical = config.mOrientation == GridLayoutManager.VERTICAL; 3447e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int expectedSizeSum = vertical ? recyclerView.getWidth() : recyclerView.getHeight(); 3457e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int lastVisible = mGlm.findLastVisibleItemPosition(); 3467e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int i = 0; i < lastVisible; i += config.mSpanCount) { 3477e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko if ((i+1)*config.mSpanCount - 1 < lastVisible) { 3487e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int childrenSizeSum = 0; 3497e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int j = 0; j < config.mSpanCount; j++) { 3507e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko View child = recyclerView.getChildAt(i * config.mSpanCount + j); 3517e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko childrenSizeSum += vertical ? child.getWidth() : child.getHeight(); 3527e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3537e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko assertEquals(expectedSizeSum, childrenSizeSum); 3547e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3557e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3567e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko removeRecyclerView(); 3577e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3587e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 3597e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko private List<Config> cachedBordersTestConfigs() { 3607e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko ArrayList<Config> configs = new ArrayList<Config>(); 3617e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int [] spanCounts = new int[]{88, 279, 741}; 3627e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int [] spanPerItem = new int[]{11, 9, 13}; 3637e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 3647e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (boolean reverseLayout : new boolean[]{false, true}) { 3657e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int i = 0 ; i < spanCounts.length; i++) { 3667e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko Config config = new Config(spanCounts[i], orientation, reverseLayout); 3677e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko config.mSpanPerItem = spanPerItem[i]; 3687e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko configs.add(config); 3697e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3707e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3717e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3727e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko return configs; 3737e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 3747e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 375061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testLayoutParams() throws Throwable { 376061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.HORIZONTAL); 377061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 378061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutParamsTest(GridLayoutManager.VERTICAL); 379061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 380061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 381a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testHorizontalAccessibilitySpanIndices() throws Throwable { 382a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(HORIZONTAL); 383a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 384a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 385a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testVerticalAccessibilitySpanIndices() throws Throwable { 386a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar accessibilitySpanIndicesTest(VERTICAL); 387a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 388a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 389a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void accessibilitySpanIndicesTest(int orientation) throws Throwable { 390a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, orientation, false)); 391a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar waitForFirstLayout(recyclerView); 392a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityDelegateCompat delegateCompat = mRecyclerView 393a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCompatAccessibilityDelegate().getItemDelegate(); 394a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 395a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final View chosen = recyclerView.getChildAt(recyclerView.getChildCount() - 2); 396115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int position = recyclerView.getChildLayoutPosition(chosen); 397a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar runTestOnUiThread(new Runnable() { 398a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 399a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 400a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(chosen, info); 401a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 402a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 403a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 404a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo = info 405a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCollectionItemInfo(); 406a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertNotNull(itemInfo); 407a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span group position", 408a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanGroupIndex(position, mGlm.getSpanCount()), 409a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getColumnIndex() : itemInfo.getRowIndex()); 410a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span index", 411a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanIndex(position, mGlm.getSpanCount()), 412a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowIndex() : itemInfo.getColumnIndex()); 413a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have span size", 414a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ssl.getSpanSize(position), 415a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar orientation == HORIZONTAL ? itemInfo.getRowSpan() : itemInfo.getColumnSpan()); 416a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 417a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 418afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public GridLayoutManager.LayoutParams ensureGridLp(View view) { 419afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar ViewGroup.LayoutParams lp = view.getLayoutParams(); 420afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp; 421afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar if (lp instanceof GridLayoutManager.LayoutParams) { 422afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) lp; 423afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else if (lp == null) { 424afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm 425afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar .generateDefaultLayoutParams(); 426afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 427afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else { 428afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp); 429afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar view.setLayoutParams(glp); 430afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 431afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar return glp; 432afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 433afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 434061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void layoutParamsTest(final int orientation) throws Throwable { 435061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation), 436061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar new GridTestAdapter(100) { 437061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 438061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBindViewHolder(TestViewHolder holder, 439061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int position) { 440061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onBindViewHolder(holder, position); 441afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 442061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int val = 0; 443061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar switch (position % 5) { 444061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 0: 445061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 10; 446061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 447061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 1: 448061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 30; 449061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 450061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 2: 451061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.WRAP_CONTENT; 452061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 453061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 3: 454061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = GridLayoutManager.LayoutParams.FILL_PARENT; 455061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 456061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar case 4: 457061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar val = 200; 458061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar break; 459061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 460061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (orientation == GridLayoutManager.VERTICAL) { 461061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.height = val; 462061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 463061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glp.width = val; 464061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 465061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar holder.itemView.setLayoutParams(glp); 466061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 467061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 468061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 469061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final OrientationHelper helper = mGlm.mOrientationHelper; 470061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2))); 471115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 472115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(0))); 473115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 474115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(1))); 475115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(firstRowSize, 476115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(2))); 477061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0))); 478061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1))); 479061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2))); 480061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 481061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3))); 482115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 483115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(3))); 484115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 485115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(4))); 486115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals(secondRowSize, 487115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar helper.getDecoratedMeasurement(mGlm.findViewByPosition(5))); 488061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3))); 489061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4))); 490061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5))); 491061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 492061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 493061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private int getSize(View view) { 494061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (mGlm.getOrientation() == GridLayoutManager.HORIZONTAL) { 495061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getWidth(); 496061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 497061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return view.getHeight(); 498061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 499061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 50073304eff156157f62075215e795e774803a6f96aYigit Boyar public void testAnchorUpdate() throws InterruptedException { 50173304eff156157f62075215e795e774803a6f96aYigit Boyar GridLayoutManager glm = new GridLayoutManager(getActivity(), 11); 50273304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup spanSizeLookup 50373304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 50473304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 50573304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 50673304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 50773304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 50873304eff156157f62075215e795e774803a6f96aYigit Boyar } 50973304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 20) { 51073304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 51173304eff156157f62075215e795e774803a6f96aYigit Boyar } 51273304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 51373304eff156157f62075215e795e774803a6f96aYigit Boyar } 51473304eff156157f62075215e795e774803a6f96aYigit Boyar }; 51573304eff156157f62075215e795e774803a6f96aYigit Boyar glm.setSpanSizeLookup(spanSizeLookup); 51673304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 11; 51742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state = new RecyclerView.State(); 518cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar mRecyclerView = new RecyclerView(getActivity()); 519061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar state.mItemCount = 1000; 520cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo); 52173304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition); 52273304eff156157f62075215e795e774803a6f96aYigit Boyar 52373304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 13; 524cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo); 52573304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition); 52673304eff156157f62075215e795e774803a6f96aYigit Boyar 52773304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 23; 528cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo); 52973304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition); 53073304eff156157f62075215e795e774803a6f96aYigit Boyar 53173304eff156157f62075215e795e774803a6f96aYigit Boyar glm.mAnchorInfo.mPosition = 35; 532cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo); 53373304eff156157f62075215e795e774803a6f96aYigit Boyar assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition); 53473304eff156157f62075215e795e774803a6f96aYigit Boyar } 53573304eff156157f62075215e795e774803a6f96aYigit Boyar 53673304eff156157f62075215e795e774803a6f96aYigit Boyar public void testSpanLookup() { 537061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(false); 538061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 539061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 540061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupWithCache() { 541061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar spanLookupTest(true); 542061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 543061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 544061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testSpanLookupCache() { 545061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 546061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 547061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 548061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 549061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (position > 6) { 550061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 2; 551061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 552061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 1; 553061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 554061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 555061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 556061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2)); 557061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(4, 5); 558061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3)); 559061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // this should not happen and if happens, it is better to return -1 560061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 561061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5)); 562061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100)); 563061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(6, 5); 564061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 565061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6)); 566061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4)); 567061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(12, 5); 568061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13)); 569061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12)); 570061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7)); 571061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < 6; i++) { 572061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.getCachedSpanIndex(i, 5); 573061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 574061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 575061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < 7; i++) { 576061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child right before " + i, i - 1, 577061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.findReferenceIndexFromCache(i)); 578061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 579061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0)); 580061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 581061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 582061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void spanLookupTest(boolean enableCache) { 58373304eff156157f62075215e795e774803a6f96aYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 58473304eff156157f62075215e795e774803a6f96aYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 58573304eff156157f62075215e795e774803a6f96aYigit Boyar @Override 58673304eff156157f62075215e795e774803a6f96aYigit Boyar public int getSpanSize(int position) { 58773304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 200) { 58873304eff156157f62075215e795e774803a6f96aYigit Boyar return 100; 58973304eff156157f62075215e795e774803a6f96aYigit Boyar } 59073304eff156157f62075215e795e774803a6f96aYigit Boyar if (position > 6) { 59173304eff156157f62075215e795e774803a6f96aYigit Boyar return 2; 59273304eff156157f62075215e795e774803a6f96aYigit Boyar } 59373304eff156157f62075215e795e774803a6f96aYigit Boyar return 1; 59473304eff156157f62075215e795e774803a6f96aYigit Boyar } 59573304eff156157f62075215e795e774803a6f96aYigit Boyar }; 596061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(enableCache); 597061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(0, 5)); 598061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(4, ssl.getCachedSpanIndex(4, 5)); 599061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(5, 5)); 600061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(1, ssl.getCachedSpanIndex(6, 5)); 601061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(7, 5)); 602061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(2, ssl.getCachedSpanIndex(9, 5)); 603061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(0, ssl.getCachedSpanIndex(8, 5)); 604061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 605061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 6061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItem() throws Throwable { 6071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 6081f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(VERTICAL).reverseLayout(false), 100, 0); 6091f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6101f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 6111f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverse() throws Throwable { 6121f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 6131f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(VERTICAL).reverseLayout(true), 100, 6141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 0); 6151f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6161f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 6171f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemHorizontal() throws Throwable { 6181f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 6191f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(HORIZONTAL).reverseLayout( 6201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar false), 100, 0); 6211f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6221f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 6231f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverseHorizontal() throws Throwable { 6241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 6251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config(3, 0).orientation(HORIZONTAL).reverseLayout(true), 6261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 100, 0); 6271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 6291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar /** 6301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * This tests a regression where predictive animations were not working as expected when the 6311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * first item is removed and there aren't any more items to add from that direction. 6321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * First item refers to the default anchor item. 6331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar */ 6341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void removeAnchorItemTest(final Config config, int adapterSize, 6351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int removePos) throws Throwable { 6361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar GridTestAdapter adapter = new GridTestAdapter(adapterSize) { 6371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 6381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 6391f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar int position) { 6401f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar super.onBindViewHolder(holder, position); 6411f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 6421f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (!(lp instanceof ViewGroup.MarginLayoutParams)) { 6431f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar lp = new ViewGroup.MarginLayoutParams(0, 0); 6441f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar holder.itemView.setLayoutParams(lp); 6451f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6461f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp; 6471f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int maxSize; 6481f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 6491f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getWidth(); 6501f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = ViewGroup.MarginLayoutParams.FILL_PARENT; 6511f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 6521f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getHeight(); 6531f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = ViewGroup.MarginLayoutParams.FILL_PARENT; 6541f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6551f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 6561f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int desiredSize; 6571f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (position == removePos) { 6581f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it large 6591f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 4; 6601f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 6611f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it small 6621f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 8; 6631f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6641f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 6651f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = desiredSize; 6661f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 6671f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = desiredSize; 6681f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6691f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6701f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar }; 6711f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView recyclerView = setupBasic(config, adapter); 6721f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar waitForFirstLayout(recyclerView); 6731f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int childCount = mGlm.getChildCount(); 6741f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder toBeRemoved = null; 6751f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>(); 6761f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < childCount; i++) { 6771f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mGlm.getChildAt(i); 6781f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 6791f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (holder.getAdapterPosition() == removePos) { 6801f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeRemoved = holder; 6811f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 6821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeMoved.add(holder); 6831f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6841f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 6851f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertNotNull("test sanity", toBeRemoved); 6861f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("test sanity", childCount - 1, toBeMoved.size()); 6871f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator(); 6881f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.setItemAnimator(loggingItemAnimator); 6891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.reset(); 6901f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.expectRunPendingAnimationsCall(1); 6911f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mGlm.expectLayout(2); 6921f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar adapter.deleteAndNotify(removePos, 1); 6931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mGlm.waitForLayout(1); 6941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.waitForPendingAnimationsCall(2); 6951f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("removed child should receive remove animation", 6961f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mRemoveVHs.contains(toBeRemoved)); 6971f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder vh : toBeMoved) { 6981f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("view holder should be in moved list", 6991f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(vh)); 7001f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 7011f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>(); 7021f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < mGlm.getChildCount(); i++) { 7031f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mGlm.getChildAt(i); 7041f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 7051f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (toBeRemoved != holder && !toBeMoved.contains(holder)) { 7061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar newHolders.add(holder); 7071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 7081f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 7091f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("some new children should show up for the new space", newHolders.size() > 0); 7101f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("no items should receive animate add since they are not new", 0, 7111f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mAddVHs.size()); 7121f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder holder : newHolders) { 7131f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("new holder should receive a move animation", 7141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(holder)); 7151f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 7161f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // for removed view, 3 for new row 7171f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("control against adding too many children due to bad layout state preparation." 7181f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(), 7191f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.getChildCount() <= childCount + 1 + 3); 7201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 7211f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 722a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testSpanGroupIndex() { 723a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final GridLayoutManager.SpanSizeLookup ssl 724a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar = new GridLayoutManager.SpanSizeLookup() { 725a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 726a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getSpanSize(int position) { 727a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 200) { 728a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 100; 729a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 730a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (position > 6) { 731a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 2; 732a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 733a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 1; 734a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 735a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }; 736a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(0, 5)); 737a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(0, ssl.getSpanGroupIndex(4, 5)); 738a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(5, 5)); 739a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(6, 5)); 740a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(1, ssl.getSpanGroupIndex(7, 5)); 741a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(9, 5)); 742a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(2, ssl.getSpanGroupIndex(8, 5)); 743a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 744a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 745061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testNotifyDataSetChange() throws Throwable { 746061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView recyclerView = setupBasic(new Config(3, 100)); 747061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup(); 748061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ssl.setSpanIndexCacheEnabled(true); 749061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(recyclerView); 750061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0); 751061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final Callback callback = new Callback() { 752061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 753061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 754061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 755061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size()); 756061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 757061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 758061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 759061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 760061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 761061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 762061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0); 763061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 764061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 765061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }; 766061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mCallbacks.add(callback); 767061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 768061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.deleteAndNotify(2, 3); 769061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 770061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 771061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 772061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 773afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenHeights() throws Throwable { 774afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 775afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 776afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, 3), new GridTestAdapter(3) { 777afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 778afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 779afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 780afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 781afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 782afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.height = 50 + position * 50; 783afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 784afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 785afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 786afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 787afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 788afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max height", 150, 789afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getHeight()); 790afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 791afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 792afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 793afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max height", 150, 794afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredHeight()); 795afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 796afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 797afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 798afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void testUnevenWidths() throws Throwable { 799afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final Map<Integer, RecyclerView.ViewHolder> viewHolderMap = 800afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new HashMap<Integer, RecyclerView.ViewHolder>(); 801afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar RecyclerView recyclerView = setupBasic(new Config(3, HORIZONTAL, false), 802afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar new GridTestAdapter(3) { 803afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar @Override 804afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 805afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar int position) { 806afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar super.onBindViewHolder(holder, position); 807afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView); 808afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar glp.width = 50 + position * 50; 809afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar viewHolderMap.put(position, holder); 810afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 811afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar }); 812afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar waitForFirstLayout(recyclerView); 813afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 814afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should get max width", 150, 815afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getWidth()); 816afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 817afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 818afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (RecyclerView.ViewHolder vh : viewHolderMap.values()) { 819afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar assertEquals("all items should have measured the max width", 150, 820afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar vh.itemView.getMeasuredWidth()); 821afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 822afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 823afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 824061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testScrollBackAndPreservePositions() throws Throwable { 825061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Config config : mBaseVariations) { 826061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar config.mItemCount = 150; 827061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollBackAndPreservePositionsTest(config); 828061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar removeRecyclerView(); 829061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 830061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 831061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 832204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar public void testSpanSizeChange() throws Throwable { 833204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 834204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar waitForFirstLayout(rv); 835204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertTrue(mGlm.supportsPredictiveItemAnimations()); 836204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.expectLayout(1); 837204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar runTestOnUiThread(new Runnable() { 838204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar @Override 839204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar public void run() { 840204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.setSpanCount(5); 841204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertFalse(mGlm.supportsPredictiveItemAnimations()); 842204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar } 843204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar }); 844204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar checkForMainThreadException(); 845204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.waitForLayout(2); 846204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.expectLayout(2); 847204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mAdapter.deleteAndNotify(3, 2); 848204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mGlm.waitForLayout(2); 849204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar assertTrue(mGlm.supportsPredictiveItemAnimations()); 850204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar } 851204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar 852061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void testCacheSpanIndices() throws Throwable { 853061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(new Config(3, 100)); 854061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true); 855061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 856061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup; 857061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0); 858061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 2, 859061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 860061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.expectLayout(2); 861061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.mFullSpanItems.add(4); 862061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.changeAndNotify(4, 1); 863061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.waitForLayout(2); 864061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("item index 5 should be in span 2", 0, 865061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar getLp(mGlm.findViewByPosition(5)).getSpanIndex()); 866061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 867061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 868061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams getLp(View view) { 869061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return (GridLayoutManager.LayoutParams) view.getLayoutParams(); 870061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 871061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 872061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void scrollBackAndPreservePositionsTest(final Config config) throws Throwable { 873061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final RecyclerView rv = setupBasic(config); 874061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 1; i < mAdapter.getItemCount(); i += config.mSpanCount + 2) { 875061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mAdapter.setFullSpan(i); 876061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 877061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar waitForFirstLayout(rv); 878061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPositions = new int[mAdapter.getItemCount()]; 879061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Arrays.fill(globalPositions, Integer.MIN_VALUE); 880061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int scrollStep = (mGlm.mOrientationHelper.getTotalSpace() / 20) 881061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * (config.mReverseLayout ? -1 : 1); 882061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final String logPrefix = config.toString(); 883061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int[] globalPos = new int[1]; 884061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 885061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 886061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 8871f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertSame("test sanity", mRecyclerView, rv); 888061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = 0; 889061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int visited = 0; 890061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (visited < mAdapter.getItemCount()) { 891061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 892061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 893115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int pos = mRecyclerView.getChildLayoutPosition(child); 894061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (globalPositions[pos] != Integer.MIN_VALUE) { 895061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 896061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 897061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited++; 898061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 899061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 900061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 901061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 902061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 903061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 904061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos] = globalScrollPosition + 905061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 906061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 907061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(logPrefix + " span index should match", 908061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 909061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 910061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 911061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrolled = mGlm.scrollBy(scrollStep, 912061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 913061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrolled; 914061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (scrolled == 0) { 915061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals( 916061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar logPrefix + " If scroll is complete, all views should be visited", 917061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar visited, mAdapter.getItemCount()); 918061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 919061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 920061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (DEBUG) { 921061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions)); 922061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 923061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos[0] = globalScrollPosition; 924061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 925061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 926061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 9271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // test sanity, ensure scroll happened 9281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar runTestOnUiThread(new Runnable() { 9291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 9301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void run() { 9311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int childCount = mGlm.getChildCount(); 9321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final BitSet expectedPositions = new BitSet(); 9331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < childCount; i ++) { 9341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar expectedPositions.set(mAdapter.getItemCount() - i - 1); 9351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 9361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i <childCount; i ++) { 9371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final View view = mGlm.getChildAt(i); 9381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar int position = mGlm.getPosition(view); 9391f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("child position should be in last page", expectedPositions.get(position)); 9401f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 9411f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 9421f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar }); 9431f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar getInstrumentation().waitForIdleSync(); 944061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar runTestOnUiThread(new Runnable() { 945061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 946061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void run() { 947061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalScrollPosition = globalPos[0]; 948061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // now scroll back and make sure global positions match 949061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar BitSet shouldTest = new BitSet(mAdapter.getItemCount()); 950061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.set(0, mAdapter.getItemCount() - 1, true); 951061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar String assertPrefix = config 952061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar + " global pos must match when scrolling in reverse for position "; 953061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int scrollAmount = Integer.MAX_VALUE; 954061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (!shouldTest.isEmpty() && scrollAmount != 0) { 955061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 956061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View child = mRecyclerView.getChildAt(i); 957115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int pos = mRecyclerView.getChildLayoutPosition(child); 958061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!shouldTest.get(pos)) { 959061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar continue; 960061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 961061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) 962061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar child.getLayoutParams(); 963061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar shouldTest.clear(pos); 964061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int globalPos; 965061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (config.mReverseLayout) { 966061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 967061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedEnd(child); 968061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 969061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPos = globalScrollPosition + 970061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.mOrientationHelper.getDecoratedStart(child); 971061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 972061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals(assertPrefix + pos, 973061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalPositions[pos], globalPos); 974061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertEquals("span index should match", 975061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mGlm.getSpanSizeLookup().getSpanIndex(pos, mGlm.getSpanCount()), 976061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lp.getSpanIndex()); 977061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 978061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar scrollAmount = mGlm.scrollBy(-scrollStep, 979061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mRecyclerView.mRecycler, mRecyclerView.mState); 980061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar globalScrollPosition += scrollAmount; 981061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 982061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assertTrue("all views should be seen", shouldTest.isEmpty()); 983061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 984061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 985061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar checkForMainThreadException(); 986061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 987061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 988061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class WrappedGridLayoutManager extends GridLayoutManager { 989061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 990061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar CountDownLatch mLayoutLatch; 991061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 992061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar List<Callback> mCallbacks = new ArrayList<Callback>(); 993061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 994871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar Boolean mFakeRTL; 995871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 996061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount) { 997061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount); 998061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 999061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1000061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public WrappedGridLayoutManager(Context context, int spanCount, int orientation, 1001061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean reverseLayout) { 1002061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(context, spanCount, orientation, reverseLayout); 1003061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1004061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1005061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 1006871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar protected boolean isLayoutRTL() { 1007871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar return mFakeRTL == null ? super.isLayoutRTL() : mFakeRTL; 1008871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 1009871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 1010871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar public void setFakeRtl(Boolean fakeRtl) { 1011871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar mFakeRTL = fakeRtl; 1012871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar try { 1013871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar requestLayoutOnUIThread(mRecyclerView); 1014871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } catch (Throwable throwable) { 1015871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar postExceptionToInstrumentation(throwable); 1016871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 1017871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar } 1018871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar 1019871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar @Override 1020061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1021061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar try { 1022061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 1023061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onBeforeLayout(recycler, state); 1024061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1025061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super.onLayoutChildren(recycler, state); 1026061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (Callback callback : mCallbacks) { 1027061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar callback.onAfterLayout(recycler, state); 1028061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1029061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } catch (Throwable t) { 1030061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar postExceptionToInstrumentation(t); 1031061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1032061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.countDown(); 1033061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1034061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1035888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 1036888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar LayoutState createLayoutState() { 1037888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return new LayoutState() { 1038888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar @Override 1039888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View next(RecyclerView.Recycler recycler) { 1040888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final boolean hadMore = hasMore(mRecyclerView.mState); 1041888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar final int position = mCurrentPosition; 1042888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar View next = super.next(recycler); 1043888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("if has more, should return a view", hadMore, next != null); 1044888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar assertEquals("position of the returned view must match current position", 1045888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar position, RecyclerView.getChildViewHolderInt(next).getLayoutPosition()); 1046888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar return next; 1047888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 1048888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar }; 1049888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar } 1050888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar 1051061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void expectLayout(int layoutCount) { 1052061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch = new CountDownLatch(layoutCount); 1053061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1054061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1055061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void waitForLayout(int seconds) throws InterruptedException { 1056061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mLayoutLatch.await(seconds, SECONDS); 1057061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1058061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1059061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1060061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Config { 1061061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1062061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mSpanCount; 1063061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mOrientation = GridLayoutManager.VERTICAL; 1064061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int mItemCount = 1000; 10657e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int mSpanPerItem = 1; 1066061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar boolean mReverseLayout = false; 1067061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1068061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config(int spanCount, int itemCount) { 1069061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 1070061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mItemCount = itemCount; 1071061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1072061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1073061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public Config(int spanCount, int orientation, boolean reverseLayout) { 1074061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanCount = spanCount; 1075061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 1076061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mReverseLayout = reverseLayout; 1077061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1078061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1079061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Config orientation(int orientation) { 1080061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mOrientation = orientation; 1081061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return this; 1082061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1083061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1084061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 1085061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public String toString() { 1086061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return "Config{" + 1087061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar "mSpanCount=" + mSpanCount + 1088061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v") + 1089061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mItemCount=" + mItemCount + 1090061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar ", mReverseLayout=" + mReverseLayout + 1091061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar '}'; 1092061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 10931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 10941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public Config reverseLayout(boolean reverseLayout) { 10951f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mReverseLayout = reverseLayout; 10961f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar return this; 10971f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 10981f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 10991f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 1100061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1101061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1102061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class GridTestAdapter extends TestAdapter { 1103061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1104061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Set<Integer> mFullSpanItems = new HashSet<Integer>(); 11057e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int mSpanPerItem = 1; 1106061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1107061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar GridTestAdapter(int count) { 1108061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar super(count); 1109061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1110061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 11117e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko GridTestAdapter(int count, int spanPerItem) { 11127e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko super(count); 11137e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mSpanPerItem = spanPerItem; 11147e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 11157e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 1116061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void setFullSpan(int... items) { 1117061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i : items) { 1118061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mFullSpanItems.add(i); 1119061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1120061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1121061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1122061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar void assignSpanSizeLookup(final GridLayoutManager glm) { 1123061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 1124061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 1125061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public int getSpanSize(int position) { 11267e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko return mFullSpanItems.contains(position) ? glm.getSpanCount() : mSpanPerItem; 1127061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1128061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar }); 1129061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1130061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1131061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1132061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar class Callback { 1133061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1134061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 1135061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 1136061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 1137061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) { 1138061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 113973304eff156157f62075215e795e774803a6f96aYigit Boyar } 114073304eff156157f62075215e795e774803a6f96aYigit Boyar} 1141