10a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarpackage android.support.v7.widget; 20a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 30a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.graphics.Rect; 40a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.annotation.Nullable; 50a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.util.Log; 60a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.view.View; 70a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.view.ViewGroup; 80a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 90a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.lang.reflect.Field; 100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.ArrayList; 110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.Arrays; 120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.HashSet; 130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.LinkedHashMap; 140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.List; 150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.Map; 160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.concurrent.CountDownLatch; 170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.concurrent.TimeUnit; 180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END; 210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START; 220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL; 230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; 240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE; 250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL; 260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.assertEquals; 270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.assertFalse; 280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.assertNotNull; 290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.assertTrue; 300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyarimport static java.util.concurrent.TimeUnit.SECONDS; 3266826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar 3366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyarimport org.hamcrest.CoreMatchers; 3466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyarimport org.hamcrest.MatcherAssert; 3566826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar 360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarpublic class BaseStaggeredGridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest { 370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static final boolean DEBUG = false; 390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static final int AVG_ITEM_PER_VIEW = 3; 400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static final String TAG = "StaggeredGridLayoutManagerTest"; 410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar volatile WrappedLayoutManager mLayoutManager; 420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar GridTestAdapter mAdapter; 430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static List<Config> createBaseVariations() { 450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar List<Config> variations = new ArrayList<>(); 460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int orientation : new int[]{VERTICAL, HORIZONTAL}) { 470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (boolean reverseLayout : new boolean[]{false, true}) { 480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int spanCount : new int[]{1, 3}) { 490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int gapStrategy : new int[]{GAP_HANDLING_NONE, 500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}) { 514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar for (boolean wrap : new boolean[]{true, false}) { 524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar variations.add(new Config(orientation, reverseLayout, spanCount, 534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar gapStrategy).wrap(wrap)); 544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return variations; 610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static List<Config> addConfigVariation(List<Config> base, String fieldName, 640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Object... variations) 650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar throws CloneNotSupportedException, NoSuchFieldException, IllegalAccessException { 660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar List<Config> newConfigs = new ArrayList<Config>(); 670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Field field = Config.class.getDeclaredField(fieldName); 680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Config config : base) { 690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Object variation : variations) { 700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config newConfig = (Config) config.clone(); 710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar field.set(newConfig, variation); 720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar newConfigs.add(newConfig); 730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return newConfigs; 760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void setupByConfig(Config config) throws Throwable { 790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar setupByConfig(config, new GridTestAdapter(config.mItemCount, config.mOrientation)); 800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void setupByConfig(Config config, GridTestAdapter adapter) throws Throwable { 830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mAdapter = adapter; 841ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik mRecyclerView = new WrappedRecyclerView(getActivity()); 850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerView.setAdapter(mAdapter); 860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerView.setHasFixedSize(true); 87a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation); 880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mLayoutManager.setGapStrategy(config.mGapStrategy); 890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mLayoutManager.setReverseLayout(config.mReverseLayout); 900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerView.setLayoutManager(mLayoutManager); 910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { 920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView.State state) { 950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar StaggeredGridLayoutManager.LayoutParams 970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); 980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertNotNull("view should have layout params assigned", lp); 990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertNotNull("when item offsets are requested, view should have a valid span", 1000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp.mSpan); 1010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable t) { 1020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar postExceptionToInstrumentation(t); 1030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar }); 1060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar StaggeredGridLayoutManager.LayoutParams getLp(View view) { 1090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); 1100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void waitFirstLayout() throws Throwable { 1130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mLayoutManager.expectLayouts(1); 1140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar setRecyclerView(mRecyclerView); 1158cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar mLayoutManager.waitForLayout(3); 1160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar getInstrumentation().waitForIdleSync(); 1170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar /** 1200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * enqueues an empty runnable to main thread so that we can be assured it did run 1210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * 1220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar * @param count Number of times to run 1230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar */ 1240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected void waitForMainThread(int count) throws Throwable { 1250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final AtomicInteger i = new AtomicInteger(count); 1260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar while (i.get() > 0) { 1270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar runTestOnUiThread(new Runnable() { 1280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 1290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void run() { 1300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar i.decrementAndGet(); 1310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar }); 1330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void assertRectSetsNotEqual(String message, Map<Item, Rect> before, 1370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Map<Item, Rect> after) { 1380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Throwable throwable = null; 1390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 1400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertRectSetsEqual("NOT " + message, before, after); 1410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable t) { 1420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar throwable = t; 1430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertNotNull(message + " two layout should be different", throwable); 1450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after) { 1480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertRectSetsEqual(message, before, after, true); 1490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after, 1520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean strictItemEquality) { 1530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar StringBuilder log = new StringBuilder(); 1540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (DEBUG) { 1550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("checking rectangle equality.\n"); 1560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("total space:" + mLayoutManager.mPrimaryOrientation.getTotalSpace()); 1570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("before:"); 1580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Map.Entry<Item, Rect> entry : before.entrySet()) { 1590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("\n").append(entry.getKey().mAdapterIndex).append(":") 1600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .append(entry.getValue()); 1610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("\nafter:"); 1630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Map.Entry<Item, Rect> entry : after.entrySet()) { 1640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar log.append("\n").append(entry.getKey().mAdapterIndex).append(":") 1650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .append(entry.getValue()); 1660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar message += "\n\n" + log.toString(); 1680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertEquals(message + ": item counts should be equal", before.size() 1700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar , after.size()); 1710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Map.Entry<Item, Rect> entry : before.entrySet()) { 1720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final Item beforeItem = entry.getKey(); 1730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Rect afterRect = null; 1740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (strictItemEquality) { 1750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar afterRect = after.get(beforeItem); 1760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertNotNull(message + ": Same item should be visible after simple re-layout", 1770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar afterRect); 1780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 1790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Map.Entry<Item, Rect> afterEntry : after.entrySet()) { 1800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final Item afterItem = afterEntry.getKey(); 1810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (afterItem.mAdapterIndex == beforeItem.mAdapterIndex) { 1820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar afterRect = afterEntry.getValue(); 1830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar break; 1840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertNotNull(message + ": Item with same adapter index should be visible " + 1870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar "after simple re-layout", 1880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar afterRect); 1890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertEquals(message + ": Item should be laid out at the same coordinates", 1910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar entry.getValue(), 1920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar afterRect); 1930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 1950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 1960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected void assertViewPositions(Config config) { 1970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ArrayList<ArrayList<View>> viewsBySpan = mLayoutManager.collectChildrenBySpan(); 1980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar OrientationHelper orientationHelper = OrientationHelper 1990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .createOrientationHelper(mLayoutManager, config.mOrientation); 2000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (ArrayList<View> span : viewsBySpan) { 2010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // validate all children's order. first child should have min start mPosition 2020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int count = span.size(); 2030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0, j = 1; j < count; i++, j++) { 2040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View prev = span.get(i); 2050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View next = span.get(j); 2060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertTrue(config + " prev item should be above next item", 2070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar orientationHelper.getDecoratedEnd(prev) <= orientationHelper 2080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .getDecoratedStart(next) 2090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ); 2100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected TargetTuple findInvisibleTarget(Config config) { 2160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int minPosition = Integer.MAX_VALUE, maxPosition = Integer.MIN_VALUE; 2170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < mLayoutManager.getChildCount(); i++) { 2180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View child = mLayoutManager.getChildAt(i); 2190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int position = mRecyclerView.getChildLayoutPosition(child); 2200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position < minPosition) { 2210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar minPosition = position; 2220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position > maxPosition) { 2240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar maxPosition = position; 2250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int tailTarget = maxPosition + (mAdapter.getItemCount() - maxPosition) / 2; 2280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int headTarget = minPosition / 2; 2290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int target; 2300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // where will the child come from ? 2310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int itemLayoutDirection; 2320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (Math.abs(tailTarget - maxPosition) > Math.abs(headTarget - minPosition)) { 2330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar target = tailTarget; 2340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar itemLayoutDirection = config.mReverseLayout ? LAYOUT_START : LAYOUT_END; 2350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 2360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar target = headTarget; 2370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar itemLayoutDirection = config.mReverseLayout ? LAYOUT_END : LAYOUT_START; 2380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (DEBUG) { 2400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Log.d(TAG, 2410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar config + " target:" + target + " min:" + minPosition + ", max:" + maxPosition); 2420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return new TargetTuple(target, itemLayoutDirection); 2440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected void scrollToPositionWithOffset(final int position, final int offset) 2470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar throws Throwable { 2480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar runTestOnUiThread(new Runnable() { 2490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 2500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void run() { 2510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mLayoutManager.scrollToPositionWithOffset(position, offset); 2520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar }); 2540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar static class OnLayoutListener { 2570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void before(RecyclerView.Recycler recycler, RecyclerView.State state) { 2590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void after(RecyclerView.Recycler recycler, RecyclerView.State state) { 2620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar static class VisibleChildren { 2660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int[] firstVisiblePositions; 2680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int[] firstFullyVisiblePositions; 2700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int[] lastVisiblePositions; 2720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int[] lastFullyVisiblePositions; 2740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View findFirstPartialVisibleClosestToStart; 2760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View findFirstPartialVisibleClosestToEnd; 2770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar VisibleChildren(int spanCount) { 2790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar firstFullyVisiblePositions = new int[spanCount]; 2800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar firstVisiblePositions = new int[spanCount]; 2810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lastVisiblePositions = new int[spanCount]; 2820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lastFullyVisiblePositions = new int[spanCount]; 2830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < spanCount; i++) { 2840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar firstFullyVisiblePositions[i] = RecyclerView.NO_POSITION; 2850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar firstVisiblePositions[i] = RecyclerView.NO_POSITION; 2860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lastVisiblePositions[i] = RecyclerView.NO_POSITION; 2870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lastFullyVisiblePositions[i] = RecyclerView.NO_POSITION; 2880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 2910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 2920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public boolean equals(Object o) { 2930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (this == o) { 2940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return true; 2950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (o == null || getClass() != o.getClass()) { 2970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 2980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 2990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar VisibleChildren that = (VisibleChildren) o; 3010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (!Arrays.equals(firstFullyVisiblePositions, that.firstFullyVisiblePositions)) { 3030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (findFirstPartialVisibleClosestToStart 3060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar != null ? !findFirstPartialVisibleClosestToStart 3070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .equals(that.findFirstPartialVisibleClosestToStart) 3080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar : that.findFirstPartialVisibleClosestToStart != null) { 3090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (!Arrays.equals(firstVisiblePositions, that.firstVisiblePositions)) { 3120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (!Arrays.equals(lastFullyVisiblePositions, that.lastFullyVisiblePositions)) { 3150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (findFirstPartialVisibleClosestToEnd != null ? !findFirstPartialVisibleClosestToEnd 3180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .equals(that.findFirstPartialVisibleClosestToEnd) 3190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar : that.findFirstPartialVisibleClosestToEnd 3200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar != null) { 3210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (!Arrays.equals(lastVisiblePositions, that.lastVisiblePositions)) { 3240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return false; 3250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return true; 3280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 3310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public int hashCode() { 3320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int result = Arrays.hashCode(firstVisiblePositions); 3330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = 31 * result + Arrays.hashCode(firstFullyVisiblePositions); 3340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = 31 * result + Arrays.hashCode(lastVisiblePositions); 3350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = 31 * result + Arrays.hashCode(lastFullyVisiblePositions); 3360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = 31 * result + (findFirstPartialVisibleClosestToStart != null 3370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ? findFirstPartialVisibleClosestToStart 3380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .hashCode() : 0); 3390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = 31 * result + (findFirstPartialVisibleClosestToEnd != null 3400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ? findFirstPartialVisibleClosestToEnd 3410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .hashCode() 3420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar : 0); 3430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return result; 3440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 3470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public String toString() { 3480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return "VisibleChildren{" + 3490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar "firstVisiblePositions=" + Arrays.toString(firstVisiblePositions) + 3500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ", firstFullyVisiblePositions=" + Arrays.toString(firstFullyVisiblePositions) + 3510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ", lastVisiblePositions=" + Arrays.toString(lastVisiblePositions) + 3520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ", lastFullyVisiblePositions=" + Arrays.toString(lastFullyVisiblePositions) + 3530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ", findFirstPartialVisibleClosestToStart=" + 3540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar viewToString(findFirstPartialVisibleClosestToStart) + 3550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ", findFirstPartialVisibleClosestToEnd=" + 3560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar viewToString(findFirstPartialVisibleClosestToEnd) + 3570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar '}'; 3580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar private String viewToString(View view) { 3610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (view == null) { 3620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return null; 3630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ViewGroup.LayoutParams lp = view.getLayoutParams(); 3650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (lp instanceof RecyclerView.LayoutParams == false) { 3660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return System.identityHashCode(view) + "(?)"; 3670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView.LayoutParams rvlp = (RecyclerView.LayoutParams) lp; 3690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return System.identityHashCode(view) + "(" + rvlp.getViewAdapterPosition() + ")"; 3700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar abstract static class OnBindCallback { 3740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar abstract void onBoundItem(TestViewHolder vh, int position); 3760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean assignRandomSize() { 3780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return true; 3790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar void onCreatedViewHolder(TestViewHolder vh) { 3820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 3840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar static class Config implements Cloneable { 3860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar static final int DEFAULT_ITEM_COUNT = 300; 3880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mOrientation = OrientationHelper.VERTICAL; 3900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean mReverseLayout = false; 3920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mSpanCount = 3; 3940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; 3960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mItemCount = DEFAULT_ITEM_COUNT; 3980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 3994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar boolean mWrap = false; 4004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 4010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config(int orientation, boolean reverseLayout, int spanCount, int gapStrategy) { 4020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOrientation = orientation; 4030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mReverseLayout = reverseLayout; 4040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSpanCount = spanCount; 4050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mGapStrategy = gapStrategy; 4060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public Config() { 4090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config orientation(int orientation) { 4130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOrientation = orientation; 4140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return this; 4150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config reverseLayout(boolean reverseLayout) { 4180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mReverseLayout = reverseLayout; 4190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return this; 4200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config spanCount(int spanCount) { 4230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSpanCount = spanCount; 4240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return this; 4250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Config gapStrategy(int gapStrategy) { 4280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mGapStrategy = gapStrategy; 4290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return this; 4300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public Config itemCount(int itemCount) { 4330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mItemCount = itemCount; 4340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return this; 4350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public Config wrap(boolean wrap) { 4384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar mWrap = wrap; 4394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar return this; 4404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 4414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 4420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 4430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public String toString() { 4440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return "[CONFIG:" + 4450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar " span:" + mSpanCount + "," + 4460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar " orientation:" + (mOrientation == HORIZONTAL ? "horz," : "vert,") + 4470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar " reverse:" + (mReverseLayout ? "T" : "F") + 4480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar " itemCount:" + mItemCount + 4494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar " wrapContent:" + mWrap + 4500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar " gap strategy: " + gapStrategyName(mGapStrategy); 4510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected static String gapStrategyName(int gapStrategy) { 4540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar switch (gapStrategy) { 4550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar case GAP_HANDLING_NONE: 4560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return "none"; 4570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS: 4580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return "move spans"; 4590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return "gap strategy: unknown"; 4610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 4640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public Object clone() throws CloneNotSupportedException { 4650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return super.clone(); 4660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar class WrappedLayoutManager extends StaggeredGridLayoutManager { 4700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar CountDownLatch layoutLatch; 4721ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik CountDownLatch prefetchLatch; 4730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar OnLayoutListener mOnLayoutListener; 4740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // gradle does not yet let us customize manifest for tests which is necessary to test RTL. 4750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // until bug is fixed, we'll fake it. 4760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // public issue id: 57819 4770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Boolean mFakeRTL; 478a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska CountDownLatch mSnapLatch; 4790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 4810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean isLayoutRTL() { 4820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return mFakeRTL == null ? super.isLayoutRTL() : mFakeRTL; 4830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 4850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void expectLayouts(int count) { 4860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar layoutLatch = new CountDownLatch(count); 4870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 4880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 48966826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar public void waitForLayout(int seconds) throws Throwable { 49066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar layoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS); 491bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar checkForMainThreadException(); 49266826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar MatcherAssert.assertThat("all layouts should complete on time", 49366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar layoutLatch.getCount(), CoreMatchers.is(0L)); 49466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar // use a runnable to ensure RV layout is finished 49566826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar getInstrumentation().runOnMainSync(new Runnable() { 49666826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar @Override 49766826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar public void run() { 49866826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar } 49966826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar }); 5000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 5021ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik public void expectPrefetch(int count) { 5031ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik prefetchLatch = new CountDownLatch(count); 5041ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik } 5051ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik 5061ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik public void waitForPrefetch(int seconds) throws Throwable { 5071ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS); 5081ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik checkForMainThreadException(); 5091ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik MatcherAssert.assertThat("all prefetches should complete on time", 5101ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik prefetchLatch.getCount(), CoreMatchers.is(0L)); 5111ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik // use a runnable to ensure RV layout is finished 5121ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik getInstrumentation().runOnMainSync(new Runnable() { 5131ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik @Override 5141ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik public void run() { 5151ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik } 5161ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik }); 5171ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik } 5181ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik 519c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void expectIdleState(int count) { 520a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska mSnapLatch = new CountDownLatch(count); 521c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 522c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 523c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 524c587f7dba5a337169e854e235da59f595255d6ccAga Madurska super.onScrollStateChanged(recyclerView, newState); 525c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (newState == RecyclerView.SCROLL_STATE_IDLE) { 526a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska mSnapLatch.countDown(); 527a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska if (mSnapLatch.getCount() == 0L) { 528c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mRecyclerView.removeOnScrollListener(this); 529c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 530c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 531c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 532c587f7dba5a337169e854e235da59f595255d6ccAga Madurska }); 533c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 534c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 535c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void waitForSnap(int seconds) throws Throwable { 536a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska mSnapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS); 537c587f7dba5a337169e854e235da59f595255d6ccAga Madurska checkForMainThreadException(); 538c587f7dba5a337169e854e235da59f595255d6ccAga Madurska MatcherAssert.assertThat("all scrolling should complete on time", 539a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska mSnapLatch.getCount(), CoreMatchers.is(0L)); 540c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // use a runnable to ensure RV layout is finished 541c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getInstrumentation().runOnMainSync(new Runnable() { 542c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 543c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public void run() { 544c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 545c587f7dba5a337169e854e235da59f595255d6ccAga Madurska }); 546c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 547c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 5480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void assertNoLayout(String msg, long timeout) throws Throwable { 5490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar layoutLatch.await(timeout, TimeUnit.SECONDS); 5500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar assertFalse(msg, layoutLatch.getCount() == 0); 5510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 5530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 5540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 5550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar String before; 5560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (DEBUG) { 5570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar before = layoutToString("before"); 5580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 5590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar before = "enable DEBUG"; 5600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 5620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOnLayoutListener != null) { 5630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOnLayoutListener.before(recycler, state); 5640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super.onLayoutChildren(recycler, state); 5660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOnLayoutListener != null) { 5670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOnLayoutListener.after(recycler, state); 5680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar validateChildren(before); 5700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable t) { 5710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar postExceptionToInstrumentation(t); 5720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 5740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar layoutLatch.countDown(); 5750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 5770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 5780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) { 5790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 5800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int result = super.scrollBy(dt, recycler, state); 5810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar validateChildren(); 5820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return result; 5830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable t) { 5840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar postExceptionToInstrumentation(t); 5850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 5870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return 0; 5880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 5890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 590c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View findFirstVisibleItemClosestToCenter() { 591c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 592c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 593c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int boundsCenter = (boundsStart + boundsEnd) / 2; 594c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final Rect childBounds = new Rect(); 595c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int minDist = Integer.MAX_VALUE; 596c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View closestChild = null; 597c587f7dba5a337169e854e235da59f595255d6ccAga Madurska for (int i = getChildCount() - 1; i >= 0; i--) { 598c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final View child = getChildAt(i); 599c587f7dba5a337169e854e235da59f595255d6ccAga Madurska childBounds.setEmpty(); 600c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getDecoratedBoundsWithMargins(child, childBounds); 601c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int childCenter = canScrollHorizontally() 602c587f7dba5a337169e854e235da59f595255d6ccAga Madurska ? childBounds.centerX() : childBounds.centerY(); 603c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int dist = Math.abs(boundsCenter - childCenter); 604c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (dist < minDist) { 605c587f7dba5a337169e854e235da59f595255d6ccAga Madurska minDist = dist; 606c587f7dba5a337169e854e235da59f595255d6ccAga Madurska closestChild = child; 607c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 608c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 609c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return closestChild; 610c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 611c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 6120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public WrappedLayoutManager(int spanCount, int orientation) { 6130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super(spanCount, orientation); 6140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 6160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ArrayList<ArrayList<View>> collectChildrenBySpan() { 6170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar ArrayList<ArrayList<View>> viewsBySpan = new ArrayList<ArrayList<View>>(); 6180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < getSpanCount(); i++) { 6190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar viewsBySpan.add(new ArrayList<View>()); 6200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < getChildCount(); i++) { 6220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View view = getChildAt(i); 6230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar LayoutParams lp 6240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar = (LayoutParams) view 6250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .getLayoutParams(); 6260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar viewsBySpan.get(lp.mSpan.mIndex).add(view); 6270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return viewsBySpan; 6290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 6310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Nullable 6320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 6330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler, 6340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView.State state) { 6350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View result = null; 6360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 6370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar result = super.onFocusSearchFailed(focused, direction, recycler, state); 6380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar validateChildren(); 6390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable t) { 6400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar postExceptionToInstrumentation(t); 6410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return result; 6430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 6450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Rect getViewBounds(View view) { 6460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (getOrientation() == HORIZONTAL) { 6470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return new Rect( 6480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedStart(view), 6490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSecondaryOrientation.getDecoratedStart(view), 6500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view), 6510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSecondaryOrientation.getDecoratedEnd(view)); 6520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 6530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return new Rect( 6540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSecondaryOrientation.getDecoratedStart(view), 6550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedStart(view), 6560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSecondaryOrientation.getDecoratedEnd(view), 6570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view)); 6580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 6610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public String getBoundsLog() { 6620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar StringBuilder sb = new StringBuilder(); 6630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar sb.append("view bounds:[start:").append(mPrimaryOrientation.getStartAfterPadding()) 6640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .append(",").append(" end").append(mPrimaryOrientation.getEndAfterPadding()); 6650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar sb.append("\nchildren bounds\n"); 6660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int childCount = getChildCount(); 6670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < childCount; i++) { 6680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View child = getChildAt(i); 6690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar sb.append("child (ind:").append(i).append(", pos:").append(getPosition(child)) 6700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .append("[").append("start:").append( 6710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedStart(child)).append(", end:") 6720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .append(mPrimaryOrientation.getDecoratedEnd(child)).append("]\n"); 6730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return sb.toString(); 6750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 6770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public VisibleChildren traverseAndFindVisibleChildren() { 6780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int childCount = getChildCount(); 6790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final VisibleChildren visibleChildren = new VisibleChildren(getSpanCount()); 6800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int start = mPrimaryOrientation.getStartAfterPadding(); 6810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int end = mPrimaryOrientation.getEndAfterPadding(); 6820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < childCount; i++) { 6830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View child = getChildAt(i); 6840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int childStart = mPrimaryOrientation.getDecoratedStart(child); 6850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); 6860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final boolean fullyVisible = childStart >= start && childEnd <= end; 6870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final boolean hidden = childEnd <= start || childStart >= end; 6880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (hidden) { 6890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar continue; 6900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int position = getPosition(child); 6920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int span = getLp(child).getSpanIndex(); 6930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (fullyVisible) { 6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position < visibleChildren.firstFullyVisiblePositions[span] || 6950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.firstFullyVisiblePositions[span] 6960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar == RecyclerView.NO_POSITION) { 6970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.firstFullyVisiblePositions[span] = position; 6980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 6990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position > visibleChildren.lastFullyVisiblePositions[span]) { 7010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.lastFullyVisiblePositions[span] = position; 7020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position < visibleChildren.firstVisiblePositions[span] || 7060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.firstVisiblePositions[span] == RecyclerView.NO_POSITION) { 7070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.firstVisiblePositions[span] = position; 7080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (position > visibleChildren.lastVisiblePositions[span]) { 7110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.lastVisiblePositions[span] = position; 7120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (visibleChildren.findFirstPartialVisibleClosestToStart == null) { 7140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.findFirstPartialVisibleClosestToStart = child; 7150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar visibleChildren.findFirstPartialVisibleClosestToEnd = child; 7170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return visibleChildren; 7190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Map<Item, Rect> collectChildCoordinates() throws Throwable { 7220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final Map<Item, Rect> items = new LinkedHashMap<Item, Rect>(); 7230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar runTestOnUiThread(new Runnable() { 7240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 7250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void run() { 7260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int childCount = getChildCount(); 7270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < childCount; i++) { 7280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar View child = getChildAt(i); 7290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // do it if and only if child is visible 7300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (child.getRight() < 0 || child.getBottom() < 0 || 7310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar child.getLeft() >= getWidth() || child.getTop() >= getHeight()) { 7320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // invisible children may be drawn in cases like scrolling so we should 7330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // ignore them 7340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar continue; 7350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar LayoutParams lp = (LayoutParams) child 7370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .getLayoutParams(); 7380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TestViewHolder vh = (TestViewHolder) lp.mViewHolder; 7390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar items.put(vh.mBoundItem, getViewBounds(child)); 7400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar }); 7430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return items; 7440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setFakeRtl(Boolean fakeRtl) { 7480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mFakeRTL = fakeRtl; 7490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar try { 7500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 7510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } catch (Throwable throwable) { 7520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar postExceptionToInstrumentation(throwable); 7530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar String layoutToString(String hint) { 7570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar StringBuilder sb = new StringBuilder(); 7580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar sb.append("LAYOUT POSITIONS AND INDICES ").append(hint).append("\n"); 7590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (int i = 0; i < getChildCount(); i++) { 7600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final View view = getChildAt(i); 7610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); 7620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar sb.append(String.format("index: %d pos: %d top: %d bottom: %d span: %d isFull:%s", 7630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar i, getPosition(view), 7640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedStart(view), 7650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view), 7660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar layoutParams.getSpanIndex(), layoutParams.isFullSpan())).append("\n"); 7670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return sb.toString(); 7690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected void validateChildren() { 7720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar validateChildren(null); 7730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 7750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar private void validateChildren(String msg) { 7760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (getChildCount() == 0 || mRecyclerView.mState.isPreLayout()) { 7770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return; 7780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int dir = mShouldReverseLayout ? -1 : 1; 7800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int i = 0; 7810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int pos = -1; 7820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar while (i < getChildCount()) { 7830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 7840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (lp.isItemRemoved()) { 7850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar i++; 7860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar continue; 7870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar pos = getPosition(getChildAt(i)); 7890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar break; 7900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (pos == -1) { 7920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return; 7930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar while (++i < getChildCount()) { 7950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 7960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (lp.isItemRemoved()) { 7970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar continue; 7980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 7990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar pos += dir; 8000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (getPosition(getChildAt(i)) != pos) { 8010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar throw new RuntimeException("INVALID POSITION FOR CHILD " + i + "\n" + 8020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar layoutToString("ERROR") + "\n msg:" + msg); 8030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8061ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik 8071ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik @Override 8081ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) { 8091ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik if (prefetchLatch != null) prefetchLatch.countDown(); 8101ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik return super.gatherPrefetchIndices(dx, dy, state, outIndices); 8111ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik } 8120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar class GridTestAdapter extends TestAdapter { 8150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mOrientation; 8170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mRecyclerViewWidth; 8180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int mRecyclerViewHeight; 8190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Integer mSizeReference = null; 8200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar // original ids of items that should be full span 8220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar HashSet<Integer> mFullSpanItems = new HashSet<Integer>(); 8230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected boolean mViewsHaveEqualSize = false; // size in the scrollable direction 8250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected OnBindCallback mOnBindCallback; 8270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar GridTestAdapter(int count, int orientation) { 8290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super(count); 8300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOrientation = orientation; 8310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 8340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 8350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int viewType) { 8360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerViewWidth = parent.getWidth(); 8370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerViewHeight = parent.getHeight(); 8380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 8390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOnBindCallback != null) { 8400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOnBindCallback.onCreatedViewHolder(vh); 8410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return vh; 8430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 8460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void offsetOriginalIndices(int start, int offset) { 8470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mFullSpanItems.size() > 0) { 8480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar HashSet<Integer> old = mFullSpanItems; 8490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mFullSpanItems = new HashSet<Integer>(); 8500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar for (Integer i : old) { 8510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (i < start) { 8520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mFullSpanItems.add(i); 8530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else if (offset > 0 || (start + Math.abs(offset)) <= i) { 8540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mFullSpanItems.add(i + offset); 8550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else if (DEBUG) { 8560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Log.d(TAG, "removed full span item " + i); 8570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super.offsetOriginalIndices(start, offset); 8610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 8640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar protected void moveInUIThread(int from, int to) { 8650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean setAsFullSpanAgain = mFullSpanItems.contains(from); 8660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super.moveInUIThread(from, to); 8670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (setAsFullSpanAgain) { 8680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mFullSpanItems.add(to); 8690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Override 8730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 8740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar int position) { 8750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mSizeReference == null) { 8760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSizeReference = mOrientation == OrientationHelper.HORIZONTAL ? mRecyclerViewWidth 8770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar / AVG_ITEM_PER_VIEW : mRecyclerViewHeight / AVG_ITEM_PER_VIEW; 8780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar super.onBindViewHolder(holder, position); 880a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska 8810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar Item item = mItems.get(position); 8820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView 8830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar .getLayoutParams(); 8840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (lp instanceof StaggeredGridLayoutManager.LayoutParams) { 8854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar ((StaggeredGridLayoutManager.LayoutParams) lp) 8864143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar .setFullSpan(mFullSpanItems.contains(item.mAdapterIndex)); 8870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 8884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar StaggeredGridLayoutManager.LayoutParams slp 889a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager 890a810d8b02435915c665ee36128ab21e4f4c76d64Aga Madurska .generateDefaultLayoutParams(); 8910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar holder.itemView.setLayoutParams(slp); 8920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar slp.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex)); 8930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp = slp; 8940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 8950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 8960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOnBindCallback == null || mOnBindCallback.assignRandomSize()) { 8970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final int minSize = mViewsHaveEqualSize ? mSizeReference : 8980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mSizeReference + 20 * (item.mId % 10); 8990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOrientation == OrientationHelper.HORIZONTAL) { 9000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar holder.itemView.setMinimumWidth(minSize); 9010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } else { 9020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar holder.itemView.setMinimumHeight(minSize); 9030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 9040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp.topMargin = 3; 9050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp.leftMargin = 5; 9060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp.rightMargin = 7; 9070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar lp.bottomMargin = 9; 9080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 9090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 9100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar if (mOnBindCallback != null) { 9110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mOnBindCallback.onBoundItem(holder, position); 9120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 9130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 9140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 9150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar} 916