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