RecyclerViewLayoutTest.java revision 3d37afbbf7bf547c1e1c541df9be9696da668884
1d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/* 2d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Copyright (C) 2014 The Android Open Source Project 3d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * 4d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Licensed under the Apache License, Version 2.0 (the "License"); 5d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * you may not use this file except in compliance with the License. 6d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * You may obtain a copy of the License at 7d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * 8d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * http://www.apache.org/licenses/LICENSE-2.0 9d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * 10d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Unless required by applicable law or agreed to in writing, software 11d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * distributed under the License is distributed on an "AS IS" BASIS, 12d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * See the License for the specific language governing permissions and 14d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * limitations under the License. 15d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */ 16d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 17d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 18d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepackage android.support.v7.widget; 19d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.hamcrest.CoreMatchers; 21be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.After; 22be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Before; 23be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Test; 24be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runner.RunWith; 253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.mockito.Mockito; 26be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 27be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport android.support.test.InstrumentationRegistry; 286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyarimport android.graphics.Color; 29ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.graphics.PointF; 30f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyarimport android.graphics.Rect; 31bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.os.SystemClock; 324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.InstrumentationRegistry; 334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 34ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.support.v4.view.ViewCompat; 350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.v7.util.TouchUtils; 36f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest; 37ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.util.Log; 38670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyarimport android.view.Gravity; 39bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.MotionEvent; 405ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyarimport android.view.View; 41bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.ViewConfiguration; 420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.view.ViewGroup; 434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyarimport android.view.ViewTreeObserver; 440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.widget.TextView; 455ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 46e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.ArrayList; 47e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.HashMap; 480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport java.util.List; 49e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.Map; 50ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport java.util.concurrent.CountDownLatch; 51d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit; 52d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicBoolean; 53d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicInteger; 54824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 55e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION; 56bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING; 574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; 58bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING; 59e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.getChildViewHolderInt; 600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*; 613d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport static org.mockito.Mockito.*; 62be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 63be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar@RunWith(AndroidJUnit4.class) 64f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 65d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest { 66cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_HORIZONTAL = 1; 67cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_VERTICAL = 1 << 1; 68cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_FLING = 1 << 2; 69d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 707bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar private static final boolean DEBUG = false; 7122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 72ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar private static final String TAG = "RecyclerViewLayoutTest"; 73ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 7422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public RecyclerViewLayoutTest() { 7522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar super(DEBUG); 7622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 77bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 78be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingFrozen() throws Throwable { 80ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu testScrollFrozen(true); 81ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 82ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 83ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragFrozen() throws Throwable { 85ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu testScrollFrozen(false); 86ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 87ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 883d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Test 893d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void requestRectOnScreenWithScrollOffset() throws Throwable { 903d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 913d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager()); 923d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final int scrollY = 50; 933d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar RecyclerView.Adapter adapter = new RecyclerView.Adapter() { 943d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 953d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 963d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar View view = new View(parent.getContext()); 973d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar view.setScrollY(scrollY); 983d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar return new RecyclerView.ViewHolder(view) { 993d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }; 1003d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 1013d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 1023d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {} 1033d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 1043d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public int getItemCount() { 1053d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar return 1; 1063d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 1073d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }; 1083d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.setAdapter(adapter); 1093d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.setLayoutManager(tlm); 1103d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar tlm.expectLayouts(1); 1113d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar setRecyclerView(recyclerView); 1123d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar tlm.waitForLayout(1); 1133d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final View child = recyclerView.getChildAt(0); 1143d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar assertThat(child.getScrollY(), CoreMatchers.is(scrollY)); 1153d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar runTestOnUiThread(new Runnable() { 1163d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 1173d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void run() { 1183d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true); 1193d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class), 1203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar any(RecyclerView.State.class)); 1213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 1223d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }); 1233d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 1243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar 125ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu private void testScrollFrozen(boolean fling) throws Throwable { 126ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 127ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 128ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int horizontalScrollCount = 3; 129ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int verticalScrollCount = 3; 130ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int horizontalVelocity = 1000; 131ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int verticalVelocity = 1000; 132ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount); 133ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount); 134ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 135ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 136ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 137ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 138ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 139ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 140ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 141ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 142ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 143ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 144ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 145ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 146ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 147ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 148ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 149ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 150ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 151ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 152ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 153ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 154ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (verticalCounter.get() > 0) { 155ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu verticalCounter.decrementAndGet(); 156ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return dy; 157ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 158ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return 0; 159ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 160ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 161ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 162ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 163ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 164ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (horizontalCounter.get() > 0) { 165ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu horizontalCounter.decrementAndGet(); 166ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return dx; 167ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 168ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return 0; 169ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 170ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 171ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 172ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 173ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 174ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 175ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 176ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 177ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 178ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 179ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 180ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (fling) { 181ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity)); 182ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } else { // drag 1830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, 184ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu Gravity.LEFT | Gravity.TOP, 185ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 186ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 187ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount, 188ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu horizontalCounter.get()); 189ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's vertical scroll cb must not run", verticalScrollCount, 190ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu verticalCounter.get()); 191ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 192ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 193ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 194ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (fling) { 195ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity)); 196ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } else { // drag 1970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, 198ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu Gravity.LEFT | Gravity.TOP, 199ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 200ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 201ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get()); 202ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get()); 203ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 204ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 205ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 2067bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar public void testFocusSearchFailFrozen() throws Throwable { 207ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 2087bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar final CountDownLatch focusLatch = new CountDownLatch(1); 209ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 210ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 211ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 212ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 213ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 214ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 215ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 216ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 217ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 218ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 219ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 220ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 221ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 222ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 223ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 224ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 225ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 226ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 227ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 228121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar public View onFocusSearchFailed(View focused, int direction, 229121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state) { 230ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 2317bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar focusLatch.countDown(); 232ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 233ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 234ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 235ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 236ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 237ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 238ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 239ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 240ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 241ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 242ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1); 243ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu runTestOnUiThread(new Runnable() { 244ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 245ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void run() { 246ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu c.requestFocus(); 247ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 248ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }); 249ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue(c.hasFocus()); 250ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 2514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar focusSearch(recyclerView, c, View.FOCUS_DOWN); 252ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("onFocusSearchFailed should not be called when layout is frozen", 253ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 0, focusSearchCalled.get()); 254ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 2554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar focusSearch(recyclerView, c, View.FOCUS_DOWN); 2567bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar assertTrue(focusLatch.await(2, TimeUnit.SECONDS)); 257ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(1, focusSearchCalled.get()); 258ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 259ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 2604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void focusSearch(final ViewGroup parent, final View focused, final int direction) 2614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar throws Throwable { 2624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 2634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 2644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 2654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar parent.focusSearch(focused, direction); 2664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 2674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 2684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 2694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 270ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 2710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void frozenAndChangeAdapter() throws Throwable { 272ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 273ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 274ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 275ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 276ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 277ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 278ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 279ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 280ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 281ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 282ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 283ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 284ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 285ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 286ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 287ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 288ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 289ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 290ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 291ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 292ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 293ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler, 294ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 295ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 296ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 297ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 298ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 299ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 300ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 301ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 302ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 303ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 304ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 305ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 306ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 307ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter2 = new TestAdapter(1000); 308ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setAdapter(adapter2); 309ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 310ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter2, recyclerView.getAdapter()); 311ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 312ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 313ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter3 = new TestAdapter(1000); 314ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu swapAdapter(adapter3, true); 315ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 316ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter3, recyclerView.getAdapter()); 317ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 318ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 319ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 3200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollToPositionCallback() throws Throwable { 3214965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 3224965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3234965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar int scrollPos = RecyclerView.NO_POSITION; 3241a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 3254965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 3264965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3274965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutLatch.countDown(); 3284965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar if (scrollPos == RecyclerView.NO_POSITION) { 3294965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, 0, 10); 3304965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } else { 3314965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, scrollPos, scrollPos + 10); 3324965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 3334965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 3341a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 3354965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 3364965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void scrollToPosition(int position) { 3374965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollPos = position; 3384965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayout(); 3394965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 3404965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }; 3414965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setLayoutManager(tlm); 3424965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestAdapter adapter = new TestAdapter(100); 3434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setAdapter(adapter); 3444965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger rvCounter = new AtomicInteger(0); 3454965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger viewGroupCounter = new AtomicInteger(0); 3464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.getViewTreeObserver().addOnScrollChangedListener( 3474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar new ViewTreeObserver.OnScrollChangedListener() { 3484965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 3494965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrollChanged() { 3504965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.incrementAndGet(); 3514965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 3524965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 3534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 3544965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 3554965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 3564965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar rvCounter.incrementAndGet(); 3574965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar super.onScrolled(recyclerView, dx, dy); 3584965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 3594965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 3604965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 3613f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 3624965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar setRecyclerView(recyclerView); 3634965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 3643f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 3653f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 3663f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 3673f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get()); 3683f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called for initialization", 1, 3694965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.get()); 3704965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 371ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 372ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu scrollToPosition(3); 373ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.assertNoLayout("scrollToPosition should be ignored", 2); 374ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 3754965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollToPosition(3); 3764965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 3773f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called", 2, rvCounter.get()); 3783f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get()); 3794965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 3804965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayoutOnUIThread(recyclerView); 3814965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 3823f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 3833f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 3844965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, rvCounter.get()); 3854965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get()); 3864965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar 3874965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 388670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 389be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 3900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqual() throws Throwable { 391670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, 1000, 1000); 392670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 393670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 394be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 3950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVertical() throws Throwable { 396670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, 1000, 1000); 397670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 398670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 399be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontal() throws Throwable { 401670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, 1000, 1000); 402670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 403670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 404be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnly() throws Throwable { 406670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, 1000, 0); 407670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 408670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 409be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnly() throws Throwable { 411670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, 1000); 412670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 413670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 414be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqualReverse() throws Throwable { 416670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, -1000, -1000); 417670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 418670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 419be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVerticalReverse() throws Throwable { 421670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, -1000, -1000); 422670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 423670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 424be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable { 426670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, -1000, -1000); 427670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 428670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 429be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnlyReverse() throws Throwable { 431670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, -1000, 0); 432670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 433670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 434be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnlyReverse() throws Throwable { 436670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, -1000); 437670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 438670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 439670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount, 440670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar int horizontalVelocity, int verticalVelocity) 441670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar throws Throwable { 442670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 443670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount); 444670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount); 445670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 446670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 447670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 448670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 449670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 450670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 451670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 452670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 453670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 454670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 455670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 456670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 457670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 458670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 459670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 460670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 461670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 462670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 463670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 464670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 465670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (verticalCounter.get() > 0) { 466670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.decrementAndGet(); 467670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dy; 468670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 469670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 470670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 471670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 472670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 473670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 474670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 475670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (horizontalCounter.get() > 0) { 476670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.decrementAndGet(); 477670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dx; 478670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 479670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 480670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 481670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 482670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 483670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 484670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 485670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 486670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 487670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 488670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity)); 489670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0, 490670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.get()); 491670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0, 492670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.get()); 493670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 494670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 495be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 4960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragHorizontal() throws Throwable { 497cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL); 498670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 499670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 500be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 5010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragVertical() throws Throwable { 502cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL); 503670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 504670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 505be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 5060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingHorizontal() throws Throwable { 507cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING); 508670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 509670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 510be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 5110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingVertical() throws Throwable { 512cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING); 513670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 514670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 515f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 5160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVertical() throws Throwable { 517f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes TestedFrameLayout tfl = getActivity().mContainer; 518f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 519f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 520cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 521f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 522f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 523f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 5240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontal() throws Throwable { 525f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes TestedFrameLayout tfl = getActivity().mContainer; 526f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 527f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 528cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 529f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 530670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 531d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 5320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontalCallsStopNestedScroll() throws Throwable { 533d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes TestedFrameLayout tfl = getActivity().mContainer; 534d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 535d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 536d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 537d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 538d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 539d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 540d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 5410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVerticalCallsStopNestedScroll() throws Throwable { 542d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes TestedFrameLayout tfl = getActivity().mContainer; 543d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 544d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 545d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 546d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 547d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 548d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 549cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(int flags) 550f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes throws Throwable { 551364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar scrollInOtherOrientationTest(flags, flags); 552f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 553f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 554cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable { 555670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 556670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false); 557670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledVertical = new AtomicBoolean(false); 558f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 559f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes final TestLayoutManager tlm = new TestLayoutManager() { 560670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 561670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 562cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_HORIZONTAL) != 0; 563670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 564670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 565670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 566670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 567cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_VERTICAL) != 0; 568670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 569670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 570670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 571670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 572670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 573670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 574670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 575670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 576670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 577670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 578670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 579670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledVertical.set(true); 580f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollVerticallyBy(dy, recycler, state); 581670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 582670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 583670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 584670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 585670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 586670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledHorizontal.set(true); 587f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollHorizontallyBy(dx, recycler, state); 588670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 589670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 590670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 591670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 592670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 593670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 594670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 595670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 596cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar if ( (flags & FLAG_FLING) != 0 ) { 597cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar int flingVelocity = (mRecyclerView.getMaxFlingVelocity() + 598cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getMinFlingVelocity()) / 2; 599cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0, 600cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar fling(flingVelocity, flingVelocity)); 601f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } else { // drag 6020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP, 603cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 604670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 605f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount, 606cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get()); 607f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount, 608cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get()); 609670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 610670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 611670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar private boolean fling(final int velocityX, final int velocityY) throws Throwable { 612670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean didStart = new AtomicBoolean(false); 613670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar runTestOnUiThread(new Runnable() { 614670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 615670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void run() { 616670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar boolean result = mRecyclerView.fling(velocityX, velocityY); 617670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar didStart.set(result); 618670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 619670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }); 620670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (!didStart.get()) { 621670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return false; 622670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 623670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar // cannot set scroll listener in case it is subject to some test so instead doing a busy 624670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar // loop until state goes idle 625670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar while (mRecyclerView.getScrollState() != SCROLL_STATE_IDLE) { 626670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar getInstrumentation().waitForIdleSync(); 627670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 628670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 629670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 630670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 631da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar private void assertPendingUpdatesAndLayout(TestLayoutManager testLayoutManager, 632da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final Runnable runnable) throws Throwable { 633da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testLayoutManager.expectLayouts(1); 634da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar runTestOnUiThread(new Runnable() { 635da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 636da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 637da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar runnable.run(); 638da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 639da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 640da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 641da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testLayoutManager.waitForLayout(1); 642da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 643da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 644da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 645da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm, 646da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter adapter, boolean waitForFirstLayout) throws Throwable { 647da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setLayoutManager(tlm); 648da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setAdapter(adapter); 649da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar if (waitForFirstLayout) { 650da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.expectLayouts(1); 651da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 652da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.waitForLayout(1); 653da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } else { 654da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 655da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 656da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 657da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 658be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 6590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void hasPendingUpdatesBeforeFirstLayout() throws Throwable { 660da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 661da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 662da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 663da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 664da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 665da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 666da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 667be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 6680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noPendingUpdatesAfterLayout() throws Throwable { 669da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 670da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 671da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 672da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, true); 673da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 674da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 675da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 676be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 6770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void hasPendingUpdatesWhenAdapterIsChanged() throws Throwable { 678da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 679da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 680da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 681da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 682da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertPendingUpdatesAndLayout(layoutManager, new Runnable() { 683da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 684da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 685da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testAdapter.notifyItemRemoved(1); 686da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 687da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 688da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertPendingUpdatesAndLayout(layoutManager, new Runnable() { 689da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 690da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 691da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testAdapter.notifyItemInserted(2); 692da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 693da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 694da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 695da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertPendingUpdatesAndLayout(layoutManager, new Runnable() { 696da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 697da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 698da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testAdapter.notifyItemMoved(2, 3); 699da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 700da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 701da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 702da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertPendingUpdatesAndLayout(layoutManager, new Runnable() { 703da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 704da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 705da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testAdapter.notifyItemChanged(2); 706da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 707da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 708da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 709da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertPendingUpdatesAndLayout(layoutManager, new Runnable() { 710da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 711da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 712da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar testAdapter.notifyDataSetChanged(); 713da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 714da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 715da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 716da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 717be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 7180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaAdapter() throws Throwable { 719e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(true, false); 720e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 721e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 722be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 7230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaTransientStateCleanup() throws Throwable { 724e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, true); 725e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 726e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 727be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 7280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateDontRecycle() throws Throwable { 729e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, false); 730e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 731e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 732e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState) 733e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar throws Throwable { 734e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> failedToRecycle = new ArrayList<View>(); 735e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> recycled = new ArrayList<View>(); 736e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestAdapter testAdapter = new TestAdapter(10) { 737e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 738e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public boolean onFailedToRecycleView( 739e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestViewHolder holder) { 740e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar failedToRecycle.add(holder.itemView); 741e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (unsetTransientState) { 742e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(holder.itemView, false); 743e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 744e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar return succeed; 745e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 746e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 747e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 748e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 749e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recycled.add(holder.itemView); 750e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar super.onViewRecycled(holder); 751e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 752e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 753e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 754e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 755e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 756e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (getChildCount() == 0) { 757e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar detachAndScrapAttachedViews(recycler); 758e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutRange(recycler, 0, 5); 759e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } else { 760e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar removeAndRecycleAllViews(recycler); 761e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 762e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (layoutLatch != null) { 763e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutLatch.countDown(); 764e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 765e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 766e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 767e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 768e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setAdapter(testAdapter); 769e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setLayoutManager(tlm); 770e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setItemAnimator(null); 771e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setRecyclerView(recyclerView); 772e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar getInstrumentation().waitForIdleSync(); 773e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // make sure we have enough views after this position so that we'll receive the on recycled 774e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // callback 775e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar View view = recyclerView.getChildAt(3);//this has to be greater than def cache size. 776e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(view, true); 777e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.expectLayouts(1); 778e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar requestLayoutOnUIThread(recyclerView); 779e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.waitForLayout(2); 780e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 781e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertTrue(failedToRecycle.contains(view)); 782e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertEquals(succeed || unsetTransientState, recycled.contains(view)); 783e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 784e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 785be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 7860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionInvalidation() throws Throwable { 787e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 788e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestAdapter adapter = new TestAdapter(10); 789e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 790e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 791e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 792e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 793e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutLatch.countDown(); 794e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 795e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }; 796e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setAdapter(adapter); 797e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setLayoutManager(tlm); 798e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.expectLayouts(1); 799e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView); 800e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.waitForLayout(1); 801e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar runTestOnUiThread(new Runnable() { 802e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 803e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void run() { 8041a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 805e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertNotSame("adapter positions should not be undefined", 806e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 807e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 808e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 809e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar adapter.notifyDataSetChanged(); 8101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 811e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertSame("adapter positions should be undefined", 812e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 813e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 814e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 815e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 816e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }); 817e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 818e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 819be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsBasic() throws Throwable { 821115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(null); 822115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 823115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 824be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItems() throws Throwable { 826115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 827115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 828115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 829115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(3, 4); 830115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 831115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 832115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 833115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 834be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItemsBefore() throws Throwable { 836115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 837115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 838115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 839115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(0, 1); 840115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 841115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 842115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 843115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 844be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsBefore() throws Throwable { 846115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 847115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 848115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 849115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(0, 5); 850115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 851115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 852115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 853115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 854be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsInside() throws Throwable { 856115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 857115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 858115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 859115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(3, 2); 860115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 861115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 862115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 863115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 864be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsMoveItems() throws Throwable { 866115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 867115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 868115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 869115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.moveAndNotify(3, 5); 870115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 871115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 872115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 873115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 874be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsNotifyDataSetChanged() throws Throwable { 876115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 877115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 878115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 879115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.clear(); 8801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < 20; i++) { 881115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.add(new Item(i, "added item")); 882115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 883115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.notifyDataSetChanged(); 884115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 885115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 886115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 887115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 888be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable { 890619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final AtomicBoolean failedToRecycle = new AtomicBoolean(false); 891619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 892619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 893619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 894619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 895619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 896619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 897619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 898619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 899619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 900619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 901619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 902619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public boolean onFailedToRecycleView( 903619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestViewHolder holder) { 904619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar failedToRecycle.set(true); 905619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar return false; 906619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 907619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 908619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 909619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 910619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 911619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 912619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 913619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 914619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar runTestOnUiThread(new Runnable() { 915619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 916619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void run() { 917619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar ViewCompat.setHasTransientState(vh.itemView, true); 918619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 919619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 920619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 921619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 922619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 923619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 924619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 925619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 926619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 927619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 928619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 929619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 930619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 931619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 932619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(failedToRecycle.get()); 933619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 934619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 935619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 936619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 937be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable { 939619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 940619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 941619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 942619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 943619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 944619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 945619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 946619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 947619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 948619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10); 949619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 950619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 951619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 952619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 953619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 954619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 955619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 956619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 957619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 958619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 959619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 960619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 961619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 962619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 963619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 964619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 965619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 966619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 967619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 968619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 969619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 970619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 971115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable { 972115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 973115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 974115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 975115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 976115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 977115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutRange(recycler, Math.min(state.getItemCount(), 2) 978115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , Math.min(state.getItemCount(), 7)); 979115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutLatch.countDown(); 980115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 981115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 982115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 983115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 984115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }; 985115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 986115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setLayoutManager(tlm); 987115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setAdapter(testAdapter); 988115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.expectLayouts(1); 989115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar setRecyclerView(recyclerView); 990115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.waitForLayout(1); 991115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar runTestOnUiThread(new Runnable() { 992115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 993115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run() { 994115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 995115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int count = recyclerView.getChildCount(); 996115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar Map<View, Integer> layoutPositions = new HashMap<View, Integer>(); 997115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertTrue("test sanity", count > 0); 9981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < count; i++) { 999115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1000115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view); 1001115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1002115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " + index, vh, 1003115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1004115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("get adapter position should return correct index", index, 1005115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1006115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.put(view, vh.mPosition); 1007115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1008115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (adapterChanges != null) { 1009115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterChanges.run(testAdapter); 1010115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar for (int i = 0; i < count; i++) { 1011115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1012115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView 1013115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar .getChildViewHolder(view); 1014115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1015115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (index >= 0) { 1016115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " 10171a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar + index, vh, 1018115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1019115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1020115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("get adapter position should return correct index", index, 1021115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1022115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("should be able to find view with layout position", 1023115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh, mRecyclerView.findViewHolderForLayoutPosition( 1024115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.get(view))); 1025115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1026115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1027115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1028115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1029115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 1030115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 1031115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1032115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1033115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1034115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar checkForMainThreadException(); 1035e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1036e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1037be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScroll() throws Throwable { 1039bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1040bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1041bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1042bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1043bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1044bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1045bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1046bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1047bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1048bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1049bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1050bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1051bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1052bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1053bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1054bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1055bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1056bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1057bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1058bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1059bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1060bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1061bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1062bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1063bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1064bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1065bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1066bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1067bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1068be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScrollWithStop() throws Throwable { 1070bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1071bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1072bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1073bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1074bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1075bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1076bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1077bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1078bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1079bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1080bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1081bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1082bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1083bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1084bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1085bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1086bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1087bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1088bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1089bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1090bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1091bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1092bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1093bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1094bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1095bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1096bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1097bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1098bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1099bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1100bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1101bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1102bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1103bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1104bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1105bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1106be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFling() throws Throwable { 1108bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1109bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1110bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1111bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1112bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1113bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1114bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1115bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1116bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1117bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1118bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1119bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1120bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1121bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1122bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1123bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1124bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1125bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1126bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1127bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f; 1128bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1129bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1130bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1131bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1132bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1133bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1134bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1135bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1136bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1137bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1138bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1139bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1140be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFlingWithStop() throws Throwable { 1142bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1143bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1144bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1145bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1146bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1147bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1148bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1149bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1150bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1151bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1152bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1153bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1154bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1155bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1156bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1157bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1158bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1159bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1160bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1161bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f; 1162bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1163bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1164bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1165bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1166bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1167bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1168bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1169bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1170bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1171bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1172bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1173bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1174bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1175bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1176bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1177bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1178bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1179bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1180bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1181be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateDrag() throws Throwable { 1183bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1184bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1185bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1186bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1187bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1188bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1189bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1190bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1191bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1192bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1193bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1194bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1195bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1196bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1197bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1198bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar drag(mRecyclerView, 0, 0, 0, 500, 5); 1199bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]); 1200bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1201bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]); 1202bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1203bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1204bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY, 1205bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar int stepCount) throws Throwable { 1206bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long downTime = SystemClock.uptimeMillis(); 1207bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long eventTime = SystemClock.uptimeMillis(); 1208bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1209bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float y = fromY; 1210bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float x = fromX; 1211bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1212bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float yStep = (toY - fromY) / stepCount; 1213bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float xStep = (toX - fromX) / stepCount; 1214bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1215bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent event = MotionEvent.obtain(downTime, eventTime, 1216bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent.ACTION_DOWN, x, y, 0); 1217bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1218bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar for (int i = 0; i < stepCount; ++i) { 1219bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar y += yStep; 1220bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar x += xStep; 1221bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1222bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 1223bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1224bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1225bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1226bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1227bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 1228bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1229bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1230bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1231bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1232bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable { 1233bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1234bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1235bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1236bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar if (view.onInterceptTouchEvent(event)) { 1237bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar view.onTouchEvent(event); 1238bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1239bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1240bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1241bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1242bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1243be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleScrap() throws Throwable { 124566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(false); 124666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeRecyclerView(); 124766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(true); 124866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 124966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 125066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void recycleScrapTest(final boolean useRecycler) throws Throwable { 125166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 125266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 125366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 125466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar @Override 125566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1256e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar ViewInfoStore infoStore = mRecyclerView.mViewInfoStore; 125766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (test.get()) { 125866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar try { 125966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar detachAndScrapAttachedViews(recycler); 126066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) { 126166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 126266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView(recycler.getScrapList().get(i).itemView); 126366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 126466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView(recycler.getScrapList().get(i).itemView, 126566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler); 126666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 126766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 1268e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 1269e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) { 127066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 127166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView( 1272e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView); 127366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 127466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView( 1275e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView, 1276e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar recycler); 127766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 127866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 127966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 128066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("no scrap should be left over", 0, recycler.getScrapCount()); 128166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("pre layout map should be empty", 0, 1282e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPreLayout(infoStore)); 128366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post layout map should be empty", 0, 1284e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPostLayout(infoStore)); 1285e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 128666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post old change map should be empty", 0, 1287e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.size()); 128866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 128966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } catch (Throwable t) { 129066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar postExceptionToInstrumentation(t); 129166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 129266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 129366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 129466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutRange(recycler, 0, 5); 129566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutLatch.countDown(); 129666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar super.onLayoutChildren(recycler, state); 129766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 129866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar }; 129966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 130066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setAdapter(testAdapter); 130166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setLayoutManager(lm); 1302121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true); 130366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 130466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar setRecyclerView(recyclerView); 130566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 130666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar test.set(true); 130766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 130866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar testAdapter.changeAndNotify(3, 1); 130966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 131066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar checkForMainThreadException(); 131166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 131222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 1313be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable { 13155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar accessRecyclerOnOnMeasureTest(true); 13165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 13175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 1318be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable { 13204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar accessRecyclerOnOnMeasureTest(false); 13214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 13224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 13234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Test 13240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable { 1325cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar smoothScrollTest(true); 1326cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar } 1327cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar 1328cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar @Test 13290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItems() throws Throwable { 1330ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar smoothScrollTest(false); 1331ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1332ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1333ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollTest(final boolean removeItem) throws Throwable { 1334ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final LinearSmoothScroller[] lss = new LinearSmoothScroller[1]; 1335ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStart = new CountDownLatch(1); 1336ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStop = new CountDownLatch(1); 1337ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int visibleChildCount = 10; 1338ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 1339ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int start = 0; 1340ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1341ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1342ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1343ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onLayoutChildren(recycler, state); 1344ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutRange(recycler, start, visibleChildCount); 1345ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutLatch.countDown(); 1346ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1347ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1348ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1349ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 1350ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar RecyclerView.State state) { 1351ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar start++; 1352ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 1353ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:" 1354ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar + visibleChildCount); 1355ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1356ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar removeAndRecycleAllViews(recycler); 1357c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar layoutRange(recycler, start, 1358c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar Math.max(state.getItemCount(), start + visibleChildCount)); 1359ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return dy; 1360ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1361ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1362ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1363ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public boolean canScrollVertically() { 1364ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return true; 1365ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1366ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1367ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1368ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 1369ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int position) { 1370ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar LinearSmoothScroller linearSmoothScroller = 1371ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 1372ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1373ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 1374ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return new PointF(0, 1); 1375ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1376ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1377ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1378ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStart() { 1379ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStart(); 1380ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStart.countDown(); 1381ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1382ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1383ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1384ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStop() { 1385ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStop(); 1386ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.countDown(); 1387ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1388ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 1389ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar linearSmoothScroller.setTargetPosition(position); 1390ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lss[0] = linearSmoothScroller; 1391ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar startSmoothScroll(linearSmoothScroller); 1392ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1393ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 1394ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 1395ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 1396ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setLayoutManager(lm); 1397ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setAdapter(testAdapter); 1398ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.expectLayouts(1); 1399ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar setRecyclerView(rv); 1400ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.waitForLayout(1); 1401ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar // regular scroll 1402ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int targetPosition = visibleChildCount * (removeItem ? 30 : 4); 1403ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 1404ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1405ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 1406ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.smoothScrollToPosition(targetPosition); 1407ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1408ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 1409ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 1410ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "scrolling to target position " + targetPosition); 1411ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1412ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS)); 1413ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (removeItem) { 1414ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int newTarget = targetPosition - 10; 1415ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1); 141690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar final CountDownLatch targetCheck = new CountDownLatch(1); 1417ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 1418ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1419ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 1420ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar ViewCompat.postOnAnimationDelayed(rv, new Runnable() { 1421ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 1422ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 1423ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar try { 1424ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertEquals("scroll position should be updated to next available", 1425ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar newTarget, lss[0].getTargetPosition()); 1426ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } catch (Throwable t) { 1427ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar postExceptionToInstrumentation(t); 1428ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 142990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.countDown(); 1430ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 143190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }, 50); 1432ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1433ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 143490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertTrue("target position should be checked on time ", 143590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.await(10, TimeUnit.SECONDS)); 1436ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 1437ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS)); 1438ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 1439ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("should scroll to new target " + newTarget 1440115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , rv.findViewHolderForLayoutPosition(newTarget)); 1441ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 1442ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on stop has been called on time"); 1443ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1444ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } else { 1445ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called eventually", 1446ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.await(30, TimeUnit.SECONDS)); 1447ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("scroll to position should succeed", 1448115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar rv.findViewHolderForLayoutPosition(targetPosition)); 1449ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1450ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 1451ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 1452ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 1453be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void consecutiveSmoothScroll() throws Throwable { 145578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger visibleChildCount = new AtomicInteger(10); 145678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger totalScrolled = new AtomicInteger(0); 145778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 145878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar int start = 0; 145978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 146078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 146178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 146278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar super.onLayoutChildren(recycler, state); 146378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutRange(recycler, start, visibleChildCount.get()); 146478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutLatch.countDown(); 146578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 146678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 146778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 146878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 146978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar RecyclerView.State state) { 147078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar totalScrolled.set(totalScrolled.get() + dy); 147178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return dy; 147278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 147378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 147478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 147578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public boolean canScrollVertically() { 147678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return true; 147778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 147878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }; 147978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 148078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 148178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setLayoutManager(lm); 148278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setAdapter(testAdapter); 148378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.expectLayouts(1); 148478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar setRecyclerView(rv); 148578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.waitForLayout(1); 148678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 148778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 148878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 148978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 2000); 149078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 149178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 149278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(250); 149378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger scrollAmt = new AtomicInteger(); 149478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 149578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 149678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 149778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 149878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar scrollAmt.set(soFar); 149978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 5000 - soFar); 150078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 150178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 15021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar while (rv.getScrollState() != SCROLL_STATE_IDLE) { 150378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(100); 150478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 150578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 150678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar assertEquals("second scroll should be competed properly", 5000, soFar); 150778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 150878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 15095cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations) 15105cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar throws Throwable { 15115cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 15125cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10); 15135cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 15145cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 15155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 15165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onLayoutChildren(recycler, state); 15175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 15185cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 15195cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 15205cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } catch (Throwable t) { 15215cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 15225cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } finally { 15235cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 15245cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15255cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15265cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 15275cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 15285cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 15295cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar int widthSpec, int heightSpec) { 15305cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 15315cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar // make sure we access all views 15325cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar for (int i = 0; i < state.getItemCount(); i++) { 15335cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar View view = recycler.getViewForPosition(i); 15345cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertNotNull(view); 15355cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertEquals(i, getPosition(view)); 15365cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (!state.isPreLayout()) { 15384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(state.toString(), 15394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar expectedOnMeasureStateCount.get(), state.getItemCount()); 15404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 1541824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 15425cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 15435cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15445cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onMeasure(recycler, state, widthSpec, heightSpec); 15455cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15465cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 15475cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 15485cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public boolean supportsPredictiveItemAnimations() { 15495cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar return enablePredictiveAnimations; 15505cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15515cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar }; 15525cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 15535cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 15545cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setAdapter(testAdapter); 15555cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 15565cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 15575cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar setRecyclerView(recyclerView); 15585cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 15595cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 15605cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 15615cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar if (!enablePredictiveAnimations) { 15625cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar expectedOnMeasureStateCount.set(15); 15635cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15645cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar testAdapter.addAndNotify(4, 5); 15655cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 15665cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 15675cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 15685cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 1569be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 15700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setCompatibleAdapter() throws Throwable { 15710b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, true); 15720b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 15730b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, true); 15740b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 15750b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, false); 15760b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 15770b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, false); 15780b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 15790b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 15800b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 15810b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews) 15820b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar throws Throwable { 15830b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 15840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final AtomicInteger recycledViewCount = new AtomicInteger(); 15850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 15860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 15870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 15880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 15890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 15900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 15910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 15920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 15930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 15940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 15950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 15960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 15970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 15980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 15990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 16000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 16010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() { 16020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 16030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onViewRecycled(RecyclerView.ViewHolder holder) { 16040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recycledViewCount.incrementAndGet(); 16050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }); 16070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 16080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 16090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 16100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 16110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 16120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews); 16130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 16140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 16150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar if (removeAndRecycleExistingViews) { 16160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertTrue("Previous views should be recycled", recycledViewCount.get() > 0); 16170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } else { 16180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertEquals("No views should be recycled if adapters are compatible and developer " 16190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar + "did not request a recycle", 0, recycledViewCount.get()); 16200b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16210b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16220b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 1623be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 16240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setIncompatibleAdapter() throws Throwable { 16250b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(true); 16260b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(false); 16270b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 16290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable { 16300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 16310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 16320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 16330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 16340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super.onLayoutChildren(recycler, state); 16350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 16360b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 16370b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 16380b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 16390b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 16400b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 16410b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 16420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16430b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 16450b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 16460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 16470b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 16480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 16490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 16500b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 16510b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 16520b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 16530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 16540b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setAdapter(new TestAdapter2(10)); 16550b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 16560b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 16570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 16580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 1659be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 16600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleIgnored() throws Throwable { 16616e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 16626e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 16636e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 16646e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 16656e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutRange(recycler, 0, 5); 16666e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutLatch.countDown(); 16676e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 16686e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }; 16696e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 16706e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setAdapter(adapter); 16716e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setLayoutManager(lm); 16726e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.expectLayouts(1); 16736e560171b774afafd572b1896becac7b308a92e6Yigit Boyar setRecyclerView(recyclerView); 16746e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.waitForLayout(2); 16756e560171b774afafd572b1896becac7b308a92e6Yigit Boyar runTestOnUiThread(new Runnable() { 16766e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 16776e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void run() { 16786e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child1 = lm.findViewByPosition(0); 16796e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child2 = lm.findViewByPosition(1); 16806e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child1); 16816e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child2); 16826e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 16836e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleAllViews(recyclerView.mRecycler); 16846e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should not be recycled or removed", 2, 16856e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.getChildCount()); 16866e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 16876e560171b774afafd572b1896becac7b308a92e6Yigit Boyar Throwable[] throwables = new Throwable[1]; 16886e560171b774afafd572b1896becac7b308a92e6Yigit Boyar try { 16896e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleView(child1, mRecyclerView.mRecycler); 16906e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } catch (Throwable t) { 16916e560171b774afafd572b1896becac7b308a92e6Yigit Boyar throwables[0] = t; 16926e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 16936e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertTrue("Trying to recycle an ignored view should throw IllegalArgException " 16945cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar , throwables[0] instanceof IllegalArgumentException); 16956e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAllViews(); 16966e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should be removed as well ", 0, lm.getChildCount()); 16976e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 16986e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }); 16996e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 17006e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 1701be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findIgnoredByPosition() throws Throwable { 1703f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 1704f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 1705f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 1706f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1707f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar detachAndScrapAttachedViews(recycler); 1708f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutRange(recycler, 0, 5); 1709f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutLatch.countDown(); 1710f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 1711f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }; 1712f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1713f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setAdapter(adapter); 1714f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setLayoutManager(lm); 1715f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 1716f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar setRecyclerView(recyclerView); 1717f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(2); 1718f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar Thread.sleep(5000); 1719f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final int pos = 1; 1720f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final View[] ignored = new View[1]; 1721f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar runTestOnUiThread(new Runnable() { 1722f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 1723f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void run() { 1724f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View child = lm.findViewByPosition(pos); 1725f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.ignoreView(child); 1726f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar ignored[0] = child; 1727f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 1728f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }); 1729f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("ignored child should not be null", ignored[0]); 1730f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNull("find view by position should not return ignored child", 1731f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.findViewByPosition(pos)); 1732f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 1733f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 1734f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(1); 1735f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertEquals("child count should be ", 6, lm.getChildCount()); 1736f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View replacement = lm.findViewByPosition(pos); 1737f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("re-layout should replace ignored child w/ another one", replacement); 1738f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotSame("replacement should be a different view", replacement, ignored[0]); 1739f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 1740f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar 1741be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateAllDecorOffsets() throws Throwable { 1743bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 1744bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1745bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true); 1746bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setAdapter(adapter); 1747bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(4); 1748bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() { 1749bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 1750bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar TestLayoutManager testLayoutManager = new TestLayoutManager() { 1751bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 1752bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1753bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar try { 1754bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // test 1755824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 1756bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar View child = getChildAt(i); 1757bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 1758bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar child.getLayoutParams(); 1759bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 1760bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets validation for VH should have expected value.", 1761bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 1762bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1763bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) { 1764bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 1765bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar vh.itemView.getLayoutParams(); 1766bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 1767bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets invalidation in cache for VH should have expected " 1768bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar + "value.", 1769bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 1770bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1771bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar detachAndScrapAttachedViews(recycler); 1772bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutRange(recycler, 0, layoutCount.get()); 1773bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } catch (Throwable t) { 1774bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar postExceptionToInstrumentation(t); 1775bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } finally { 1776bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutLatch.countDown(); 1777bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1778bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1779bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1780bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 1781bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public boolean supportsPredictiveItemAnimations() { 1782bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar return false; 1783bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1784bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 1785bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // first layout 1786bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setItemViewCacheSize(5); 1787bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setLayoutManager(testLayoutManager); 1788bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1789e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView, true, false); 1790bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 1791bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1792bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1793bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 1794bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 1795bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1796bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 1797bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1798bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1799bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1800bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/o an item decorator 1801e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 1802bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 1803bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1804bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 1805bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.assertNoLayout("layout should not happen", 2); 1806bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1807bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1808bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // set item decorator, should invalidate 1809bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 1810bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1811bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar addItemDecoration(mRecyclerView, dummyItemDecoration); 1812bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1813bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1814bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1815bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 1816bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 1817bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1818bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 1819bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1820bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1821bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1822bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/ item decorator 1823bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 1824bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 1825bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1826bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 1827bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 1828bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1829bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1830bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // trigger cache. 1831bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(3); 1832bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 1833bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1834bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 1835bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1836bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1837bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size()); 1838bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1839bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(5); 1840bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 1841bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1842bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 1843bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1844bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1845bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1846bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // remove item decorator 1847bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 1848bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 1849bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar removeItemDecoration(mRecyclerView, dummyItemDecoration); 1850bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 1851bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 1852bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1853bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1854bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void addItemDecoration(final RecyclerView recyclerView, final 1855824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 1856bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 1857bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 1858bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 1859bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.addItemDecoration(itemDecoration); 1860bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1861bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 1862bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1863bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1864bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void removeItemDecoration(final RecyclerView recyclerView, final 1865bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 1866bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 1867bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 1868bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 1869bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.removeItemDecoration(itemDecoration); 1870bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1871bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 1872bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1873bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1874bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable { 1875bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 1876bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 1877bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 1878bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.invalidateItemDecorations(); 1879bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1880bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 1881bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 1882bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 1883be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateDecorOffsets() throws Throwable { 1885cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final TestAdapter adapter = new TestAdapter(10); 1886cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.setHasStableIds(true); 1887cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 1888cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setAdapter(adapter); 1889cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1890cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final Map<Long, Boolean> changes = new HashMap<Long, Boolean>(); 1891cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1892cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 1893cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 1894cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1895cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase try { 1896cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (changes.size() > 0) { 1897cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase // test 1898824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 1899cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase View child = getChildAt(i); 1900cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 1901cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase child.getLayoutParams(); 1902cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.ViewHolder vh = lp.mViewHolder; 1903cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (!changes.containsKey(vh.getItemId())) { 1904cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase continue; //nothing to test 1905cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1906cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase assertEquals( 1907cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase "Decord insets validation for VH should have expected value.", 1908cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.get(vh.getItemId()).booleanValue(), 1909cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase lp.mInsetsDirty); 1910cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1911cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1912cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase detachAndScrapAttachedViews(recycler); 1913cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutRange(recycler, 0, state.getItemCount()); 1914cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } catch (Throwable t) { 1915cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase postExceptionToInstrumentation(t); 1916cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } finally { 1917cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutLatch.countDown(); 1918cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1919cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1920cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1921cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 1922cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public boolean supportsPredictiveItemAnimations() { 1923cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase return false; 1924cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1925cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase }; 1926cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setLayoutManager(testLayoutManager); 1927cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 1928cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase setRecyclerView(recyclerView); 1929cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 1930cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int itemAddedTo = 5; 1931cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = 0; i < itemAddedTo; i++) { 1932115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 1933cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1934cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) { 1935115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 1936cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1937cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 1938cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.addAndNotify(5, 1); 1939cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 1940cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 1941cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1942cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.clear(); 1943cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int[] changedItems = new int[]{3, 5, 6}; 1944824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 1945115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 1946cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1947824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < changedItems.length; i++) { 19481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItems[i]).getItemId(), 19491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar true); 1950cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1951cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 1952cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changePositionsAndNotify(changedItems); 1953cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 1954cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 1955cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1956824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 1957115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 1958cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1959cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 1960cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 1961cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 1962cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 1963cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 1964cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 1965be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 19660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void movingViaStableIds() throws Throwable { 1967c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(true); 1968c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 1969c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(false); 1970c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 1971c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 1972c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 1973c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable { 1974c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1975c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.setHasStableIds(true); 1976c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 1977c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewFromIndex = 3; 1978c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewToIndex = 6; 1979c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final View[] movedView = new View[1]; 1980c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 1981c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 1982c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1983c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar detachAndScrapAttachedViews(recycler); 1984c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar try { 1985c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (test.get()) { 1986c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (state.isPreLayout()) { 1987c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewFromIndex, true); 1988c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In pre layout, should be able to get moved view w/ old " 1989c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 1990c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 1991c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 1992c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 1993c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 1994c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } else { 1995c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewToIndex, true); 1996c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In post layout, should be able to get moved view w/ new " 1997c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 1998c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 1999c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 2000c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 2001c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 2002c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2003c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2004c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 2005c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } catch (Throwable t) { 2006c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar postExceptionToInstrumentation(t); 2007c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } finally { 2008c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutLatch.countDown(); 2009c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2010c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2011c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2012c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2013c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2014c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2015c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public boolean supportsPredictiveItemAnimations() { 2016c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar return supportsPredictive; 2017c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2018c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }; 2019c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView recyclerView = new RecyclerView(this.getActivity()); 2020c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setAdapter(testAdapter); 2021c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setLayoutManager(lm); 2022c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(1); 2023c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar setRecyclerView(recyclerView); 2024c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(1); 2025c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2026c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar movedView[0] = recyclerView.getChildAt(movedViewFromIndex); 2027c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar test.set(true); 2028c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(supportsPredictive ? 2 : 1); 2029c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar runTestOnUiThread(new Runnable() { 2030c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2031c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void run() { 2032c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar Item item = testAdapter.mItems.remove(movedViewFromIndex); 2033c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.mItems.add(movedViewToIndex, item); 2034c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemRemoved(movedViewFromIndex); 2035c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemInserted(movedViewToIndex); 2036c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2037c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }); 2038c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(2); 2039c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar checkForMainThreadException(); 2040c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2041cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2042be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 20430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringLayout() throws Throwable { 20440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() { 20450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 20460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 20470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 20480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 20500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 20510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() { 20520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 20530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 20540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 20550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 20570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 20580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() { 20590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 20600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 20610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 20620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 20640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() { 20650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 20660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 20670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 20680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 20700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 20720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeInMainThreadTest(String msg, 20730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onLayoutRunnable) throws Throwable { 20740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final AtomicBoolean doneFirstLayout = new AtomicBoolean(false); 20750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 20760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 20770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 20780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 20790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 20800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 20810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 20820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (doneFirstLayout.get()) { 20830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onLayoutRunnable.run(); 20840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 20860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 20870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 20880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 20890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 20910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 20920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 20930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 20940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 20950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 20960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 20970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 20980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 20990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar doneFirstLayout.set(true); 21000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 21010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar requestLayoutOnUIThread(recyclerView); 21020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 21030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 21040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 21050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mainThreadException instanceof IllegalStateException); 21066b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar mainThreadException = null; 21070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2109be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 21100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScroll() throws Throwable { 21110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int orientation : new int[]{OrientationHelper.HORIZONTAL, 21120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar OrientationHelper.VERTICAL}) { 21130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyDataSetChanged", orientation, 21140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar new Runnable() { 21150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 21170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 21180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 21200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() { 21210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 21230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 21240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 21260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() { 21280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 21300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 21310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 21330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() { 21340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 21360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 21370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 21390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeDuringScrollTest(String msg, final int orientation, 21430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onScrollRunnable) throws Throwable { 21440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(100); 21450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 21460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 21480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 21490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 21500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, 10); 21510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 21520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 21530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 21540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 21550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollVertically() { 21600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.VERTICAL; 21610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollHorizontally() { 21650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.HORIZONTAL; 21660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int mockScroll() { 21690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 21700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onScrollRunnable.run(); 21710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 21720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 21730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 21740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 21750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return 0; 21770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 21810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 21820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 21830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 21850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 21860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 21870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 21880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 21890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 21900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 21910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 21920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 21930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 21940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 21950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 21960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 21970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 21980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar scrollBy(200); 21990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 22000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 22010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 22020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mainThreadException instanceof IllegalStateException); 22036b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar mainThreadException = null; 22040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 22050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2206be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 22070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleOnDetach() throws Throwable { 220849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 220949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 221049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final AtomicBoolean didRunOnDetach = new AtomicBoolean(false); 221149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 221249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 221349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 221449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onLayoutChildren(recycler, state); 221549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutRange(recycler, 0, state.getItemCount() - 1); 221649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutLatch.countDown(); 221749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 221849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 221949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 222049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 222149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onDetachedFromWindow(view, recycler); 222249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar didRunOnDetach.set(true); 222349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeAndRecycleAllViews(recycler); 222449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 222549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar }; 222649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setAdapter(testAdapter); 222749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setLayoutManager(lm); 222849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.expectLayouts(1); 222949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar setRecyclerView(recyclerView); 223049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.waitForLayout(2); 223149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeRecyclerView(); 223249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get()); 223349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertEquals("All children should be recycled", recyclerView.getChildCount(), 0); 223449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 22350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2236be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 22370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesWhileDetached() throws Throwable { 2238bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2239bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 2240bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 2241bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 2242bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2243bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2244bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2245bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 2246bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 2247bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 2248bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 2249bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2250bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 2251bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 2252bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 2253bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 2254bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2255bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 2256bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 2257bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2258bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 2259be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 22600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesAfterDetach() throws Throwable { 2261bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2262bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 2263bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 2264bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 2265bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2266bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2267bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2268bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 2269bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 2270bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 2271bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 2272bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2273bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 2274bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 2275bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 2276bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2277bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 2278bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar setRecyclerView(recyclerView); 2279bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.waitForLayout(2); 2280bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2281bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int prevLayoutCount = layoutCount.get(); 2282bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar runTestOnUiThread(new Runnable() { 2283bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2284bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void run() { 2285bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar try { 2286bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 2287bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar removeRecyclerView(); 2288bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } catch (Throwable throwable) { 228990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar postExceptionToInstrumentation(throwable); 2290bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2291bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2292bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }); 229390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 2294bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 2295bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 2296bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar assertEquals("No extra layout should happen when detached", prevLayoutCount, 2297bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.get()); 2298bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 229949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 2300be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedWithStableIds() throws Throwable { 2302e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int defaultViewType = 1; 2303e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Item, Integer> viewTypeMap = new HashMap<Item, Integer>(); 2304e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Integer, Integer> oldPositionToNewPositionMapping = 2305e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new HashMap<Integer, Integer>(); 2306e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 2307e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2308e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public int getItemViewType(int position) { 2309e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Integer type = viewTypeMap.get(mItems.get(position)); 2310e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return type == null ? defaultViewType : type; 2311e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2312e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 2313e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2314e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 2315e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 2316e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2317e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 2318e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 2319e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final ArrayList<Item> previousItems = new ArrayList<Item>(); 2320e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar previousItems.addAll(adapter.mItems); 2321e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 2322e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicInteger layoutStart = new AtomicInteger(50); 2323e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicBoolean validate = new AtomicBoolean(false); 2324e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int childCount = 10; 2325e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 2326e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2327e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2328e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 2329e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar super.onLayoutChildren(recycler, state); 2330e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 2331e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("Cached views should be kept", 5, recycler 2332e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .mCachedViews.size()); 2333e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.mCachedViews) { 2334e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 23350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 23360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 2337e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 2338e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2339e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2340e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar detachAndScrapAttachedViews(recycler); 2341e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 2342e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("cache size should stay the same", 5, 2343e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.mCachedViews.size()); 2344e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("all views should be scrapped", childCount, 2345e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.getScrapList().size()); 2346e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.getScrapList()) { 2347e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // TODO create test case for type change 2348e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 23490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 23500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 2351e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 2352e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2353e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2354e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 2355e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 2356e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < getChildCount(); i++) { 2357e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = getChildAt(i); 2358e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) mRecyclerView 2359e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .getChildViewHolder(view); 2360115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int oldPos = previousItems.indexOf(tvh.mBoundItem); 2361e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("view holder's position should be correct", 2362e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.get(oldPos).intValue(), 2363115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tvh.getLayoutPosition()); 23640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar ; 23650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 2366e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2367e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable t) { 2368e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(t); 2369e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } finally { 2370e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutLatch.countDown(); 2371e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2372e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2373e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 2374e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2375e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemAnimator(null); 2376e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setAdapter(adapter); 2377e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setLayoutManager(lm); 2378e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemViewCacheSize(10); 2379e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 2380e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setRecyclerView(recyclerView); 2381e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 2382e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 2383e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar getInstrumentation().waitForIdleSync(); 2384e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutStart.set(layoutStart.get() + 5);//55 2385e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 2386e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar requestLayoutOnUIThread(recyclerView); 2387e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 2388e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar validate.set(true); 2389e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 2390e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar runTestOnUiThread(new Runnable() { 2391e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2392e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void run() { 2393e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 2394e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.moveItems(false, 2395e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2}, 2396e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64}, 2397e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{75, 58}); 2398e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < previousItems.size(); i++) { 2399e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item = previousItems.get(i); 2400e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item)); 2401e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2402cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 2403e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable throwable) { 2404e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(throwable); 2405e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2406e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2407e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }); 2408e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 2409e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 2410e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2411e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 2412be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSwap() throws Throwable { 2414824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(true); 2415824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2416824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2417be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSet() throws Throwable { 2419824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(false); 2420824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2421824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2422824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void callbacksDuringAdapterChange(boolean swap) throws Throwable { 2423824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter() 2424824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 2425824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter() 2426824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 2427824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2428824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 2429824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2430824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2431824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar try { 2432824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 2433824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 2434824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar postExceptionToInstrumentation(t); 2435824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2436824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutLatch.countDown(); 2437824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2438824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 2439824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 2440824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setAdapter(adapter1); 2441824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setLayoutManager(tlm); 2442824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 2443824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setRecyclerView(rv); 2444824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 2445824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 2446824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 2447824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar if (swap) { 2448824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar swapAdapter(adapter2, true); 2449824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } else { 2450824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setAdapter(adapter2); 2451824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2452824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 2453824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 2454824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 2455824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2456824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2457824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createOwnerCheckingAdapter() { 2458824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 2459824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2460824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 2461824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 2462824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 2463824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 2464824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2465824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2466824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2467824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 2468824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 2469824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on bind should be called w/ the creator adapter", this, holder.mData); 2470824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2471824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2472824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2473824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 2474824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar int viewType) { 2475824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType); 2476824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar vh.mData = this; 2477824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return vh; 2478824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2479824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 2480824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2481824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2482824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createBinderCheckingAdapter() { 2483824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 2484824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2485824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 2486824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 2487824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 2488824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = null; 2489824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 2490824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2491824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2492824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 2493824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 2494824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 2495824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = this; 2496824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2497824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 2498824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 2499824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 2500be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 25010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findViewById() throws Throwable { 25025ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(false); 25035ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar removeRecyclerView(); 25045ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(true); 25055ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25065ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 25075ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void findViewByIdTest(final boolean supportPredictive) throws Throwable { 25085ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 25095ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int initialAdapterSize = 20; 25105ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 25115ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteStart = 6; 25125ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteCount = 5; 25135ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setAdapter(adapter); 25145ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final AtomicBoolean assertPositions = new AtomicBoolean(false); 25155ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 25165ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 25175ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 25185ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar super.onLayoutChildren(recycler, state); 25195ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (assertPositions.get()) { 25205ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (state.isPreLayout()) { 25210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteStart; i++) { 25225ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 25235ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position for existing items should work " 25245ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "fine", view); 25255ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 25265ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 25275ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 25285ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteCount; i++) { 25305ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i + deleteStart); 25315ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position should work fine for removed " 25325ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "views in pre-layout", view); 25335ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertTrue("view should be marked as removed", 25345ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 25355ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 25365ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25375ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar for (int i = deleteStart + deleteCount; i < 20; i++) { 25385ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 25395ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull(view); 25405ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 25415ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 25425ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 25435ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25445ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } else { 25450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < initialAdapterSize - deleteCount; i++) { 25465ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 2547fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar assertNotNull("find view by position for existing item " + i + 2548fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar " should work fine. child count:" + getChildCount(), view); 25495ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestViewHolder viewHolder = 25505ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar (TestViewHolder) mRecyclerView.getChildViewHolder(view); 25515ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertSame("should be the correct item " + viewHolder 2552115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , viewHolder.mBoundItem, 25535ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.mItems.get(viewHolder.mPosition)); 25545ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 25555ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 25565ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 25575ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25585ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25595ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25605ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar detachAndScrapAttachedViews(recycler); 25615ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutRange(recycler, state.getItemCount() - 1, -1); 25625ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutLatch.countDown(); 25635ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25645ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 25655ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 25665ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public boolean supportsPredictiveItemAnimations() { 25675ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar return supportPredictive; 25685ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25695ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar }; 25705ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setLayoutManager(lm); 25715ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(1); 25725ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar setRecyclerView(recyclerView); 25735ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 25745ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar getInstrumentation().waitForIdleSync(); 25755ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 25765ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertPositions.set(true); 25775ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(supportPredictive ? 2 : 1); 25785ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1}); 25795ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 25805ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 25815ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 2582be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 25830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForCache() throws Throwable { 258422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 258522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestAdapter adapter = new TestAdapter(100) { 258622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 258722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public int getItemViewType(int position) { 258822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return viewType.get(); 258922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 259022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 259122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 259222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public long getItemId(int position) { 259322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return mItems.get(position).mId; 259422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 259522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 259622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.setHasStableIds(true); 259722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger layoutStart = new AtomicInteger(2); 259822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final int childCount = 10; 259922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 260022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 260122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 260222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar super.onLayoutChildren(recycler, state); 260322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar detachAndScrapAttachedViews(recycler); 260422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 260522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutLatch.countDown(); 260622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 260722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 260822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2609668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar recyclerView.setItemAnimator(null); 261022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setAdapter(adapter); 261122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setLayoutManager(lm); 261222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setItemViewCacheSize(10); 261322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 261422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar setRecyclerView(recyclerView); 261522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 261622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar getInstrumentation().waitForIdleSync(); 261722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(4); // trigger a cache for 3,4 261822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 261922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar requestLayoutOnUIThread(recyclerView); 262022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 262122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar // 262222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar viewType.incrementAndGet(); 262322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(2); // go back to bring views from cache 262422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 262522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.mItems.remove(1); 2626cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 262722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 262822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar runTestOnUiThread(new Runnable() { 262922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 263022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void run() { 263122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar for (int i = 2; i < 4; i++) { 2632115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i); 263322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar assertEquals("View holder's type should match latest type", viewType.get(), 263422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar vh.getItemViewType()); 263522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 263622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 263722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }); 263822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 263922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 2640be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 26410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForExistingViews() throws Throwable { 26427e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 26437e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int invalidatedCount = 2; 26447e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int layoutStart = 2; 26457e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 26467e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 26477e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public int getItemViewType(int position) { 26487e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return viewType.get(); 26497e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26507e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 26517e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 26527e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 26537e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar int position) { 26547e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onBindViewHolder(holder, position); 26557e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar if (position >= layoutStart && position < invalidatedCount + layoutStart) { 26567e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar try { 26577e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar assertEquals("holder type should match current view type at position " + 26587e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar position, viewType.get(), holder.getItemViewType()); 26597e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } catch (Throwable t) { 26607e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar postExceptionToInstrumentation(t); 26617e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26627e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26637e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26647e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 26657e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 26667e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public long getItemId(int position) { 26677e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return mItems.get(position).mId; 26687e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26697e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 26707e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar adapter.setHasStableIds(true); 26717e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 26727e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int childCount = 10; 26737e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 26747e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 26757e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 26767e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onLayoutChildren(recycler, state); 26777e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar detachAndScrapAttachedViews(recycler); 26787e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutRange(recycler, layoutStart, layoutStart + childCount); 26797e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutLatch.countDown(); 26807e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26817e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 26827e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 26837e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setAdapter(adapter); 26847e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setLayoutManager(lm); 26857e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 26867e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar setRecyclerView(recyclerView); 26877e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 26887e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar getInstrumentation().waitForIdleSync(); 26897e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar viewType.incrementAndGet(); 26907e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 2691cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changeAndNotify(layoutStart, invalidatedCount); 26927e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 26937e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar checkForMainThreadException(); 26947e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 26957e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 26967e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 2697be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 26980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void state() throws Throwable { 2699d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final TestAdapter adapter = new TestAdapter(10); 2700d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 2701d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setAdapter(adapter); 2702d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setItemAnimator(null); 2703d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicInteger itemCount = new AtomicInteger(); 2704d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicBoolean structureChanged = new AtomicBoolean(); 2705d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 2706d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 2707d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 27088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar detachAndScrapAttachedViews(recycler); 2709d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutRange(recycler, 0, state.getItemCount()); 2710d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.set(state.getItemCount()); 2711d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.set(state.didStructureChange()); 2712d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutLatch.countDown(); 2713d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 2714d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }; 2715d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setLayoutManager(testLayoutManager); 2716d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 2717d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 2718d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 2719d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 2720d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase getActivity().mContainer.addView(recyclerView); 2721d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 2722d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 2723d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.waitForLayout(2, TimeUnit.SECONDS); 2724d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 2725d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("item count in state should be correct", adapter.getItemCount() 2726d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase , itemCount.get()); 2727d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true for first layout", true, 2728d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 2729d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase Thread.sleep(1000); //wait for other layouts. 2730d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 2731d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 2732d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 2733d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 2734d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.requestLayout(); 2735d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 2736d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 27378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 2738d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("in second layout,structure changed should be false", false, 2739d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 27408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); // 2741b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.deleteAndNotify(3, 2); 27428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 2743d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are removed, item count in state should be updated", 2744d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 2745d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 2746d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 2747d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 27488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); 2749b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.addAndNotify(2, 5); 27508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 2751d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 2752d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are added, item count in state should be updated", 2753d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 2754d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 2755d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 2756d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 27570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 27580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 2759be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 27600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachWithoutLayoutManager() throws Throwable { 2761abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2762abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar runTestOnUiThread(new Runnable() { 2763abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar @Override 2764abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar public void run() { 2765abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar try { 2766abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar setRecyclerView(recyclerView); 2767abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar removeRecyclerView(); 2768abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } catch (Throwable t) { 2769abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar postExceptionToInstrumentation(t); 2770abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 2771abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 2772abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar }); 2773abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar checkForMainThreadException(); 2774abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 2775abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 2776be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 27770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updateHiddenView() throws Throwable { 27781a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final RecyclerView.ViewHolder[] mTargetVH = new RecyclerView.ViewHolder[1]; 27791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 27801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] preLayoutRange = new int[]{0, 10}; 27811a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] postLayoutRange = new int[]{0, 10}; 27821a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final AtomicBoolean enableGetViewTest = new AtomicBoolean(false); 27831a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final List<Integer> disappearingPositions = new ArrayList<Integer>(); 27841a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 27851a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 27861a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public boolean supportsPredictiveItemAnimations() { 27871a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar return true; 27881a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 27891a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 27901a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 27911a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 27921a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 27931a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] layoutRange = state.isPreLayout() ? preLayoutRange 27941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar : postLayoutRange; 27951a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar detachAndScrapAttachedViews(recycler); 27961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutRange(recycler, layoutRange[0], layoutRange[1]); 27971a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar if (!state.isPreLayout()) { 27981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (Integer position : disappearingPositions) { 27991a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // test sanity. 28001a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar assertNull(findViewByPosition(position)); 28011a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final View view = recycler.getViewForPosition(position); 28021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar addDisappearingView(view); 28031a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar measureChildWithMargins(view, 0, 0); 28041a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // position item out of bounds. 28051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar view.layout(0, -500, view.getMeasuredWidth(), 28061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar -500 + view.getMeasuredHeight()); 28071a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28081a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28091a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable t) { 28101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postExceptionToInstrumentation(t); 28111a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28121a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutLatch.countDown(); 28131a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28141a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }; 28151a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 28161a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.getItemAnimator().setMoveDuration(2000); 28171a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.getItemAnimator().setRemoveDuration(2000); 28181a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestAdapter adapter = new TestAdapter(100); 28191a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setAdapter(adapter); 28201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setLayoutManager(tlm); 28211a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(1); 28221a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar setRecyclerView(recyclerView); 28231a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 28241a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(1); 28251a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 28261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar mTargetVH[0] = recyclerView.findViewHolderForAdapterPosition(0); 28271a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now, a child disappears 28281a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.add(0); 28291a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // layout one shifted 28301a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[0] = 1; 28311a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[1] = 11; 28321a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 28331a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.addAndNotify(8, 1); 28341a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 28351a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 28361a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 28371a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 28381a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.clear(); 28391a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now that item should be moving, invalidate it and delete it. 28401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar enableGetViewTest.set(true); 28411a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar runTestOnUiThread(new Runnable() { 28421a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 28431a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void run() { 28441a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 28451a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.changeAndNotify(0, 1); 28461a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.deleteAndNotify(0, 1); 28471a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable throwable) { 28481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar throwable.printStackTrace(); 28491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28501a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28511a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }); 28521a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 28531a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 28541a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 28551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 2856be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnTop() throws Throwable { 28586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.TOP); 28596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2861be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeft() throws Throwable { 28636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT); 28646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2866be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRight() throws Throwable { 28686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT); 28696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2871be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnBottom() throws Throwable { 28736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.BOTTOM); 28746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2876be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeftRTL() throws Throwable { 28786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT, true); 28796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 28806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 28816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2883be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRightRTL() throws Throwable { 28856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT, true); 28866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 28876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 28886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 28906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity) throws Throwable { 28916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(gravity, false); 28926d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 2893be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 28946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable { 28956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 28966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 28976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL); 28986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 28996d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vScrollDist = new AtomicInteger(0); 29006d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hScrollDist = new AtomicInteger(0); 29016d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vDesiredDist = new AtomicInteger(0); 29026d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hDesiredDist = new AtomicInteger(0); 29036d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 29046d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29056d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29066d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int getLayoutDirection() { 29076d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR; 29086d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29096d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29106d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29116d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 29126d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar detachAndScrapAttachedViews(recycler); 29136d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final View view = recycler.getViewForPosition(0); 29146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar addView(view); 29156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar int left = 0, top = 0; 29166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.setBackgroundColor(Color.rgb(0, 0, 255)); 29176d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar switch (gravity) { 29186d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.LEFT: 29196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.RIGHT: 29206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 29216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5), 29226d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY), 29236d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9), 29246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST)); 29256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80 29266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar : 90; 29276d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = 0; 29286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) { 29296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth()); 29306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 29316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set(left); 29326d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29336d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 29346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.TOP: 29356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.BOTTOM: 29366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 29376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9), 29386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST), 29396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5), 29406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY)); 29416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() - 29426d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 80 : 90; 29436d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = 0; 29446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vDesiredDist.set(top); 29456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 29466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29486d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.layout(left, top, left + view.getMeasuredWidth(), 29496d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top + view.getMeasuredHeight()); 29506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar layoutLatch.countDown(); 29516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollVertically() { 29556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return true; 29566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollHorizontally() { 29606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return super.canScrollHorizontally(); 29616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29626d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 29656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 29666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vScrollDist.addAndGet(dy); 29676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetTopAndBottom(-dy); 29686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dy; 29696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 29716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 29726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 29736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 29746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hScrollDist.addAndGet(dx); 29756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetLeftAndRight(-dx); 29766d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dx; 29776d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar }; 29796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestAdapter adapter = new TestAdapter(10); 29806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setAdapter(adapter); 29816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setLayoutManager(tlm); 29826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.expectLayouts(1); 29836d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar setRecyclerView(rv); 29846d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.waitForLayout(2); 29856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View view = rv.getChildAt(0); 29866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar requestFocus(view); 29876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar Thread.sleep(1000); 29886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(vDesiredDist.get(), vScrollDist.get()); 29896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(hDesiredDist.get(), hScrollDist.get()); 29906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingTop(), view.getTop()); 29916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 2992be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), 2993be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar view.getRight()); 29946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 29956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft()); 29966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 29986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 2999be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void firstLayoutWithAdapterChanges() throws Throwable { 30014bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final TestAdapter adapter = new TestAdapter(0); 30024bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 30034bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setVisibility(rv, View.GONE); 30044bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 30054bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 30064bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 30074bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 30084bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar super.onLayoutChildren(recycler, state); 30094bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 30104bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable t) { 30114bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar postExceptionToInstrumentation(t); 30124bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } finally { 30134bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutLatch.countDown(); 30144bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30154bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30164bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 30174bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 30184bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public boolean supportsPredictiveItemAnimations() { 30194bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar return true; 30204bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30214bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }; 30224bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setLayoutManager(tlm); 30234bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setAdapter(adapter); 30244bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setHasFixedSize(true); 30254bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setRecyclerView(rv); 30264bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.expectLayouts(1); 30274bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.assertNoLayout("test sanity, layout should not run", 1); 30284bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar getInstrumentation().waitForIdleSync(); 30294bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar runTestOnUiThread(new Runnable() { 30304bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 30314bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void run() { 30324bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 30334bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar adapter.addAndNotify(2); 30344bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable throwable) { 30354bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar throwable.printStackTrace(); 30364bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30374bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setVisibility(View.VISIBLE); 30384bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30394bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }); 30404bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 30414bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.waitForLayout(2); 30424bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar assertEquals(2, rv.getChildCount()); 30434bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 30444bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 30454bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 30464bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Test 304714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutLayoutManager() throws Throwable { 304814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 304914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setAdapter(new TestAdapter(10)); 305014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 305114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 305214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 305314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 305414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 305514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 305614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 305714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 305814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 305914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 306014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 306114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutAdapter() throws Throwable { 306214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 306314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setLayoutManager(new TestLayoutManager()); 306414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 306514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 306614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 306714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 306814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 306914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 307014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 307114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 307214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 307314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 307414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 30750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithDecorOffsets() throws Throwable { 3076f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(true); 3077f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3078f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3079be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithout() throws Throwable { 3081f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(false); 3082f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3083f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3084f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable { 3085f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3086f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final AtomicInteger scrollDist = new AtomicInteger(0); 3087f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3088f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3089f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3090f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar detachAndScrapAttachedViews(recycler); 3091f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final View view = recycler.getViewForPosition(0); 3092f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar addView(view); 3093f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar measureChildWithMargins(view, 0, 0); 3094f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar view.layout(0, -20, view.getWidth(), 3095f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar -20 + view.getHeight());// ignore decors on purpose 3096f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar layoutLatch.countDown(); 3097f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3098f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3099f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3100f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public boolean canScrollVertically() { 3101f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return true; 3102f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3103f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3104f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3105f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 3106f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3107f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar scrollDist.addAndGet(dy); 3108f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return dy; 3109f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3110f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }; 3111f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestAdapter adapter = new TestAdapter(10); 3112f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar if (addItemDecors) { 3113f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.addItemDecoration(new RecyclerView.ItemDecoration() { 3114f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3115f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 3116f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3117f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar outRect.set(0, 10, 0, 10); 3118f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3119f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }); 3120f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3121f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setAdapter(adapter); 3122f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setLayoutManager(tlm); 3123f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.expectLayouts(1); 3124f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar setRecyclerView(rv); 3125f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.waitForLayout(2); 3126f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3127f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar View view = rv.getChildAt(0); 3128f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar requestFocus(view); 3129f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar Thread.sleep(1000); 3130f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar assertEquals(addItemDecors ? -30 : -20, scrollDist.get()); 3131f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3132f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3133e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 31340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void unimplementedSmoothScroll() throws Throwable { 3135e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1); 3136e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1); 3137e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final CountDownLatch cbLatch = new CountDownLatch(2); 3138e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3139e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3140e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3141e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 3142e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, 0, 10); 3143e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 3144e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3145e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3146e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3147e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 3148e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int position) { 3149e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedSmoothScrollToPosition.get()); 3150e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedSmoothScrollToPosition.set(position); 3151e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 3152e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 3153e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3154e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 3155e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return null; 3156e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3157e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3158e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 3159e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 3160e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3161e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3162e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3163e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3164e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 3165e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedScrollToPosition.get()); 3166e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPosition.set(position); 3167e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3168e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3169e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3170e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3171e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(new TestAdapter(100)); 3172e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 3173e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 3174e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 3175e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 3176ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 3177ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu smoothScrollToPosition(35); 3178ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("smoothScrollToPosition should be ignored when frozen", 3179ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu -1, receivedSmoothScrollToPosition.get()); 3180ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 3181e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar smoothScrollToPosition(35); 3182e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS)); 3183e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3184e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedSmoothScrollToPosition.get()); 3185e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedScrollToPosition.get()); 3186e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3187e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3188e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 31890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScroller() throws Throwable { 3190e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(true); 3191e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3192e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3193e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 31940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScrollerGoesIdle() throws Throwable { 3195e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(false); 3196e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3197e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3198e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable { 3199e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final List<Integer> receivedScrollToPositions = new ArrayList<>(); 3200e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final TestAdapter testAdapter = new TestAdapter(200); 3201e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicBoolean mTargetFound = new AtomicBoolean(false); 3202e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3203e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int pendingScrollPosition = -1; 3204e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3205e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3206e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 3207e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition; 3208e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, pos, pos + 10); 3209e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (layoutLatch != null) { 3210e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 3211e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3212e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3213e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3214e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3215e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 3216e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int position) { 3217e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 3218e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 3219e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3220e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 3221e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return new PointF(0, 1); 3222e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3223e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3224e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3225e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void onTargetFound(View targetView, RecyclerView.State state, 3226e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Action action) { 3227e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar super.onTargetFound(targetView, state, action); 3228e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar mTargetFound.set(true); 3229e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3230e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3231e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3232e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void updateActionForInterimTarget(Action action) { 3233e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = succeed ? getTargetPosition() : 100; 3234e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition + 2 < limit) { 3235e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition != NO_POSITION) { 3236e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(pendingScrollPosition, 3237e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar getChildViewHolderInt(getChildAt(0)) 3238e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar .getAdapterPosition()); 3239e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3240e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar action.jumpTo(pendingScrollPosition + 2); 3241e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3242e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3243e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3244e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 3245e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 3246e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3247e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3248e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3249e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 3250e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPositions.add(position); 3251e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar pendingScrollPosition = position; 3252e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar requestLayout(); 3253e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3254e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3255e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 3256e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(testAdapter); 3257e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 3258e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3259e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 3260e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 3261e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 3262e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3263e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar runTestOnUiThread(new Runnable() { 3264e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3265e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void run() { 3266e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.smoothScrollToPosition(150); 3267e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3268e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }); 3269e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = 100; 3270e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) { 3271e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Thread.sleep(200); 3272e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3273e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3274e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3275e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue(limit > 0); 3276e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar for (int i = 1; i < 100; i+=2) { 3277e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i)); 3278e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3279e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3280e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(succeed, mTargetFound.get()); 3281e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3282e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3283e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 32840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestViewHolder2 extends RecyclerView.ViewHolder { 3285824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3286824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar Object mData; 3287824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 32880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2(View itemView) { 32890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super(itemView); 32900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 32910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 3292d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 32930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> { 3294824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 32950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar List<Item> mItems; 32960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 32970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private TestAdapter2(int count) { 32980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems = new ArrayList<Item>(count); 32990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar for (int i = 0; i < count; i++) { 33000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems.add(new Item(i, "Item " + i)); 33010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 33020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 33030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 33040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 33050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 33060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar int viewType) { 33070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return new TestViewHolder2(new TextView(parent.getContext())); 33080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 33090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 33100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 33110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 33120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final Item item = mItems.get(position); 33130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")"); 33140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 33150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 33160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 33170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public int getItemCount() { 33180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return mItems.size(); 33190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 3320d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3321d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 3322115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar private static interface AdapterRunnable { 33231a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 33243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar void run(TestAdapter adapter) throws Throwable; 3325115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 3326115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 33273d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public class LayoutAllLayoutManager extends TestLayoutManager { 33283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 33293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 33303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 33313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutLatch.countDown(); 33323d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 33333d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 33347a59e4b36500bcfddd842376d6c3abe0d9f23d84Yigit Boyar} 3335