RecyclerViewLayoutTest.java revision d8d42d52f8ae53107ffa849b86496650182e24b8
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; 212e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyarimport org.hamcrest.MatcherAssert; 22be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.After; 23be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Before; 24be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Test; 25be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runner.RunWith; 263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.mockito.Mockito; 27be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 28bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.content.Context; 29bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.support.annotation.Nullable; 30be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport android.support.test.InstrumentationRegistry; 316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyarimport android.graphics.Color; 32ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.graphics.PointF; 33f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyarimport android.graphics.Rect; 34bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.os.SystemClock; 354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.InstrumentationRegistry; 364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 37ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.support.v4.view.ViewCompat; 380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.v7.util.TouchUtils; 39f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest; 40bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.util.AttributeSet; 41ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.util.Log; 42670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyarimport android.view.Gravity; 43bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.MotionEvent; 445ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyarimport android.view.View; 45bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.ViewConfiguration; 460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.view.ViewGroup; 474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyarimport android.view.ViewTreeObserver; 48a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyarimport android.widget.LinearLayout; 490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.widget.TextView; 505ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 51e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.ArrayList; 52e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.HashMap; 530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport java.util.List; 54e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.Map; 55ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport java.util.concurrent.CountDownLatch; 56d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit; 57d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicBoolean; 58d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicInteger; 59824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 60e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION; 61bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING; 624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; 63bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING; 64e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.getChildViewHolderInt; 65d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar 66d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyarimport static org.hamcrest.CoreMatchers.sameInstance; 670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*; 683d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport static org.mockito.Mockito.*; 694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyarimport static org.hamcrest.CoreMatchers.is; 70be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 71be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar@RunWith(AndroidJUnit4.class) 72f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 73d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest { 74cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_HORIZONTAL = 1; 75cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_VERTICAL = 1 << 1; 76cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private static final int FLAG_FLING = 1 << 2; 77d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 787bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar private static final boolean DEBUG = false; 7922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 80ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar private static final String TAG = "RecyclerViewLayoutTest"; 81ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 8222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public RecyclerViewLayoutTest() { 8322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar super(DEBUG); 8422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 85bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 86be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 87a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void detachAttachGetReadyWithoutChanges() throws Throwable { 88a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar detachAttachGetReady(false, false, false); 89a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 90a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 91a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Test 92a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void detachAttachGetReadyRequireLayout() throws Throwable { 93a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar detachAttachGetReady(true, false, false); 94a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 95a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 96a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Test 97a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void detachAttachGetReadyRemoveAdapter() throws Throwable { 98a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar detachAttachGetReady(false, true, false); 99a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 100a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 101a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Test 102a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void detachAttachGetReadyRemoveLayoutManager() throws Throwable { 103a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar detachAttachGetReady(false, false, true); 104a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 105a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 106a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar private void detachAttachGetReady(final boolean requestLayoutOnDetach, 107a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final boolean removeAdapter, final boolean removeLayoutManager) throws Throwable { 108a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final LinearLayout ll1 = new LinearLayout(getActivity()); 109a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final LinearLayout ll2 = new LinearLayout(getActivity()); 110a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final LinearLayout ll3 = new LinearLayout(getActivity()); 111a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 112a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 113a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar ll1.addView(ll2); 114a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar ll2.addView(ll3); 115a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar ll3.addView(rv); 116a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestLayoutManager layoutManager = new TestLayoutManager() { 117a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Override 118a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void onLayoutCompleted(RecyclerView.State state) { 119a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar super.onLayoutCompleted(state); 120a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutLatch.countDown(); 121a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 122a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 123a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Override 124a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 125a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar super.onDetachedFromWindow(view, recycler); 126a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar if (requestLayoutOnDetach) { 127a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar view.requestLayout(); 128a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 129a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 130a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar }; 131a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setLayoutManager(layoutManager); 132a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setAdapter(new TestAdapter(10)); 133a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutManager.expectLayouts(1); 134a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar runTestOnUiThread(new Runnable() { 135a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Override 136a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void run() { 137a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getActivity().getContainer().addView(ll1); 138a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 139a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar }); 140a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutManager.waitForLayout(2); 141a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar runTestOnUiThread(new Runnable() { 142a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Override 143a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void run() { 144a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar ll1.removeView(ll2); 145a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 146a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar }); 147a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getInstrumentation().waitForIdleSync(); 148a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar if (removeLayoutManager) { 149a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setLayoutManager(null); 150a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setLayoutManager(layoutManager); 151a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 152a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar if (removeAdapter) { 153a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setAdapter(null); 154a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar rv.setAdapter(new TestAdapter(10)); 155a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 156a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar final boolean requireLayout = requestLayoutOnDetach || removeAdapter || removeLayoutManager; 157a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutManager.expectLayouts(1); 158a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar runTestOnUiThread(new Runnable() { 159a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Override 160a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar public void run() { 161a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar ll1.addView(ll2); 162a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar if (requireLayout) { 163a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar assertTrue(rv.hasPendingAdapterUpdates()); 164a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar assertFalse(rv.mFirstLayoutComplete); 165a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } else { 166a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar assertFalse(rv.hasPendingAdapterUpdates()); 167a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar assertTrue(rv.mFirstLayoutComplete); 168a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 169a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 170a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar }); 171a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar if (requireLayout) { 172a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutManager.waitForLayout(2); 173a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } else { 174a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar layoutManager.assertNoLayout("nothing is invalid, layout should not happen", 2); 175a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 176a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar } 177a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar 178a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar @Test 179d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public void focusSearchWithOtherFocusables() throws Throwable { 180d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar final LinearLayout container = new LinearLayout(getActivity()); 181d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar container.setOrientation(LinearLayout.VERTICAL); 182d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 183d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar mRecyclerView = rv; 184d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar rv.setAdapter(new TestAdapter(10) { 185d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Override 186d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 187d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar int position) { 188d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar super.onBindViewHolder(holder, position); 189d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar holder.itemView.setFocusableInTouchMode(true); 190d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar holder.itemView.setLayoutParams( 191d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 192d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT)); 193d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar } 194d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar }); 195d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 196d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Override 197d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 198d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar detachAndScrapAttachedViews(recycler); 199d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar layoutRange(recycler, 0, 1); 200d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar layoutLatch.countDown(); 201d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar } 202d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar 203d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Nullable 204d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Override 205d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public View onFocusSearchFailed(View focused, int direction, 206d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar RecyclerView.Recycler recycler, 207d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar RecyclerView.State state) { 208d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar assertEquals(View.FOCUS_FORWARD, direction); 209d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar assertEquals(1, getChildCount()); 210d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar View child0 = getChildAt(0); 211d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar View view = recycler.getViewForPosition(1); 212d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar addView(view); 213d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar measureChild(view, 0, 0); 214d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar layoutDecorated(view, 0, child0.getBottom(), getDecoratedMeasuredWidth(view), 215d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar child0.getBottom() + getDecoratedMeasuredHeight(view)); 216d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar return view; 217d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar } 218d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar }; 219d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar tlm.setAutoMeasureEnabled(true); 220d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar rv.setLayoutManager(tlm); 221d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar TextView viewAbove = new TextView(getActivity()); 222d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar viewAbove.setText("view above"); 223d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar viewAbove.setFocusableInTouchMode(true); 224d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar container.addView(viewAbove); 225d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar container.addView(rv); 226d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar TextView viewBelow = new TextView(getActivity()); 227d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar viewBelow.setText("view below"); 228d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar viewBelow.setFocusableInTouchMode(true); 229d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar container.addView(viewBelow); 230d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar tlm.expectLayouts(1); 231d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar runTestOnUiThread(new Runnable() { 232d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Override 233d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public void run() { 234d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar getActivity().getContainer().addView(container); 235d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar } 236d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar }); 237d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar 238d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar tlm.waitForLayout(2); 239d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar requestFocus(viewAbove, true); 240d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar assertTrue(viewAbove.hasFocus()); 241d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar View newFocused = focusSearch(viewAbove, View.FOCUS_FORWARD); 242d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar assertThat(newFocused, sameInstance(rv.getChildAt(0))); 243d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar newFocused = focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD); 244d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar assertThat(newFocused, sameInstance(rv.getChildAt(1))); 245d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar } 246d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar 247d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar @Test 2484510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxNoTranslation() throws Throwable { 2494510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 2504510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 2514510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 2524510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 2534510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(10, 10, 30, 50))); 2544510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2554510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 2564510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2574510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 2584510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 2594510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxTranslateX() throws Throwable { 2604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 2614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 2624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 2634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 2644510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setTranslationX(view, 10); 2654510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(20, 10, 40, 50))); 2664510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2674510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 2684510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 2704510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 2714510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxTranslateY() throws Throwable { 2724510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 2734510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 2744510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 2754510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 2764510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setTranslationY(view, 10); 2774510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(10, 20, 30, 60))); 2784510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2794510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 2804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 2824510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 2834510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxScaleX() throws Throwable { 2844510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 2854510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 2864510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 2874510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 2884510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setScaleX(view, 2); 2894510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(0, 10, 40, 50))); 2904510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2914510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 2924510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 2934510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 2944510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 2954510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxScaleY() throws Throwable { 2964510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 2974510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 2984510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 2994510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 3004510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setScaleY(view, 2); 3014510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(10, -10, 30, 70))); 3024510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3034510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 3044510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3054510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3064510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 3074510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxRotated() throws Throwable { 3084510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar transformedBoundingBoxTest(new ViewRunnable() { 3094510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 3104510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void run(View view) throws RuntimeException { 3114510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 3124510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setRotation(view, 90); 3134510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(getTransformedBoundingBox(view), is(new Rect(0, 20, 40, 40))); 3144510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3154510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 3164510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3174510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3184510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 3194510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void boundingBoxRotatedWithDecorOffsets() throws Throwable { 3204510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3214510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar final TestAdapter adapter = new TestAdapter(1); 3224510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar recyclerView.setAdapter(adapter); 3234510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { 3244510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 3254510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 3264510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar RecyclerView.State state) { 3274510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar outRect.set(1, 2, 3, 4); 3284510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3294510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }); 3304510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar TestLayoutManager layoutManager = new TestLayoutManager() { 3314510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 3324510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3334510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar detachAndScrapAttachedViews(recycler); 3344510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View view = recycler.getViewForPosition(0); 3354510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar addView(view); 3364510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.measure( 3374510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY), 3384510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY) 3394510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ); 3404510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar // trigger decor offsets calculation 3414510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar calculateItemDecorationsForChild(view, new Rect()); 3424510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.layout(10, 10, 30, 50); 3434510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ViewCompat.setRotation(view, 90); 3444510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar assertThat(RecyclerViewLayoutTest.this.getTransformedBoundingBox(view), 3454510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar is(new Rect(-4, 19, 42, 43))); 3464510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3474510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutLatch.countDown(); 3484510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3494510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }; 3504510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar recyclerView.setLayoutManager(layoutManager); 3514510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutManager.expectLayouts(1); 3524510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar setRecyclerView(recyclerView); 3534510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutManager.waitForLayout(2); 3544510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar checkForMainThreadException(); 3554510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3564510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3574510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar private Rect getTransformedBoundingBox(View child) { 3584510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar Rect rect = new Rect(); 3594510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar mRecyclerView.getLayoutManager().getTransformedBoundingBox(child, true, rect); 3604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar return rect; 3614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void transformedBoundingBoxTest(final ViewRunnable layout) throws Throwable { 3644510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3654510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar final TestAdapter adapter = new TestAdapter(1); 3664510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar recyclerView.setAdapter(adapter); 3674510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar TestLayoutManager layoutManager = new TestLayoutManager() { 3684510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Override 3694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3704510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar detachAndScrapAttachedViews(recycler); 3714510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View view = recycler.getViewForPosition(0); 3724510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar addView(view); 3734510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar view.measure( 3744510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY), 3754510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY) 3764510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar ); 3774510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layout.run(view); 3784510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutLatch.countDown(); 3794510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar }; 3814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar recyclerView.setLayoutManager(layoutManager); 3824510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutManager.expectLayouts(1); 3834510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar setRecyclerView(recyclerView); 3844510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar layoutManager.waitForLayout(2); 3854510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar checkForMainThreadException(); 3864510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 3874510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 3884510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar @Test 3890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingFrozen() throws Throwable { 390ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu testScrollFrozen(true); 391ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 392ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 393ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 3940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragFrozen() throws Throwable { 395ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu testScrollFrozen(false); 396ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 397ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 3983d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Test 3993d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void requestRectOnScreenWithScrollOffset() throws Throwable { 4003d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 4013d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager()); 4023d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final int scrollY = 50; 4033d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar RecyclerView.Adapter adapter = new RecyclerView.Adapter() { 4043d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 4053d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 4063d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar View view = new View(parent.getContext()); 4073d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar view.setScrollY(scrollY); 4083d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar return new RecyclerView.ViewHolder(view) { 4093d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }; 4103d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4113d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 4123d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {} 4133d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 4143d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public int getItemCount() { 4153d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar return 1; 4163d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4173d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }; 4183d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.setAdapter(adapter); 4193d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.setLayoutManager(tlm); 4203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar tlm.expectLayouts(1); 4213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar setRecyclerView(recyclerView); 4223d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar tlm.waitForLayout(1); 4233d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar final View child = recyclerView.getChildAt(0); 4243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar assertThat(child.getScrollY(), CoreMatchers.is(scrollY)); 4253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar runTestOnUiThread(new Runnable() { 4263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 4273d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void run() { 4283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true); 4293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class), 4303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar any(RecyclerView.State.class)); 4313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4323d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar }); 4333d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4343d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar 4352ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata @Test 4362ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata public void reattachAndScrollCrash() throws Throwable { 4372ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata final RecyclerView recyclerView = new RecyclerView(getActivity()); 4382ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata final TestLayoutManager tlm = new TestLayoutManager() { 4392ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4402ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata @Override 4412ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata public boolean canScrollVertically() { 4422ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata return true; 4432ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4442ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4452ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata @Override 4462ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 4472ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata layoutRange(recycler, 0, Math.min(state.getItemCount(), 10)); 4482ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4492ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4502ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata @Override 4512ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 4522ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata RecyclerView.State state) { 4532ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata // Access views in the state (that might have been deleted). 4542ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata for (int i = 10; i < state.getItemCount(); i++) { 4552ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata recycler.getViewForPosition(i); 4562ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4572ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata return dy; 4582ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4592ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata }; 4602ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4612ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata final TestAdapter adapter = new TestAdapter(12); 4622ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4632ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata recyclerView.setAdapter(adapter); 4642ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata recyclerView.setLayoutManager(tlm); 4652ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4662ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata setRecyclerView(recyclerView); 4672ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 4682ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata runTestOnUiThread(new Runnable() { 4692ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata @Override 4702ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata public void run() { 471a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getActivity().getContainer().removeView(recyclerView); 472a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getActivity().getContainer().addView(recyclerView); 4732ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata try { 4742ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata adapter.deleteAndNotify(1, adapter.getItemCount() - 1); 4752ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } catch (Throwable throwable) { 4762ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata postExceptionToInstrumentation(throwable); 4772ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4782ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata recyclerView.scrollBy(0, 10); 4792ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4802ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata }); 4812ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata } 4822ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata 483ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu private void testScrollFrozen(boolean fling) throws Throwable { 484ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 485ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 486ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int horizontalScrollCount = 3; 487ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int verticalScrollCount = 3; 488ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int horizontalVelocity = 1000; 489ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final int verticalVelocity = 1000; 490ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount); 491ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount); 492ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 493ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 494ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 495ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 496ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 497ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 498ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 499ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 500ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 501ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 502ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 503ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 504ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 505ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 506ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 507ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 508ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 509ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 510ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 511ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 512ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (verticalCounter.get() > 0) { 513ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu verticalCounter.decrementAndGet(); 514ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return dy; 515ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 516ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return 0; 517ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 518ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 519ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 520ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 521ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 522ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (horizontalCounter.get() > 0) { 523ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu horizontalCounter.decrementAndGet(); 524ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return dx; 525ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 526ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return 0; 527ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 528ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 529ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 530ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 531ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 532ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 533ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 534ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 535ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 536ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 537ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 538ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (fling) { 539ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity)); 540ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } else { // drag 5410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, 542ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu Gravity.LEFT | Gravity.TOP, 543ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 544ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 545ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount, 546ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu horizontalCounter.get()); 547ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's vertical scroll cb must not run", verticalScrollCount, 548ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu verticalCounter.get()); 549ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 550ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 551ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 552ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu if (fling) { 553ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity)); 554ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } else { // drag 5550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, 556ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu Gravity.LEFT | Gravity.TOP, 557ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 558ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 559ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get()); 560ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get()); 561ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 562ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 563ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 5647bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar public void testFocusSearchFailFrozen() throws Throwable { 565ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 5667bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar final CountDownLatch focusLatch = new CountDownLatch(1); 567ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 568ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 569ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 570ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 571ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 572ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 573ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 574ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 575ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 576ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 577ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 578ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 579ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 580ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 581ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 582ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 583ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 584ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 585ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 586121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar public View onFocusSearchFailed(View focused, int direction, 587121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state) { 588ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 5897bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar focusLatch.countDown(); 590ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 591ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 592ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 593ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 594ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 595ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 596ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 597ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 598ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 599ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1); 600959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", requestFocus(c, true)); 601959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", c.hasFocus()); 602ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 6034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar focusSearch(recyclerView, c, View.FOCUS_DOWN); 604ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("onFocusSearchFailed should not be called when layout is frozen", 605ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 0, focusSearchCalled.get()); 606ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 607d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar focusSearch(c, View.FOCUS_DOWN); 6087bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar assertTrue(focusLatch.await(2, TimeUnit.SECONDS)); 609ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(1, focusSearchCalled.get()); 610ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 611ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 612d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public View focusSearch(final ViewGroup parent, final View focused, final int direction) 6134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar throws Throwable { 614d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar final View[] result = new View[1]; 6154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 6164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 6174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 618d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar result[0] = parent.focusSearch(focused, direction); 6194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 6204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 621d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar return result[0]; 6224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 6234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 624ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 6250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void frozenAndChangeAdapter() throws Throwable { 626ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 627ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 628ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 629ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 630ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 631ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 632ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 633ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 634ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 635ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 636ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 637ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 638ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 639ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 640ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 641ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 642ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 643ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 644ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 645ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 646ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 647ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler, 648ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 649ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 650ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 651ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 652ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 653ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 654ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 655ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 656ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 657ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 658ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 659ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 660ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 661ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter2 = new TestAdapter(1000); 662ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setAdapter(adapter2); 663ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 664ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter2, recyclerView.getAdapter()); 665ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 666ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 667ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter3 = new TestAdapter(1000); 668ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu swapAdapter(adapter3, true); 669ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 670ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter3, recyclerView.getAdapter()); 671ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 672ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 673ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 6748fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreChanged() throws Throwable { 6758fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 6768fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 6778fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 6788fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeChanged(3, 0); 6798fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 6808fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 6818fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 6828fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 6838fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 6848fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreChangedWithPayload() throws Throwable { 6858fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 6868fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 6878fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 6888fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeChanged(0, 0, new Object()); 6898fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 6908fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 6918fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 6928fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 6938fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 6948fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreAdded() throws Throwable { 6958fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 6968fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 6978fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 6988fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeInserted(3, 0); 6998fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7008fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7018fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7028fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7038fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7048fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreRemoved() throws Throwable { 7058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7078fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7088fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeRemoved(3, 0); 7098fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7108fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7118fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7128fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7138fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7148fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIfItemMovedIntoItsOwnPlace() throws Throwable { 7158fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7168fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemMoved(3, 3); 7198fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7208fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7218fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7228fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7238fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void unnecessaryNotifyEvents(final AdapterRunnable action) throws Throwable { 7248fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 7258fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar final TestAdapter adapter = new TestAdapter(5); 7268fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 7278fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7288fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 7298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar super.onLayoutChildren(recycler, state); 7308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar layoutLatch.countDown(); 7318fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7328fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }; 7338fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar recyclerView.setLayoutManager(tlm); 7348fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar recyclerView.setAdapter(adapter); 7358fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.expectLayouts(1); 7368fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar setRecyclerView(recyclerView); 7378fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.waitForLayout(1); 7388fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar // ready 7398fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.expectLayouts(1); 7408fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar runTestOnUiThread(new Runnable() { 7418fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7428fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run() { 7438fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar try { 7448fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar action.run(adapter); 7458fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } catch (Throwable throwable) { 7468fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar postExceptionToInstrumentation(throwable); 7478fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7488fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7498fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7508fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.assertNoLayout("dummy event should not trigger a layout", 1); 7518fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar checkForMainThreadException(); 7528fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7538fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7548fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollToPositionCallback() throws Throwable { 7564965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 7574965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 7584965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar int scrollPos = RecyclerView.NO_POSITION; 7591a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 7604965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 7614965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 7624965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutLatch.countDown(); 7634965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar if (scrollPos == RecyclerView.NO_POSITION) { 7644965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, 0, 10); 7654965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } else { 7664965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, scrollPos, scrollPos + 10); 7674965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 7684965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 7691a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 7704965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 7714965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void scrollToPosition(int position) { 7724965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollPos = position; 7734965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayout(); 7744965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 7754965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }; 7764965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setLayoutManager(tlm); 7774965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestAdapter adapter = new TestAdapter(100); 7784965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setAdapter(adapter); 7794965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger rvCounter = new AtomicInteger(0); 7804965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger viewGroupCounter = new AtomicInteger(0); 7814965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.getViewTreeObserver().addOnScrollChangedListener( 7824965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar new ViewTreeObserver.OnScrollChangedListener() { 7834965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 7844965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrollChanged() { 7854965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.incrementAndGet(); 7864965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 7874965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 7884965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 7894965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 7904965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 7914965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar rvCounter.incrementAndGet(); 7924965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar super.onScrolled(recyclerView, dx, dy); 7934965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 7944965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 7954965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 7963f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 7974965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar setRecyclerView(recyclerView); 7984965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 7993f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 8003f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 8013f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 8023f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get()); 8033f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called for initialization", 1, 8044965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.get()); 8054965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 806ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 807ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu scrollToPosition(3); 808ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.assertNoLayout("scrollToPosition should be ignored", 2); 809ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 8104965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollToPosition(3); 8114965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 8123f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called", 2, rvCounter.get()); 8133f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get()); 8144965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 8154965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayoutOnUIThread(recyclerView); 8164965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 8173f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 8183f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 8194965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, rvCounter.get()); 8204965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get()); 821e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 822e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 823e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 824e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeExpand() throws Throwable { 825e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{3, 6}); 826e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 827e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 828e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 829e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeShrink() throws Throwable { 830e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{3, 5}); 831e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 832e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 833e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 834e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeExpand2() throws Throwable { 835e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{2, 5}); 836e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 837e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 838e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 839e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeShrink2() throws Throwable { 840e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{2, 6}); 841e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 842e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 843e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar private void scrollCallbackOnVisibleRangeChange(int itemCount, final int[] beforeRange, 844e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final int[] afterRange) throws Throwable { 845e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 846e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final AtomicBoolean beforeState = new AtomicBoolean(true); 847e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 848e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Override 849e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 850e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar detachAndScrapAttachedViews(recycler); 851e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar int[] range = beforeState.get() ? beforeRange : afterRange; 852e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar layoutRange(recycler, range[0], range[1]); 853e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar layoutLatch.countDown(); 854e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 855e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar }; 856e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.setLayoutManager(tlm); 857e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final TestAdapter adapter = new TestAdapter(itemCount); 858e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.setAdapter(adapter); 859e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.expectLayouts(1); 860e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar setRecyclerView(recyclerView); 861e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.waitForLayout(1); 862e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 863e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar RecyclerView.OnScrollListener mockListener = mock(RecyclerView.OnScrollListener.class); 864e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.addOnScrollListener(mockListener); 865e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar verify(mockListener, never()).onScrolled(any(RecyclerView.class), anyInt(), anyInt()); 8664965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar 867e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.expectLayouts(1); 868e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar beforeState.set(false); 869e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar requestLayoutOnUIThread(recyclerView); 870e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.waitForLayout(2); 871e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar checkForMainThreadException(); 872e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar verify(mockListener).onScrolled(recyclerView, 0, 0); 8734965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 874670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 875be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 8762e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void addItemOnScroll() throws Throwable { 8772e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 8782e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final AtomicInteger start = new AtomicInteger(0); 8792e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 8802e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Override 8812e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 8822e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar layoutRange(recycler, start.get(), start.get() + 10); 8832e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar layoutLatch.countDown(); 8842e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 8852e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar }; 8862e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.setLayoutManager(tlm); 8872e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final TestAdapter adapter = new TestAdapter(100); 8882e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.setAdapter(adapter); 8892e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.expectLayouts(1); 8902e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar setRecyclerView(recyclerView); 8912e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.waitForLayout(1); 8922e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final Throwable[] error = new Throwable[1]; 8932e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final AtomicBoolean calledOnScroll = new AtomicBoolean(false); 8942e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 8952e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Override 8962e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 8972e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar super.onScrolled(recyclerView, dx, dy); 8982e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar calledOnScroll.set(true); 8992e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar try { 9002e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar adapter.addAndNotify(5, 20); 9012e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } catch (Throwable throwable) { 9022e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar error[0] = throwable; 9032e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9042e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9052e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar }); 9062e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar start.set(4); 9072e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(false)); 9082e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.expectLayouts(1); 9092e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar requestLayoutOnUIThread(recyclerView); 9102e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.waitForLayout(2); 9112e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar checkForMainThreadException(); 9122e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(true)); 9132e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat(error[0], CoreMatchers.nullValue()); 9142e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9152e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar 9162e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Test 9170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqual() throws Throwable { 918670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, 1000, 1000); 919670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 920670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 921be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVertical() throws Throwable { 923670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, 1000, 1000); 924670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 925670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 926be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontal() throws Throwable { 928670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, 1000, 1000); 929670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 930670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 931be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnly() throws Throwable { 933670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, 1000, 0); 934670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 935670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 936be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnly() throws Throwable { 938670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, 1000); 939670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 940670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 941be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqualReverse() throws Throwable { 943670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, -1000, -1000); 944670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 945670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 946be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVerticalReverse() throws Throwable { 948670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, -1000, -1000); 949670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 950670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 951be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable { 953670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, -1000, -1000); 954670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 955670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 956be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnlyReverse() throws Throwable { 958670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, -1000, 0); 959670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 960670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 961be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnlyReverse() throws Throwable { 963670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, -1000); 964670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 965670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 966670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount, 967670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar int horizontalVelocity, int verticalVelocity) 968670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar throws Throwable { 969670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 970670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount); 971670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount); 972670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 973670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 974670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 975670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 976670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 977670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 978670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 979670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 980670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 981670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 982670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 983670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 984670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 985670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 986670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 987670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 988670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 989670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 990670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 991670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 992670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (verticalCounter.get() > 0) { 993670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.decrementAndGet(); 994670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dy; 995670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 996670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 997670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 998670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 999670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1000670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 1001670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1002670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (horizontalCounter.get() > 0) { 1003670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.decrementAndGet(); 1004670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dx; 1005670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1006670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 1007670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1008670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 1009670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 1010670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 1011670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 1012670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 1013670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 1014670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 1015670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity)); 1016670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0, 1017670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.get()); 1018670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0, 1019670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.get()); 1020670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1021670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1022be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragHorizontal() throws Throwable { 1024cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL); 1025670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1026670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1027be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragVertical() throws Throwable { 1029cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL); 1030670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1031670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1032be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingHorizontal() throws Throwable { 1034cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING); 1035670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1036670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1037be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingVertical() throws Throwable { 1039cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING); 1040670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1041670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1042f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 10430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVertical() throws Throwable { 1044a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1045f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1046f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1047cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 1048f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1049f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1050f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 10510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontal() throws Throwable { 1052a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1053f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1054f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1055cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 1056f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1057670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1058d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 10590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontalCallsStopNestedScroll() throws Throwable { 1060a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1061d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1062d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1063d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 1064d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 1065d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 1066d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 1067d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 10680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVerticalCallsStopNestedScroll() throws Throwable { 1069a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1070d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1071d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1072d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 1073d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 1074d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 1075d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 1076cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(int flags) 1077f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes throws Throwable { 1078364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar scrollInOtherOrientationTest(flags, flags); 1079f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1080f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1081cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable { 1082670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1083670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false); 1084670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledVertical = new AtomicBoolean(false); 1085f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1086f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes final TestLayoutManager tlm = new TestLayoutManager() { 1087670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1088670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 1089cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_HORIZONTAL) != 0; 1090670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1091670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1092670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1093670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 1094cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_VERTICAL) != 0; 1095670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1096670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1097670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1098670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1099670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 1100670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 1101670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1102670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1103670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1104670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 1105670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1106670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledVertical.set(true); 1107f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollVerticallyBy(dy, recycler, state); 1108670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1109670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1110670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1111670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 1112670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1113670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledHorizontal.set(true); 1114f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollHorizontallyBy(dx, recycler, state); 1115670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1116670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 1117670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 1118670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 1119670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 1120670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 1121670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 1122670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 1123cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar if ( (flags & FLAG_FLING) != 0 ) { 1124cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar int flingVelocity = (mRecyclerView.getMaxFlingVelocity() + 1125cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getMinFlingVelocity()) / 2; 1126cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0, 1127cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar fling(flingVelocity, flingVelocity)); 1128f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } else { // drag 11290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP, 1130cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 1131670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1132f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount, 1133cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get()); 1134f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount, 1135cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get()); 1136670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1137670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1138670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar private boolean fling(final int velocityX, final int velocityY) throws Throwable { 1139670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean didStart = new AtomicBoolean(false); 1140670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar runTestOnUiThread(new Runnable() { 1141670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1142670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void run() { 1143670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar boolean result = mRecyclerView.fling(velocityX, velocityY); 1144670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar didStart.set(result); 1145670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1146670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }); 1147670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (!didStart.get()) { 1148670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return false; 1149670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1150959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar waitForIdleScroll(mRecyclerView); 1151670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 1152670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1153670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1154959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar private void assertPendingUpdatesAndLayoutTest(final AdapterRunnable runnable) throws Throwable { 1155959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1156959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1157959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1158959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 1159959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar layoutManager.expectLayouts(1); 1160da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar runTestOnUiThread(new Runnable() { 1161da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1162da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 1163959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar try { 1164959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar runnable.run(testAdapter); 1165959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } catch (Throwable throwable) { 1166959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar fail("runnable has thrown an exception"); 1167959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1168da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 1169da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1170da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1171959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar layoutManager.waitForLayout(1); 1172da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 1173959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar checkForMainThreadException(); 1174da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1175da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1176da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm, 1177da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter adapter, boolean waitForFirstLayout) throws Throwable { 1178da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setLayoutManager(tlm); 1179da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setAdapter(adapter); 1180da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar if (waitForFirstLayout) { 1181da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.expectLayouts(1); 1182da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 1183da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.waitForLayout(1); 1184da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } else { 1185da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 1186da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1187da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1188da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1189be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void hasPendingUpdatesBeforeFirstLayout() throws Throwable { 1191da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1192da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1193da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1194da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 1195da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 1196da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1197da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1198be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noPendingUpdatesAfterLayout() throws Throwable { 1200da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1201da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1202da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1203da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, true); 1204da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 1205da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1206da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1207be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 1208959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsRemoved() throws Throwable { 1209959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1210da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1211959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1212959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.deleteAndNotify(1, 1); 1213da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1214da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1215959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1216959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1217959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsInserted() throws Throwable { 1218959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1219da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1220959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1221959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.addAndNotify(2, 1); 1222da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1223da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1224959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1225959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1226959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsMoved() throws Throwable { 1227959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1228da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1229959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1230959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.moveItem(2, 3, true); 1231da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1232da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1233959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1234959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1235959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsChanged() throws Throwable { 1236959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1237da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1238959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1239959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.changeAndNotify(2, 1); 1240da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1241da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1242959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1243959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1244959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterDataSetIsChanged() throws Throwable { 1245959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1246da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1247959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) { 1248959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 1249da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1250da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1251da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1252da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1253be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaAdapter() throws Throwable { 1255e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(true, false); 1256e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1257e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1258be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaTransientStateCleanup() throws Throwable { 1260e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, true); 1261e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1262e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1263be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateDontRecycle() throws Throwable { 1265e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, false); 1266e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1267e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1268e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState) 1269e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar throws Throwable { 1270e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> failedToRecycle = new ArrayList<View>(); 1271e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> recycled = new ArrayList<View>(); 1272e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestAdapter testAdapter = new TestAdapter(10) { 1273e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1274e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public boolean onFailedToRecycleView( 1275e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestViewHolder holder) { 1276e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar failedToRecycle.add(holder.itemView); 1277e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (unsetTransientState) { 1278e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(holder.itemView, false); 1279e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1280e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar return succeed; 1281e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1282e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1283e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1284e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 1285e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recycled.add(holder.itemView); 1286e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar super.onViewRecycled(holder); 1287e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1288e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 1289e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1290e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1291e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1292e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (getChildCount() == 0) { 1293e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar detachAndScrapAttachedViews(recycler); 1294e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutRange(recycler, 0, 5); 1295e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } else { 1296e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar removeAndRecycleAllViews(recycler); 1297e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1298e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (layoutLatch != null) { 1299e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutLatch.countDown(); 1300e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1301e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1302e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 1303e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1304e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setAdapter(testAdapter); 1305e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setLayoutManager(tlm); 1306e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setItemAnimator(null); 1307e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setRecyclerView(recyclerView); 1308e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar getInstrumentation().waitForIdleSync(); 1309e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // make sure we have enough views after this position so that we'll receive the on recycled 1310e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // callback 1311e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar View view = recyclerView.getChildAt(3);//this has to be greater than def cache size. 1312e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(view, true); 1313e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.expectLayouts(1); 1314e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar requestLayoutOnUIThread(recyclerView); 1315e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.waitForLayout(2); 1316e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1317e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertTrue(failedToRecycle.contains(view)); 1318e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertEquals(succeed || unsetTransientState, recycled.contains(view)); 1319e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1320e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 1321be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionInvalidation() throws Throwable { 1323e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1324e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestAdapter adapter = new TestAdapter(10); 1325e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 1326e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 1327e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1328e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1329e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutLatch.countDown(); 1330e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1331e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }; 1332e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setAdapter(adapter); 1333e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setLayoutManager(tlm); 1334e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.expectLayouts(1); 1335e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView); 1336e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.waitForLayout(1); 1337e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar runTestOnUiThread(new Runnable() { 1338e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 1339e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void run() { 13401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 1341e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertNotSame("adapter positions should not be undefined", 1342e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 1343e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 1344e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1345e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar adapter.notifyDataSetChanged(); 13461a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 1347e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertSame("adapter positions should be undefined", 1348e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 1349e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 1350e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1351e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1352e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }); 1353e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1354e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 1355be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsBasic() throws Throwable { 1357115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(null); 1358115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1359115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1360be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItems() throws Throwable { 1362115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1363115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1364115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1365115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(3, 4); 1366115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1367115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1368115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1369115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1370be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItemsBefore() throws Throwable { 1372115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1373115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1374115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1375115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(0, 1); 1376115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1377115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1378115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1379115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1380be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsBefore() throws Throwable { 1382115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1383115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1384115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1385115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(0, 5); 1386115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1387115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1388115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1389115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1390be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsInside() throws Throwable { 1392115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1393115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1394115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1395115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(3, 2); 1396115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1397115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1398115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1399115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1400be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsMoveItems() throws Throwable { 1402115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1403115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1404115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1405115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.moveAndNotify(3, 5); 1406115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1407115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1408115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1409115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1410be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsNotifyDataSetChanged() throws Throwable { 1412115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1413115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1414115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1415115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.clear(); 14161a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < 20; i++) { 1417115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.add(new Item(i, "added item")); 1418115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1419115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.notifyDataSetChanged(); 1420115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1421115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1422115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1423115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1424be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable { 1426619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final AtomicBoolean failedToRecycle = new AtomicBoolean(false); 1427619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 1428619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1429619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1430619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1431619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 1432619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1433619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 1434619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1435619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1436619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 1437619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1438619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public boolean onFailedToRecycleView( 1439619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestViewHolder holder) { 1440619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar failedToRecycle.set(true); 1441619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar return false; 1442619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1443619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1444619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 1445619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 1446619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1447619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 1448619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 1449619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 1450619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar runTestOnUiThread(new Runnable() { 1451619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1452619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void run() { 1453619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar ViewCompat.setHasTransientState(vh.itemView, true); 1454619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1455619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1456619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1457619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 1458619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 1459619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 1460619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 1461619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 1462619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1463619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 1464619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 1465619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1466619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1467619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 1468619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(failedToRecycle.get()); 1469619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 1470619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 1471619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1472619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 1473be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable { 1475619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 1476619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1477619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1478619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1479619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 1480619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1481619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 1482619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1483619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1484619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10); 1485619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 1486619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 1487619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1488619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 1489619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 1490619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 1491619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1492619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 1493619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 1494619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 1495619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 1496619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 1497619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1498619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 1499619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 1500619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1501619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1502619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 1503619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 1504619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 1505619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1506619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 1507bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Test 1508bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void duplicateAdapterPositionTest() throws Throwable { 1509bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1510bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 1511bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1512bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1513bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar detachAndScrapAttachedViews(recycler); 1514bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1515bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (!state.isPreLayout()) { 1516bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar while (!recycler.getScrapList().isEmpty()) { 1517bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder viewHolder = recycler.getScrapList().get(0); 1518bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar addDisappearingView(viewHolder.itemView, 0); 1519bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1520bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1521bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar layoutLatch.countDown(); 1522bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1523bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1524bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1525bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public boolean supportsPredictiveItemAnimations() { 1526bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar return true; 1527bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1528bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar }; 1529bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator(); 1530bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar animator.setSupportsChangeAnimations(true); 1531bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar animator.setChangeDuration(10000); 1532bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.setHasStableIds(true); 1533bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestRecyclerView recyclerView = new TestRecyclerView(getActivity()); 1534bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setLayoutManager(tlm); 1535bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setAdapter(testAdapter); 1536bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setItemAnimator(animator); 1537bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1538bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.expectLayouts(1); 1539bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar setRecyclerView(recyclerView); 1540bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.waitForLayout(2); 1541bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1542bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.expectLayouts(2); 1543bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.mItems.get(2).mType += 2; 1544bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final int itemId = testAdapter.mItems.get(2).mId; 1545bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.changeAndNotify(2, 1); 1546bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.waitForLayout(2); 1547bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1548bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar runTestOnUiThread(new Runnable() { 1549bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1550bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void run() { 1551bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat("test sanity", recyclerView.getChildCount(), CoreMatchers.is(11)); 1552bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now mangle the order and run the test 1553bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder hidden = null; 1554bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder updated = null; 1555bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar for (int i = 0; i < recyclerView.getChildCount(); i ++) { 1556bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar View view = recyclerView.getChildAt(i); 1557bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 1558bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (vh.getAdapterPosition() == 2) { 1559bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (mRecyclerView.mChildHelper.isHidden(view)) { 1560bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(hidden, CoreMatchers.nullValue()); 1561bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar hidden = vh; 1562bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } else { 1563bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(updated, CoreMatchers.nullValue()); 1564bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar updated = vh; 1565bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1566bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1567bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1568bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(hidden, CoreMatchers.notNullValue()); 1569bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(updated, CoreMatchers.notNullValue()); 1570bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1571bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.eatRequestLayout(); 1572bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1573bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // first put the hidden child back 1574bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int index1 = mRecyclerView.indexOfChild(hidden.itemView); 1575bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int index2 = mRecyclerView.indexOfChild(updated.itemView); 1576bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index1 < index2) { 1577bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // swap views 1578bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar swapViewsAtIndices(recyclerView, index1, index2); 1579bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1580bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView)); 1581bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1582bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1583bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1584bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1585bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1586bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1587bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1588bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1589bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now swap back 1590bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar swapViewsAtIndices(recyclerView, index1, index2); 1591bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1592bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView)); 1593bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1594bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1595bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1596bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1597bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1598bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1599bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1600bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now remove updated. re-assert fallback to the hidden one 1601bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.removeView(updated.itemView); 1602bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1603bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.nullValue()); 1604bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1605bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1606bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1607bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1608bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1609bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1610bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1611bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar }); 1612bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1613bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1614bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1615bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar private void swapViewsAtIndices(TestRecyclerView recyclerView, int index1, int index2) { 1616bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index1 == index2) { 1617bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar return; 1618bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1619bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index2 < index1) { 1620bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int tmp = index1; 1621bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar index1 = index2; 1622bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar index2 = tmp; 1623bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1624bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final View v1 = recyclerView.getChildAt(index1); 1625bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final View v2 = recyclerView.getChildAt(index2); 1626bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar boolean v1Hidden = recyclerView.mChildHelper.isHidden(v1); 1627bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar boolean v2Hidden = recyclerView.mChildHelper.isHidden(v2); 1628bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // must unhide before swap otherwise bucket indices will become invalid. 1629bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v1Hidden) { 1630bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.unhide(v1); 1631bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1632bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v2Hidden) { 1633bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.unhide(v2); 1634bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1635bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.detachViewFromParent(index2); 1636bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.attachViewToParent(v2, index1, v2.getLayoutParams()); 1637bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.detachViewFromParent(index1 + 1); 1638bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.attachViewToParent(v1, index2, v1.getLayoutParams()); 1639bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1640bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v1Hidden) { 1641bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.hide(v1); 1642bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1643bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v2Hidden) { 1644bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.hide(v2); 1645bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1646bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1647bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1648115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable { 1649115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1650115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1651115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1652115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1653115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 1654115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutRange(recycler, Math.min(state.getItemCount(), 2) 1655115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , Math.min(state.getItemCount(), 7)); 1656115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutLatch.countDown(); 1657115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 1658115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 1659115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1660115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1661115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }; 1662115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1663115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setLayoutManager(tlm); 1664115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setAdapter(testAdapter); 1665115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.expectLayouts(1); 1666115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar setRecyclerView(recyclerView); 1667115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.waitForLayout(1); 1668115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar runTestOnUiThread(new Runnable() { 1669115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1670115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run() { 1671115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 1672115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int count = recyclerView.getChildCount(); 1673115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar Map<View, Integer> layoutPositions = new HashMap<View, Integer>(); 1674115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertTrue("test sanity", count > 0); 16751a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < count; i++) { 1676115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1677115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view); 1678115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1679115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " + index, vh, 1680115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1681115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("get adapter position should return correct index", index, 1682115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1683115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.put(view, vh.mPosition); 1684115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1685115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (adapterChanges != null) { 1686115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterChanges.run(testAdapter); 1687115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar for (int i = 0; i < count; i++) { 1688115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1689115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView 1690115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar .getChildViewHolder(view); 1691115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1692115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (index >= 0) { 1693115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " 16941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar + index, vh, 1695115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1696115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1697115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("get adapter position should return correct index", index, 1698115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1699115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("should be able to find view with layout position", 1700115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh, mRecyclerView.findViewHolderForLayoutPosition( 1701115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.get(view))); 1702115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1703115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1704115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1705115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1706115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 1707115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 1708115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1709115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1710115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1711115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar checkForMainThreadException(); 1712e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1713e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1714be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScroll() throws Throwable { 1716bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1717bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1718bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1719bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1720bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1721bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1722bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1723bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1724bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1725bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1726bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1727bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1728bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1729bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1730bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1731bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1732bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1733bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1734bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1735bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1736bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1737bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1738bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1739bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1740bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1741bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1742bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1743bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1744bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1745be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScrollWithStop() throws Throwable { 1747bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1748bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1749bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1750bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1751bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1752bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1753bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1754bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1755bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1756bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1757bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1758bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1759bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1760bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1761bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1762bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1763bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1764bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1765bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1766bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1767bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1768bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1769bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1770bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1771bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1772bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1773bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1774bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1775bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1776bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1777bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1778bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1779bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1780bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1781bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1782bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1783be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFling() throws Throwable { 1785bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1786bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1787bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1788bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1789bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1790bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1791bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1792bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1793bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1794bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1795bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1796bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1797bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1798bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1799bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1800bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1801bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1802bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1803bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1804bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f; 1805bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1806bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1807bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1808bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1809bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1810bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1811bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1812bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1813bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1814bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1815bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1816bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1817be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFlingWithStop() throws Throwable { 1819bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1820bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1821bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1822bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1823bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1824bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1825bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1826bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1827bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1828bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1829bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1830bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1831bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1832bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1833bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1834bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1835bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1836bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1837bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1838bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f; 1839bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1840bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1841bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1842bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1843bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1844bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1845bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1846bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1847bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1848bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1849bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1850bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1851bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1852bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1853bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1854bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1855bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1856bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1857bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1858be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateDrag() throws Throwable { 1860bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1861bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1862bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1863bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1864bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1865bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1866bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1867bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1868bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1869bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1870bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1871bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1872bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1873bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1874bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1875bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar drag(mRecyclerView, 0, 0, 0, 500, 5); 1876bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]); 1877bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1878bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]); 1879bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1880bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1881bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY, 1882bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar int stepCount) throws Throwable { 1883bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long downTime = SystemClock.uptimeMillis(); 1884bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long eventTime = SystemClock.uptimeMillis(); 1885bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1886bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float y = fromY; 1887bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float x = fromX; 1888bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1889bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float yStep = (toY - fromY) / stepCount; 1890bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float xStep = (toX - fromX) / stepCount; 1891bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1892bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent event = MotionEvent.obtain(downTime, eventTime, 1893bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent.ACTION_DOWN, x, y, 0); 1894bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1895bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar for (int i = 0; i < stepCount; ++i) { 1896bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar y += yStep; 1897bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar x += xStep; 1898bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1899bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 1900bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1901bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1902bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1903bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1904bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 1905bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1906bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1907bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1908bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1909bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable { 1910bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1911bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1912bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1913bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar if (view.onInterceptTouchEvent(event)) { 1914bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar view.onTouchEvent(event); 1915bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1916bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1917bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1918bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1919bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1920be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 19210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleScrap() throws Throwable { 192266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(false); 192366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeRecyclerView(); 192466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(true); 192566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 192666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 192766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void recycleScrapTest(final boolean useRecycler) throws Throwable { 192866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 192966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 193066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 193166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar @Override 193266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1933e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar ViewInfoStore infoStore = mRecyclerView.mViewInfoStore; 193466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (test.get()) { 193566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar try { 193666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar detachAndScrapAttachedViews(recycler); 193766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) { 193866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 193966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView(recycler.getScrapList().get(i).itemView); 194066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 194166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView(recycler.getScrapList().get(i).itemView, 194266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler); 194366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 194466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 1945e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 1946e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) { 194766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 194866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView( 1949e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView); 195066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 195166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView( 1952e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView, 1953e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar recycler); 195466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 195566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 195666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 195766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("no scrap should be left over", 0, recycler.getScrapCount()); 195866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("pre layout map should be empty", 0, 1959e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPreLayout(infoStore)); 196066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post layout map should be empty", 0, 1961e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPostLayout(infoStore)); 1962e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 196366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post old change map should be empty", 0, 1964e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.size()); 196566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 196666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } catch (Throwable t) { 196766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar postExceptionToInstrumentation(t); 196866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 196966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 197066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 197166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutRange(recycler, 0, 5); 197266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutLatch.countDown(); 197366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar super.onLayoutChildren(recycler, state); 197466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 197566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar }; 197666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 197766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setAdapter(testAdapter); 197866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setLayoutManager(lm); 1979121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true); 198066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 198166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar setRecyclerView(recyclerView); 198266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 198366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar test.set(true); 198466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 198566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar testAdapter.changeAndNotify(3, 1); 198666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 198766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar checkForMainThreadException(); 198866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 198922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 1990be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 19914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable { 19925cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar accessRecyclerOnOnMeasureTest(true); 19935cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 19945cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 1995be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 19964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable { 19974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar accessRecyclerOnOnMeasureTest(false); 19984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 19994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 20004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Test 20010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable { 2002cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar smoothScrollTest(true); 2003cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar } 2004cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar 2005cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar @Test 20060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItems() throws Throwable { 2007ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar smoothScrollTest(false); 2008ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2009ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2010ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollTest(final boolean removeItem) throws Throwable { 2011ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final LinearSmoothScroller[] lss = new LinearSmoothScroller[1]; 2012ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStart = new CountDownLatch(1); 2013ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStop = new CountDownLatch(1); 2014ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int visibleChildCount = 10; 2015ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2016ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int start = 0; 2017ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2018ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2019ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2020ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onLayoutChildren(recycler, state); 2021ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutRange(recycler, start, visibleChildCount); 2022ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutLatch.countDown(); 2023ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2024ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2025ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2026ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 2027ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar RecyclerView.State state) { 2028ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar start++; 2029ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2030ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:" 2031ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar + visibleChildCount); 2032ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2033ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar removeAndRecycleAllViews(recycler); 2034c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar layoutRange(recycler, start, 2035c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar Math.max(state.getItemCount(), start + visibleChildCount)); 2036ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return dy; 2037ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2038ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2039ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2040ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public boolean canScrollVertically() { 2041ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return true; 2042ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2043ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2044ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2045ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 2046ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int position) { 2047ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar LinearSmoothScroller linearSmoothScroller = 2048ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 2049ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2050ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 2051ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return new PointF(0, 1); 2052ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2053ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2054ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2055ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStart() { 2056ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStart(); 2057ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStart.countDown(); 2058ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2059ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2060ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2061ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStop() { 2062ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStop(); 2063ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.countDown(); 2064ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2065ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 2066ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar linearSmoothScroller.setTargetPosition(position); 2067ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lss[0] = linearSmoothScroller; 2068ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar startSmoothScroll(linearSmoothScroller); 2069ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2070ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 2071ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 2072ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 2073ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setLayoutManager(lm); 2074ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setAdapter(testAdapter); 2075ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.expectLayouts(1); 2076ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar setRecyclerView(rv); 2077ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.waitForLayout(1); 2078ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar // regular scroll 2079ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int targetPosition = visibleChildCount * (removeItem ? 30 : 4); 2080ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 2081ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2082ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2083ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.smoothScrollToPosition(targetPosition); 2084ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2085ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 2086ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2087ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "scrolling to target position " + targetPosition); 2088ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2089ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS)); 2090ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (removeItem) { 2091ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int newTarget = targetPosition - 10; 2092ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1); 209390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar final CountDownLatch targetCheck = new CountDownLatch(1); 2094ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 2095ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2096ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2097ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar ViewCompat.postOnAnimationDelayed(rv, new Runnable() { 2098ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2099ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2100ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar try { 2101ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertEquals("scroll position should be updated to next available", 2102ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar newTarget, lss[0].getTargetPosition()); 2103ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } catch (Throwable t) { 2104ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar postExceptionToInstrumentation(t); 2105ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 210690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.countDown(); 2107ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 210890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }, 50); 2109ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2110ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 211190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertTrue("target position should be checked on time ", 211290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.await(10, TimeUnit.SECONDS)); 2113ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2114ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS)); 2115ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2116ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("should scroll to new target " + newTarget 2117115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , rv.findViewHolderForLayoutPosition(newTarget)); 2118ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2119ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on stop has been called on time"); 2120ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2121ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } else { 2122ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called eventually", 2123ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.await(30, TimeUnit.SECONDS)); 2124ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("scroll to position should succeed", 2125115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar rv.findViewHolderForLayoutPosition(targetPosition)); 2126ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2127ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2128ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2129ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2130be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 21310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void consecutiveSmoothScroll() throws Throwable { 213278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger visibleChildCount = new AtomicInteger(10); 213378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger totalScrolled = new AtomicInteger(0); 213478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 213578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar int start = 0; 213678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 213778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 213878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 213978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar super.onLayoutChildren(recycler, state); 214078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutRange(recycler, start, visibleChildCount.get()); 214178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutLatch.countDown(); 214278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 214378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 214478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 214578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 214678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar RecyclerView.State state) { 214778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar totalScrolled.set(totalScrolled.get() + dy); 214878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return dy; 214978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 215078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 215178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 215278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public boolean canScrollVertically() { 215378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return true; 215478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 215578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }; 215678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 215778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 215878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setLayoutManager(lm); 215978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setAdapter(testAdapter); 216078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.expectLayouts(1); 216178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar setRecyclerView(rv); 216278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.waitForLayout(1); 216378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 216478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 216578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 216678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 2000); 216778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 216878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 216978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(250); 217078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger scrollAmt = new AtomicInteger(); 217178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 217278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 217378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 217478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 217578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar scrollAmt.set(soFar); 217678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 5000 - soFar); 217778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 217878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 21791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar while (rv.getScrollState() != SCROLL_STATE_IDLE) { 218078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(100); 218178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 218278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 218378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar assertEquals("second scroll should be competed properly", 5000, soFar); 218478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 218578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 21865cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations) 21875cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar throws Throwable { 21885cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 21895cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10); 21905cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 21915cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 21925cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 21935cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onLayoutChildren(recycler, state); 21945cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 21955cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 21965cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 21975cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } catch (Throwable t) { 21985cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 21995cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } finally { 22005cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 22015cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22025cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22035cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 22045cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 22055cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 22065cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar int widthSpec, int heightSpec) { 22075cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 22085cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar // make sure we access all views 22095cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar for (int i = 0; i < state.getItemCount(); i++) { 22105cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar View view = recycler.getViewForPosition(i); 22115cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertNotNull(view); 22125cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertEquals(i, getPosition(view)); 22135cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (!state.isPreLayout()) { 22154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(state.toString(), 22164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar expectedOnMeasureStateCount.get(), state.getItemCount()); 22174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 2218824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 22195cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 22205cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22215cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onMeasure(recycler, state, widthSpec, heightSpec); 22225cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22235cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 22245cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 22255cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public boolean supportsPredictiveItemAnimations() { 22265cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar return enablePredictiveAnimations; 22275cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22285cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar }; 22295cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 22305cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 22315cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setAdapter(testAdapter); 22325cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 22335cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 22345cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar setRecyclerView(recyclerView); 22355cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 22365cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 22375cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 22385cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar if (!enablePredictiveAnimations) { 22395cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar expectedOnMeasureStateCount.set(15); 22405cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22415cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar testAdapter.addAndNotify(4, 5); 22425cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 22435cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 22445cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22455cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 2246be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 22470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setCompatibleAdapter() throws Throwable { 22480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, true); 22490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 22500b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, true); 22510b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 22520b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, false); 22530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 22540b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, false); 22550b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 22560b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 22580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews) 22590b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar throws Throwable { 22600b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 22610b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final AtomicInteger recycledViewCount = new AtomicInteger(); 22620b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 22630b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 22640b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 22650b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 22660b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 22670b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 22680b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 22690b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 22700b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 22710b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 22720b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22730b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22740b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 22750b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 22760b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 22770b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 22780b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() { 22790b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 22800b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onViewRecycled(RecyclerView.ViewHolder holder) { 22810b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recycledViewCount.incrementAndGet(); 22820b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22830b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }); 22840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 22850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 22860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 22870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 22880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 22890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews); 22900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 22910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 22920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar if (removeAndRecycleExistingViews) { 22930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertTrue("Previous views should be recycled", recycledViewCount.get() > 0); 22940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } else { 22950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertEquals("No views should be recycled if adapters are compatible and developer " 22960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar + "did not request a recycle", 0, recycledViewCount.get()); 22970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 22990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 2300be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setIncompatibleAdapter() throws Throwable { 23020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(true); 23030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(false); 23040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 23060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable { 23070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 23080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 23090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 23100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 23110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super.onLayoutChildren(recycler, state); 23120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 23130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 23140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 23160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 23170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 23180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23200b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23210b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 23220b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 23230b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 23240b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 23250b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 23260b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 23270b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 23280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 23290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 23300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 23310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setAdapter(new TestAdapter2(10)); 23320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 23330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 23340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 2336be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleIgnored() throws Throwable { 23386e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 23396e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 23406e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 23416e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 23426e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutRange(recycler, 0, 5); 23436e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutLatch.countDown(); 23446e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 23456e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }; 23466e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 23476e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setAdapter(adapter); 23486e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setLayoutManager(lm); 23496e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.expectLayouts(1); 23506e560171b774afafd572b1896becac7b308a92e6Yigit Boyar setRecyclerView(recyclerView); 23516e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.waitForLayout(2); 23526e560171b774afafd572b1896becac7b308a92e6Yigit Boyar runTestOnUiThread(new Runnable() { 23536e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 23546e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void run() { 23556e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child1 = lm.findViewByPosition(0); 23566e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child2 = lm.findViewByPosition(1); 23576e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child1); 23586e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child2); 23596e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 23606e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleAllViews(recyclerView.mRecycler); 23616e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should not be recycled or removed", 2, 23626e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.getChildCount()); 23636e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 23646e560171b774afafd572b1896becac7b308a92e6Yigit Boyar Throwable[] throwables = new Throwable[1]; 23656e560171b774afafd572b1896becac7b308a92e6Yigit Boyar try { 23666e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleView(child1, mRecyclerView.mRecycler); 23676e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } catch (Throwable t) { 23686e560171b774afafd572b1896becac7b308a92e6Yigit Boyar throwables[0] = t; 23696e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 23706e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertTrue("Trying to recycle an ignored view should throw IllegalArgException " 23715cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar , throwables[0] instanceof IllegalArgumentException); 23726e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAllViews(); 23736e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should be removed as well ", 0, lm.getChildCount()); 23746e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 23756e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }); 23766e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 23776e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 2378be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findIgnoredByPosition() throws Throwable { 2380f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 2381f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 2382f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 2383f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2384f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar detachAndScrapAttachedViews(recycler); 2385f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutRange(recycler, 0, 5); 2386f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutLatch.countDown(); 2387f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2388f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }; 2389f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2390f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setAdapter(adapter); 2391f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setLayoutManager(lm); 2392f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 2393f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar setRecyclerView(recyclerView); 2394f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(2); 2395f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar Thread.sleep(5000); 2396f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final int pos = 1; 2397f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final View[] ignored = new View[1]; 2398f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar runTestOnUiThread(new Runnable() { 2399f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 2400f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void run() { 2401f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View child = lm.findViewByPosition(pos); 2402f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.ignoreView(child); 2403f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar ignored[0] = child; 2404f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2405f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }); 2406f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("ignored child should not be null", ignored[0]); 2407f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNull("find view by position should not return ignored child", 2408f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.findViewByPosition(pos)); 2409f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 2410f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 2411f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(1); 2412f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertEquals("child count should be ", 6, lm.getChildCount()); 2413f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View replacement = lm.findViewByPosition(pos); 2414f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("re-layout should replace ignored child w/ another one", replacement); 2415f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotSame("replacement should be a different view", replacement, ignored[0]); 2416f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2417f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar 2418be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateAllDecorOffsets() throws Throwable { 2420bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 2421bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2422bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true); 2423bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setAdapter(adapter); 2424bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(4); 2425bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() { 2426bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 2427bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar TestLayoutManager testLayoutManager = new TestLayoutManager() { 2428bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2429bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2430bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar try { 2431bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // test 2432824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 2433bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar View child = getChildAt(i); 2434bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2435bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar child.getLayoutParams(); 2436bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 2437bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets validation for VH should have expected value.", 2438bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 2439bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2440bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) { 2441bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2442bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar vh.itemView.getLayoutParams(); 2443bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 2444bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets invalidation in cache for VH should have expected " 2445bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar + "value.", 2446bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 2447bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2448bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar detachAndScrapAttachedViews(recycler); 2449bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutRange(recycler, 0, layoutCount.get()); 2450bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } catch (Throwable t) { 2451bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar postExceptionToInstrumentation(t); 2452bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } finally { 2453bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutLatch.countDown(); 2454bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2455bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2456bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2457bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2458bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public boolean supportsPredictiveItemAnimations() { 2459bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar return false; 2460bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2461bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 2462bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // first layout 2463bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setItemViewCacheSize(5); 2464bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setLayoutManager(testLayoutManager); 2465bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2466e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView, true, false); 2467bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 2468bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2469bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2470bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 2471bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2472bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2473bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 2474bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2475bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2476bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2477bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/o an item decorator 2478e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 2479bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2480bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2481bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2482bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.assertNoLayout("layout should not happen", 2); 2483bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2484bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2485bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // set item decorator, should invalidate 2486bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2487bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2488bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar addItemDecoration(mRecyclerView, dummyItemDecoration); 2489bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2490bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2491bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2492bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 2493bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2494bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2495bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 2496bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2497bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2498bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2499bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/ item decorator 2500bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2501bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2502bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2503bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2504bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 2505bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2506bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2507bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // trigger cache. 2508bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(3); 2509bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2510bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2511bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 2512bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2513bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2514bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size()); 2515bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2516bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(5); 2517bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2518bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2519bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2520bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2521bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2522bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2523bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // remove item decorator 2524bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2525bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2526bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar removeItemDecoration(mRecyclerView, dummyItemDecoration); 2527bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2528bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2529bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2530bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2531bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void addItemDecoration(final RecyclerView recyclerView, final 2532824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 2533bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2534bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2535bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2536bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.addItemDecoration(itemDecoration); 2537bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2538bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2539bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2540bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2541bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void removeItemDecoration(final RecyclerView recyclerView, final 2542bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 2543bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2544bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2545bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2546bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.removeItemDecoration(itemDecoration); 2547bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2548bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2549bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2550bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2551bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable { 2552bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2553bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2554bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2555bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.invalidateItemDecorations(); 2556bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2557bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2558bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2559bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2560be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 25610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateDecorOffsets() throws Throwable { 2562cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final TestAdapter adapter = new TestAdapter(10); 2563cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.setHasStableIds(true); 2564cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 2565cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setAdapter(adapter); 2566cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2567cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final Map<Long, Boolean> changes = new HashMap<Long, Boolean>(); 2568cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2569cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 2570cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 2571cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2572cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase try { 2573cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (changes.size() > 0) { 2574cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase // test 2575824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 2576cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase View child = getChildAt(i); 2577cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2578cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase child.getLayoutParams(); 2579cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.ViewHolder vh = lp.mViewHolder; 2580cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (!changes.containsKey(vh.getItemId())) { 2581cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase continue; //nothing to test 2582cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2583cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase assertEquals( 2584cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase "Decord insets validation for VH should have expected value.", 2585cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.get(vh.getItemId()).booleanValue(), 2586cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase lp.mInsetsDirty); 2587cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2588cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2589cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase detachAndScrapAttachedViews(recycler); 2590cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutRange(recycler, 0, state.getItemCount()); 2591cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } catch (Throwable t) { 2592cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase postExceptionToInstrumentation(t); 2593cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } finally { 2594cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutLatch.countDown(); 2595cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2596cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2597cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2598cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 2599cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public boolean supportsPredictiveItemAnimations() { 2600cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase return false; 2601cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2602cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase }; 2603cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setLayoutManager(testLayoutManager); 2604cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2605cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase setRecyclerView(recyclerView); 2606cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2607cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int itemAddedTo = 5; 2608cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = 0; i < itemAddedTo; i++) { 2609115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 2610cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2611cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) { 2612115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 2613cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2614cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2615cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.addAndNotify(5, 1); 2616cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2617cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2618cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2619cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.clear(); 2620cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int[] changedItems = new int[]{3, 5, 6}; 2621824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 2622115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 2623cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2624824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < changedItems.length; i++) { 26251a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItems[i]).getItemId(), 26261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar true); 2627cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2628cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2629cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changePositionsAndNotify(changedItems); 2630cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2631cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2632cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2633824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 2634115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 2635cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2636cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2637cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 2638cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2639cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2640cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2641cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2642be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 26430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void movingViaStableIds() throws Throwable { 2644c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(true); 2645c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 2646c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(false); 2647c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 2648c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2649c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2650c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable { 2651c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 2652c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.setHasStableIds(true); 2653c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 2654c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewFromIndex = 3; 2655c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewToIndex = 6; 2656c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final View[] movedView = new View[1]; 2657c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2658c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2659c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2660c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar detachAndScrapAttachedViews(recycler); 2661c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar try { 2662c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (test.get()) { 2663c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (state.isPreLayout()) { 2664c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewFromIndex, true); 2665c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In pre layout, should be able to get moved view w/ old " 2666c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 2667c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 2668c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 2669c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 2670c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 2671c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } else { 2672c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewToIndex, true); 2673c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In post layout, should be able to get moved view w/ new " 2674c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 2675c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 2676c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 2677c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 2678c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 2679c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2680c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2681c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 2682c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } catch (Throwable t) { 2683c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar postExceptionToInstrumentation(t); 2684c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } finally { 2685c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutLatch.countDown(); 2686c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2687c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2688c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2689c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2690c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2691c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2692c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public boolean supportsPredictiveItemAnimations() { 2693c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar return supportsPredictive; 2694c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2695c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }; 2696c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView recyclerView = new RecyclerView(this.getActivity()); 2697c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setAdapter(testAdapter); 2698c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setLayoutManager(lm); 2699c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(1); 2700c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar setRecyclerView(recyclerView); 2701c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(1); 2702c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2703c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar movedView[0] = recyclerView.getChildAt(movedViewFromIndex); 2704c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar test.set(true); 2705c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(supportsPredictive ? 2 : 1); 2706c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar runTestOnUiThread(new Runnable() { 2707c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2708c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void run() { 2709c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar Item item = testAdapter.mItems.remove(movedViewFromIndex); 2710c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.mItems.add(movedViewToIndex, item); 2711c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemRemoved(movedViewFromIndex); 2712c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemInserted(movedViewToIndex); 2713c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2714c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }); 2715c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(2); 2716c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar checkForMainThreadException(); 2717c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2718cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2719be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 27200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringLayout() throws Throwable { 27210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() { 27220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 27240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 27250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 27270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 27280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() { 27290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 27310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 27320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 27340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 27350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() { 27360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 27380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 27390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 27410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() { 27420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 27440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 27450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 27470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 27490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeInMainThreadTest(String msg, 27500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onLayoutRunnable) throws Throwable { 275166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 27520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final AtomicBoolean doneFirstLayout = new AtomicBoolean(false); 27530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 27540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 27550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 27570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 27580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 27590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 27600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (doneFirstLayout.get()) { 27610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onLayoutRunnable.run(); 27620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 27640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 27650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 27660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 27670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 27690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 27710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 27720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 27730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 27740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 27750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 27760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 27770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar doneFirstLayout.set(true); 27780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 27790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar requestLayoutOnUIThread(recyclerView); 27800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 27810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 27820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 278366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar getMainThreadException() instanceof IllegalStateException); 27840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2786be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 27870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScroll() throws Throwable { 27880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int orientation : new int[]{OrientationHelper.HORIZONTAL, 27890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar OrientationHelper.VERTICAL}) { 27900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyDataSetChanged", orientation, 27910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar new Runnable() { 27920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 27940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 27950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 27960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 27970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() { 27980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 27990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 28010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() { 28050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 28080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28090bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28100bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() { 28110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 28140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeDuringScrollTest(String msg, final int orientation, 28200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onScrollRunnable) throws Throwable { 282166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 28220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(100); 28230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 28240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 28260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 28270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 28280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, 10); 28290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 28300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 28310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 28320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 28330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollVertically() { 28380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.VERTICAL; 28390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollHorizontally() { 28430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.HORIZONTAL; 28440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int mockScroll() { 28470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 28480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onScrollRunnable.run(); 28490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 28500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 28510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 28520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 28530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return 0; 28550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 28590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 28600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 28610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 28650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 28660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 28670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 28690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 28700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 28710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 28720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 28730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 28740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 28750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 28760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar scrollBy(200); 28770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 28780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 28790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 288066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar getMainThreadException() instanceof IllegalStateException); 28810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2883be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleOnDetach() throws Throwable { 288549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 288649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 288749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final AtomicBoolean didRunOnDetach = new AtomicBoolean(false); 288849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 288949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 289049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 289149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onLayoutChildren(recycler, state); 289249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutRange(recycler, 0, state.getItemCount() - 1); 289349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutLatch.countDown(); 289449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 289549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 289649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 289749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 289849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onDetachedFromWindow(view, recycler); 289949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar didRunOnDetach.set(true); 290049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeAndRecycleAllViews(recycler); 290149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 290249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar }; 290349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setAdapter(testAdapter); 290449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setLayoutManager(lm); 290549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.expectLayouts(1); 290649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar setRecyclerView(recyclerView); 290749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.waitForLayout(2); 290849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeRecyclerView(); 290949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get()); 291049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertEquals("All children should be recycled", recyclerView.getChildCount(), 0); 291149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 29120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2913be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 29140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesWhileDetached() throws Throwable { 2915bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2916bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 2917bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 2918bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 2919bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2920bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2921bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2922bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 2923bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 2924bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 2925bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 2926bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2927bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 2928bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 2929bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 2930bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 2931bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2932bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 2933bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 2934bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2935bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 2936be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 29370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesAfterDetach() throws Throwable { 2938bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2939bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 2940bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 2941bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 2942bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2943bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2944bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2945bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 2946bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 2947bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 2948bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 2949bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2950bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 2951bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 2952bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 2953bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2954bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 2955bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar setRecyclerView(recyclerView); 2956bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.waitForLayout(2); 2957bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 2958bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int prevLayoutCount = layoutCount.get(); 2959bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar runTestOnUiThread(new Runnable() { 2960bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 2961bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void run() { 2962bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar try { 2963bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 2964bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar removeRecyclerView(); 2965bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } catch (Throwable throwable) { 296690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar postExceptionToInstrumentation(throwable); 2967bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2968bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 2969bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }); 297090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 2971bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 2972bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 2973bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar assertEquals("No extra layout should happen when detached", prevLayoutCount, 2974bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.get()); 2975bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 297649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 2977be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 29780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedWithStableIds() throws Throwable { 2979e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int defaultViewType = 1; 2980e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Item, Integer> viewTypeMap = new HashMap<Item, Integer>(); 2981e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Integer, Integer> oldPositionToNewPositionMapping = 2982e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new HashMap<Integer, Integer>(); 2983e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 2984e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2985e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public int getItemViewType(int position) { 2986e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Integer type = viewTypeMap.get(mItems.get(position)); 2987e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return type == null ? defaultViewType : type; 2988e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2989e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 2990e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 2991e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 2992e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 2993e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 2994e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 2995e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 2996e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final ArrayList<Item> previousItems = new ArrayList<Item>(); 2997e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar previousItems.addAll(adapter.mItems); 2998e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 2999e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicInteger layoutStart = new AtomicInteger(50); 3000e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicBoolean validate = new AtomicBoolean(false); 3001e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int childCount = 10; 3002e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 3003e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3004e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3005e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 3006e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar super.onLayoutChildren(recycler, state); 3007e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3008e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("Cached views should be kept", 5, recycler 3009e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .mCachedViews.size()); 3010e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.mCachedViews) { 3011e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 30120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 30130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 3014e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 3015e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3016e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3017e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar detachAndScrapAttachedViews(recycler); 3018e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3019e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("cache size should stay the same", 5, 3020e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.mCachedViews.size()); 3021e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("all views should be scrapped", childCount, 3022e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.getScrapList().size()); 3023e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.getScrapList()) { 3024e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // TODO create test case for type change 3025e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 30260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 30270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 3028e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 3029e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3030e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3031e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 3032e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3033e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < getChildCount(); i++) { 3034e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = getChildAt(i); 3035e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) mRecyclerView 3036e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .getChildViewHolder(view); 3037115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int oldPos = previousItems.indexOf(tvh.mBoundItem); 3038e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("view holder's position should be correct", 3039e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.get(oldPos).intValue(), 3040115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tvh.getLayoutPosition()); 30410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar ; 30420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 3043e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3044e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable t) { 3045e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(t); 3046e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } finally { 3047e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutLatch.countDown(); 3048e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3049e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3050e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 3051e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3052e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemAnimator(null); 3053e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setAdapter(adapter); 3054e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setLayoutManager(lm); 3055e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemViewCacheSize(10); 3056e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3057e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setRecyclerView(recyclerView); 3058e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3059e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 3060e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar getInstrumentation().waitForIdleSync(); 3061e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutStart.set(layoutStart.get() + 5);//55 3062e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3063e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar requestLayoutOnUIThread(recyclerView); 3064e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3065e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar validate.set(true); 3066e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3067e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar runTestOnUiThread(new Runnable() { 3068e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3069e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void run() { 3070e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 3071e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.moveItems(false, 3072e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2}, 3073e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64}, 3074e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{75, 58}); 3075e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < previousItems.size(); i++) { 3076e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item = previousItems.get(i); 3077e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item)); 3078e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3079cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 3080e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable throwable) { 3081e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(throwable); 3082e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3083e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3084e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }); 3085e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3086e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 3087e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3088e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 3089be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSwap() throws Throwable { 3091824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(true); 3092824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3093824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3094be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSet() throws Throwable { 3096824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(false); 3097824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3098824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3099824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void callbacksDuringAdapterChange(boolean swap) throws Throwable { 3100824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter() 3101824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 3102824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter() 3103824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 3104824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3105824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3106824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3107824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3108824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar try { 3109824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 3110824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 3111824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar postExceptionToInstrumentation(t); 3112824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3113824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutLatch.countDown(); 3114824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3115824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3116824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3117824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setAdapter(adapter1); 3118824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setLayoutManager(tlm); 3119824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 3120824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setRecyclerView(rv); 3121824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 3122824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3123824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 3124824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar if (swap) { 3125824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar swapAdapter(adapter2, true); 3126824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } else { 3127824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setAdapter(adapter2); 3128824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3129824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3130824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 3131824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3132824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3133824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3134824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createOwnerCheckingAdapter() { 3135824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 3136824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3137824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 3138824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 3139824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 3140824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 3141824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3142824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3143824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3144824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 3145824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 3146824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on bind should be called w/ the creator adapter", this, holder.mData); 3147824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3148824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3149824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3150824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 3151824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar int viewType) { 3152824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType); 3153824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar vh.mData = this; 3154824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return vh; 3155824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3156824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3157824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3158824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3159824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createBinderCheckingAdapter() { 3160824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 3161824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3162824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 3163824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 3164824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 3165824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = null; 3166824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 3167824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3168824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3169824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3170824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 3171824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 3172824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = this; 3173824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3174824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3175824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3176824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3177be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 31780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findViewById() throws Throwable { 31795ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(false); 31805ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar removeRecyclerView(); 31815ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(true); 31825ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 31835ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 31845ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void findViewByIdTest(final boolean supportPredictive) throws Throwable { 31855ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 31865ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int initialAdapterSize = 20; 31875ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 31885ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteStart = 6; 31895ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteCount = 5; 31905ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setAdapter(adapter); 31915ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final AtomicBoolean assertPositions = new AtomicBoolean(false); 31925ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 31935ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 31945ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 31955ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar super.onLayoutChildren(recycler, state); 31965ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (assertPositions.get()) { 31975ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (state.isPreLayout()) { 31980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteStart; i++) { 31995ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 32005ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position for existing items should work " 32015ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "fine", view); 32025ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 32035ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32045ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32055ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteCount; i++) { 32075ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i + deleteStart); 32085ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position should work fine for removed " 32095ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "views in pre-layout", view); 32105ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertTrue("view should be marked as removed", 32115ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32125ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32135ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32145ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar for (int i = deleteStart + deleteCount; i < 20; i++) { 32155ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 32165ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull(view); 32175ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 32185ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32195ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32205ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32215ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } else { 32220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < initialAdapterSize - deleteCount; i++) { 32235ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 3224fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar assertNotNull("find view by position for existing item " + i + 3225fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar " should work fine. child count:" + getChildCount(), view); 32265ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestViewHolder viewHolder = 32275ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar (TestViewHolder) mRecyclerView.getChildViewHolder(view); 32285ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertSame("should be the correct item " + viewHolder 3229115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , viewHolder.mBoundItem, 32305ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.mItems.get(viewHolder.mPosition)); 32315ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 32325ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32335ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32345ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32355ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32365ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32375ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar detachAndScrapAttachedViews(recycler); 32385ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutRange(recycler, state.getItemCount() - 1, -1); 32395ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutLatch.countDown(); 32405ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32415ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 32425ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 32435ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public boolean supportsPredictiveItemAnimations() { 32445ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar return supportPredictive; 32455ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32465ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar }; 32475ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setLayoutManager(lm); 32485ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(1); 32495ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar setRecyclerView(recyclerView); 32505ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 32515ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar getInstrumentation().waitForIdleSync(); 32525ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 32535ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertPositions.set(true); 32545ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(supportPredictive ? 2 : 1); 32555ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1}); 32565ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 32575ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32585ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 3259be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 32600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForCache() throws Throwable { 326122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 326222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestAdapter adapter = new TestAdapter(100) { 326322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 326422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public int getItemViewType(int position) { 326522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return viewType.get(); 326622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 326722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 326822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 326922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public long getItemId(int position) { 327022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return mItems.get(position).mId; 327122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 327222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 327322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.setHasStableIds(true); 327422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger layoutStart = new AtomicInteger(2); 327522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final int childCount = 10; 327622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 327722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 327822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 327922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar super.onLayoutChildren(recycler, state); 328022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar detachAndScrapAttachedViews(recycler); 328122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 328222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutLatch.countDown(); 328322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 328422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 328522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3286668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar recyclerView.setItemAnimator(null); 328722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setAdapter(adapter); 328822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setLayoutManager(lm); 328922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setItemViewCacheSize(10); 329022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 329122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar setRecyclerView(recyclerView); 329222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 329322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar getInstrumentation().waitForIdleSync(); 329422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(4); // trigger a cache for 3,4 329522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 329622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar requestLayoutOnUIThread(recyclerView); 329722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 329822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar // 329922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar viewType.incrementAndGet(); 330022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(2); // go back to bring views from cache 330122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 330222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.mItems.remove(1); 3303cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 330422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 330522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar runTestOnUiThread(new Runnable() { 330622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 330722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void run() { 330822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar for (int i = 2; i < 4; i++) { 3309115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i); 331022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar assertEquals("View holder's type should match latest type", viewType.get(), 331122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar vh.getItemViewType()); 331222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 331322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 331422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }); 331522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 331622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 3317be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 33180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForExistingViews() throws Throwable { 33197e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 33207e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int invalidatedCount = 2; 33217e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int layoutStart = 2; 33227e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 33237e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 33247e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public int getItemViewType(int position) { 33257e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return viewType.get(); 33267e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33277e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 33287e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 33297e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 33307e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar int position) { 33317e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onBindViewHolder(holder, position); 33327e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar if (position >= layoutStart && position < invalidatedCount + layoutStart) { 33337e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar try { 33347e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar assertEquals("holder type should match current view type at position " + 33357e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar position, viewType.get(), holder.getItemViewType()); 33367e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } catch (Throwable t) { 33377e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar postExceptionToInstrumentation(t); 33387e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33397e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33407e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33417e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 33427e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 33437e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public long getItemId(int position) { 33447e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return mItems.get(position).mId; 33457e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33467e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 33477e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar adapter.setHasStableIds(true); 33487e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 33497e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int childCount = 10; 33507e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 33517e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 33527e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 33537e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onLayoutChildren(recycler, state); 33547e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar detachAndScrapAttachedViews(recycler); 33557e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutRange(recycler, layoutStart, layoutStart + childCount); 33567e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutLatch.countDown(); 33577e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33587e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 33597e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 33607e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setAdapter(adapter); 33617e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setLayoutManager(lm); 33627e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 33637e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar setRecyclerView(recyclerView); 33647e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 33657e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar getInstrumentation().waitForIdleSync(); 33667e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar viewType.incrementAndGet(); 33677e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 3368cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changeAndNotify(layoutStart, invalidatedCount); 33697e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 33707e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar checkForMainThreadException(); 33717e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 33727e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 33737e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 3374be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 33750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void state() throws Throwable { 3376d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final TestAdapter adapter = new TestAdapter(10); 3377d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 3378d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setAdapter(adapter); 3379d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setItemAnimator(null); 3380d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicInteger itemCount = new AtomicInteger(); 3381d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicBoolean structureChanged = new AtomicBoolean(); 3382d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 3383d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3384d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 33858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar detachAndScrapAttachedViews(recycler); 3386d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutRange(recycler, 0, state.getItemCount()); 3387d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.set(state.getItemCount()); 3388d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.set(state.didStructureChange()); 3389d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutLatch.countDown(); 3390d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3391d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }; 3392d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setLayoutManager(testLayoutManager); 3393d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 3394d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 3395d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3396d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 3397a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getActivity().getContainer().addView(recyclerView); 3398d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3399d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 340066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar testLayoutManager.waitForLayout(2); 3401d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 3402d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("item count in state should be correct", adapter.getItemCount() 3403d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase , itemCount.get()); 3404d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true for first layout", true, 3405d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 3406d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase Thread.sleep(1000); //wait for other layouts. 3407d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 3408d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 3409d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3410d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 3411d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.requestLayout(); 3412d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3413d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 34148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3415d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("in second layout,structure changed should be false", false, 3416d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 34178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); // 3418b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.deleteAndNotify(3, 2); 34198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3420d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are removed, item count in state should be updated", 3421d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 3422d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 3423d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 3424d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 34258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); 3426b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.addAndNotify(2, 5); 34278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3428d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 3429d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are added, item count in state should be updated", 3430d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 3431d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 3432d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 3433d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 34340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 34350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 3436be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 34370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachWithoutLayoutManager() throws Throwable { 3438abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3439abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar runTestOnUiThread(new Runnable() { 3440abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar @Override 3441abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar public void run() { 3442abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar try { 3443abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar setRecyclerView(recyclerView); 3444abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar removeRecyclerView(); 3445abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } catch (Throwable t) { 3446abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar postExceptionToInstrumentation(t); 3447abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3448abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3449abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar }); 3450abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar checkForMainThreadException(); 3451abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3452abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 3453be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 34540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updateHiddenView() throws Throwable { 34551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 34561a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] preLayoutRange = new int[]{0, 10}; 34571a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] postLayoutRange = new int[]{0, 10}; 34581a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final AtomicBoolean enableGetViewTest = new AtomicBoolean(false); 3459959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar final List<Integer> disappearingPositions = new ArrayList<>(); 34601a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 34611a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 34621a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public boolean supportsPredictiveItemAnimations() { 34631a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar return true; 34641a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 34651a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 34661a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 34671a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 34681a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 34691a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] layoutRange = state.isPreLayout() ? preLayoutRange 34701a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar : postLayoutRange; 34711a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar detachAndScrapAttachedViews(recycler); 34721a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutRange(recycler, layoutRange[0], layoutRange[1]); 34731a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar if (!state.isPreLayout()) { 34741a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (Integer position : disappearingPositions) { 34751a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // test sanity. 34761a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar assertNull(findViewByPosition(position)); 34771a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final View view = recycler.getViewForPosition(position); 3478959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertNotNull(view); 34791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar addDisappearingView(view); 34801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar measureChildWithMargins(view, 0, 0); 34811a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // position item out of bounds. 34821a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar view.layout(0, -500, view.getMeasuredWidth(), 34831a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar -500 + view.getMeasuredHeight()); 34841a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 34851a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 34861a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable t) { 34871a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postExceptionToInstrumentation(t); 34881a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 34891a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutLatch.countDown(); 34901a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 34911a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }; 3492959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar recyclerView.getItemAnimator().setMoveDuration(4000); 3493959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar recyclerView.getItemAnimator().setRemoveDuration(4000); 34941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestAdapter adapter = new TestAdapter(100); 34951a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setAdapter(adapter); 34961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setLayoutManager(tlm); 34971a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(1); 34981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar setRecyclerView(recyclerView); 34991a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(1); 35001a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 35011a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now, a child disappears 35021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.add(0); 35031a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // layout one shifted 35041a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[0] = 1; 35051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[1] = 11; 35061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 35071a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.addAndNotify(8, 1); 35081a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 35091a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 35101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 35111a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 35121a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.clear(); 35131a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now that item should be moving, invalidate it and delete it. 35141a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar enableGetViewTest.set(true); 35151a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar runTestOnUiThread(new Runnable() { 35161a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 35171a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void run() { 35181a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 3519959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertThat("test sanity, should still be animating", 3520959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar mRecyclerView.isAnimating(), CoreMatchers.is(true)); 35211a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.changeAndNotify(0, 1); 35221a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.deleteAndNotify(0, 1); 35231a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable throwable) { 3524959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar fail(throwable.getMessage()); 35251a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35271a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }); 35281a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 35291a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 35301a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35311a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 3532be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnTop() throws Throwable { 35346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.TOP); 35356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3537be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeft() throws Throwable { 35396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT); 35406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3542be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRight() throws Throwable { 35446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT); 35456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3547be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnBottom() throws Throwable { 35496d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.BOTTOM); 35506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3552be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeftRTL() throws Throwable { 35546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT, true); 35556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 35566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 35576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3559be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRightRTL() throws Throwable { 35616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT, true); 35626d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 35636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 35646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 35666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity) throws Throwable { 35676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(gravity, false); 35686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 3569be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 35706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable { 35716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 35726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 35736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL); 35746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vScrollDist = new AtomicInteger(0); 35766d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hScrollDist = new AtomicInteger(0); 35776d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vDesiredDist = new AtomicInteger(0); 35786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hDesiredDist = new AtomicInteger(0); 35796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 35806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 35816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 35826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int getLayoutDirection() { 35836d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR; 35846d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 35856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 35866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 35876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 35886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar detachAndScrapAttachedViews(recycler); 35896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final View view = recycler.getViewForPosition(0); 35906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar addView(view); 35916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar int left = 0, top = 0; 35926d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.setBackgroundColor(Color.rgb(0, 0, 255)); 35936d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar switch (gravity) { 35946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.LEFT: 35956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.RIGHT: 35966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 35976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5), 35986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY), 35996d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9), 36006d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST)); 36016d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80 36026d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar : 90; 36036d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = 0; 36046d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) { 36056d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth()); 36066d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 36076d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set(left); 36086d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36096d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 36106d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.TOP: 36116d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.BOTTOM: 36126d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 36136d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9), 36146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST), 36156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5), 36166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY)); 36176d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() - 36186d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 80 : 90; 36196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = 0; 36206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vDesiredDist.set(top); 36216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 36226d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36236d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.layout(left, top, left + view.getMeasuredWidth(), 36256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top + view.getMeasuredHeight()); 36266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar layoutLatch.countDown(); 36276d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollVertically() { 36316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return true; 36326d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36336d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollHorizontally() { 36366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return super.canScrollHorizontally(); 36376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 36416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 36426d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vScrollDist.addAndGet(dy); 36436d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetTopAndBottom(-dy); 36446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dy; 36456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36486d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 36496d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 36506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hScrollDist.addAndGet(dx); 36516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetLeftAndRight(-dx); 36526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dx; 36536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar }; 36556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestAdapter adapter = new TestAdapter(10); 36566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setAdapter(adapter); 36576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setLayoutManager(tlm); 36586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.expectLayouts(1); 36596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar setRecyclerView(rv); 36606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.waitForLayout(2); 36616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View view = rv.getChildAt(0); 3662959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", requestFocus(view, true)); 3663959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", view.hasFocus()); 36646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(vDesiredDist.get(), vScrollDist.get()); 36656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(hDesiredDist.get(), hScrollDist.get()); 36666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingTop(), view.getTop()); 36676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 3668be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), 3669be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar view.getRight()); 36706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 36716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft()); 36726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3675be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void firstLayoutWithAdapterChanges() throws Throwable { 36774bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final TestAdapter adapter = new TestAdapter(0); 36784bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 36794bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setVisibility(rv, View.GONE); 36804bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 36814bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 36824bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 36834bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 36844bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar super.onLayoutChildren(recycler, state); 36854bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 36864bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable t) { 36874bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar postExceptionToInstrumentation(t); 36884bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } finally { 36894bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutLatch.countDown(); 36904bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 36914bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 36924bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 36934bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 36944bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public boolean supportsPredictiveItemAnimations() { 36954bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar return true; 36964bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 36974bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }; 36984bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setLayoutManager(tlm); 36994bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setAdapter(adapter); 37004bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setHasFixedSize(true); 37014bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setRecyclerView(rv); 37024bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.expectLayouts(1); 37034bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.assertNoLayout("test sanity, layout should not run", 1); 37044bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar getInstrumentation().waitForIdleSync(); 37054bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar runTestOnUiThread(new Runnable() { 37064bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 37074bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void run() { 37084bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 37094bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar adapter.addAndNotify(2); 37104bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable throwable) { 37114bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar throwable.printStackTrace(); 37124bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37134bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setVisibility(View.VISIBLE); 37144bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37154bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }); 37164bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 37174bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.waitForLayout(2); 37184bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar assertEquals(2, rv.getChildCount()); 37194bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 37204bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37214bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 37224bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Test 372314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutLayoutManager() throws Throwable { 372414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 372514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setAdapter(new TestAdapter(10)); 372614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 372714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 372814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 372914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 373014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 373114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 373214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 373314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 373414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 373514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 373614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 373714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutAdapter() throws Throwable { 373814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 373914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setLayoutManager(new TestLayoutManager()); 374014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 374114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 374214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 374314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 374414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 374514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 374614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 374714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 374814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 374914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 375014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 37510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithDecorOffsets() throws Throwable { 3752f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(true); 3753f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3754f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3755be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 37560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithout() throws Throwable { 3757f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(false); 3758f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3759f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3760f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable { 3761f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3762f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final AtomicInteger scrollDist = new AtomicInteger(0); 3763f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3764f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3765f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3766f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar detachAndScrapAttachedViews(recycler); 3767f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final View view = recycler.getViewForPosition(0); 3768f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar addView(view); 3769f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar measureChildWithMargins(view, 0, 0); 3770f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar view.layout(0, -20, view.getWidth(), 3771f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar -20 + view.getHeight());// ignore decors on purpose 3772f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar layoutLatch.countDown(); 3773f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3774f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3775f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3776f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public boolean canScrollVertically() { 3777f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return true; 3778f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3779f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3780f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3781f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 3782f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3783f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar scrollDist.addAndGet(dy); 3784f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return dy; 3785f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3786f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }; 3787f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestAdapter adapter = new TestAdapter(10); 3788f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar if (addItemDecors) { 3789f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.addItemDecoration(new RecyclerView.ItemDecoration() { 3790f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3791f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 3792f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3793f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar outRect.set(0, 10, 0, 10); 3794f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3795f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }); 3796f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3797f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setAdapter(adapter); 3798f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setLayoutManager(tlm); 3799f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.expectLayouts(1); 3800f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar setRecyclerView(rv); 3801f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.waitForLayout(2); 3802f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3803f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar View view = rv.getChildAt(0); 3804959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar requestFocus(view, true); 3805f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar assertEquals(addItemDecors ? -30 : -20, scrollDist.get()); 3806f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3807f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3808e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 38090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void unimplementedSmoothScroll() throws Throwable { 3810e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1); 3811e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1); 3812e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final CountDownLatch cbLatch = new CountDownLatch(2); 3813e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3814e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3815e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3816e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 3817e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, 0, 10); 3818e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 3819e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3820e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3821e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3822e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 3823e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int position) { 3824e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedSmoothScrollToPosition.get()); 3825e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedSmoothScrollToPosition.set(position); 3826e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 3827e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 3828e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3829e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 3830e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return null; 3831e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3832e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3833e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 3834e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 3835e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3836e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3837e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3838e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3839e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 3840e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedScrollToPosition.get()); 3841e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPosition.set(position); 3842e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3843e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3844e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3845e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3846e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(new TestAdapter(100)); 3847e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 3848e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 3849e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 3850e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 3851ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 3852959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar smoothScrollToPosition(35, false); 3853ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("smoothScrollToPosition should be ignored when frozen", 3854ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu -1, receivedSmoothScrollToPosition.get()); 3855ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 3856959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar smoothScrollToPosition(35, false); 3857e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS)); 3858e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3859e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedSmoothScrollToPosition.get()); 3860e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedScrollToPosition.get()); 3861e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3862e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3863e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 38640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScroller() throws Throwable { 3865e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(true); 3866e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3867e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3868e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 38690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScrollerGoesIdle() throws Throwable { 3870e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(false); 3871e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3872e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 38737f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Test 38747f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void testScrollByBeforeFirstLayout() throws Throwable { 38757f5e94985f795f81884334ca2752a0469a998762Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 38767f5e94985f795f81884334ca2752a0469a998762Yigit Boyar TestAdapter adapter = new TestAdapter(10); 38777f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.setLayoutManager(new TestLayoutManager() { 38787f5e94985f795f81884334ca2752a0469a998762Yigit Boyar AtomicBoolean didLayout = new AtomicBoolean(false); 38797f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 38807f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 38817f5e94985f795f81884334ca2752a0469a998762Yigit Boyar super.onLayoutChildren(recycler, state); 38827f5e94985f795f81884334ca2752a0469a998762Yigit Boyar didLayout.set(true); 38837f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 38847f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 38857f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 38867f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 38877f5e94985f795f81884334ca2752a0469a998762Yigit Boyar RecyclerView.State state) { 38887f5e94985f795f81884334ca2752a0469a998762Yigit Boyar assertThat("should run layout before scroll", 38897f5e94985f795f81884334ca2752a0469a998762Yigit Boyar didLayout.get(), CoreMatchers.is(true)); 38907f5e94985f795f81884334ca2752a0469a998762Yigit Boyar return super.scrollVerticallyBy(dy, recycler, state); 38917f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 38927f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 38937f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 38947f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public boolean canScrollVertically() { 38957f5e94985f795f81884334ca2752a0469a998762Yigit Boyar return true; 38967f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 38977f5e94985f795f81884334ca2752a0469a998762Yigit Boyar }); 38987f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.setAdapter(adapter); 38997f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39007f5e94985f795f81884334ca2752a0469a998762Yigit Boyar runTestOnUiThread(new Runnable() { 39017f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 39027f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void run() { 39037f5e94985f795f81884334ca2752a0469a998762Yigit Boyar try { 39047f5e94985f795f81884334ca2752a0469a998762Yigit Boyar setRecyclerView(recyclerView); 39057f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.scrollBy(10, 19); 39067f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } catch (Throwable throwable) { 39077f5e94985f795f81884334ca2752a0469a998762Yigit Boyar postExceptionToInstrumentation(throwable); 39087f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39097f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39107f5e94985f795f81884334ca2752a0469a998762Yigit Boyar }); 39117f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39127f5e94985f795f81884334ca2752a0469a998762Yigit Boyar checkForMainThreadException(); 39137f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39147f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 3915e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable { 3916e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final List<Integer> receivedScrollToPositions = new ArrayList<>(); 3917e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final TestAdapter testAdapter = new TestAdapter(200); 3918e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicBoolean mTargetFound = new AtomicBoolean(false); 3919e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3920e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int pendingScrollPosition = -1; 3921e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3922e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3923e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 3924e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition; 3925e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, pos, pos + 10); 3926e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (layoutLatch != null) { 3927e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 3928e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3929e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3930e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3931e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3932e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 3933e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int position) { 3934e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 3935e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 3936e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3937e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 3938e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return new PointF(0, 1); 3939e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3940e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3941e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3942e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void onTargetFound(View targetView, RecyclerView.State state, 3943e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Action action) { 3944e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar super.onTargetFound(targetView, state, action); 3945e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar mTargetFound.set(true); 3946e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3947e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3948e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3949e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void updateActionForInterimTarget(Action action) { 3950e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = succeed ? getTargetPosition() : 100; 3951e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition + 2 < limit) { 3952e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition != NO_POSITION) { 3953e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(pendingScrollPosition, 3954e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar getChildViewHolderInt(getChildAt(0)) 3955e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar .getAdapterPosition()); 3956e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3957e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar action.jumpTo(pendingScrollPosition + 2); 3958e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3959e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3960e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3961e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 3962e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 3963e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3964e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3965e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3966e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 3967e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPositions.add(position); 3968e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar pendingScrollPosition = position; 3969e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar requestLayout(); 3970e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3971e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3972e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 3973e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(testAdapter); 3974e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 3975e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3976e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 3977e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 3978e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 3979e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3980e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar runTestOnUiThread(new Runnable() { 3981e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3982e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void run() { 3983e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.smoothScrollToPosition(150); 3984e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3985e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }); 3986e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = 100; 3987e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) { 3988e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Thread.sleep(200); 3989e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3990e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3991e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3992e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue(limit > 0); 3993e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar for (int i = 1; i < 100; i+=2) { 3994e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i)); 3995e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3996e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3997e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(succeed, mTargetFound.get()); 3998e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3999e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4000e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 40010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestViewHolder2 extends RecyclerView.ViewHolder { 4002824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 4003824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar Object mData; 4004824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 40050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2(View itemView) { 40060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super(itemView); 40070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 4009d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 40100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> { 4011824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 40120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar List<Item> mItems; 40130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 40140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private TestAdapter2(int count) { 40150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems = new ArrayList<Item>(count); 40160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar for (int i = 0; i < count; i++) { 40170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems.add(new Item(i, "Item " + i)); 40180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40200b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 40210b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 40220b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 40230b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar int viewType) { 40240b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return new TestViewHolder2(new TextView(parent.getContext())); 40250b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40260b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 40270b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 40280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 40290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final Item item = mItems.get(position); 40300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")"); 40310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 40330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 40340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public int getItemCount() { 40350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return mItems.size(); 40360b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 4037d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 4038d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 4039e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public interface AdapterRunnable { 40401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 40413d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar void run(TestAdapter adapter) throws Throwable; 4042115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 4043115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 40443d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public class LayoutAllLayoutManager extends TestLayoutManager { 40453d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 40463d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 40473d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 40483d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutLatch.countDown(); 40493d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 40503d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4051bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4052bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar /** 4053bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar * Proxy class to make protected methods public 4054bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar */ 4055bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public static class TestRecyclerView extends RecyclerView { 4056bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4057bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context) { 4058bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context); 4059bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4060bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4061bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context, @Nullable AttributeSet attrs) { 4062bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context, attrs); 4063bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4064bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4065bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 4066bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context, attrs, defStyle); 4067bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4068bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4069bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 4070bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void detachViewFromParent(int index) { 4071bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super.detachViewFromParent(index); 4072bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4073bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4074bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 4075bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void attachViewToParent(View child, int index, ViewGroup.LayoutParams params) { 4076bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super.attachViewToParent(child, index, params); 4077bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4078bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 40794510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 40804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar private static interface ViewRunnable { 40814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar void run(View view) throws RuntimeException; 40824510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 40837a59e4b36500bcfddd842376d6c3abe0d9f23d84Yigit Boyar} 4084