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 5644be551523e8e36b5a1d480af456bfb392416882cYigit Boyar public void testFocusSearchAfterChangedData() throws Throwable { 5654be551523e8e36b5a1d480af456bfb392416882cYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 5664be551523e8e36b5a1d480af456bfb392416882cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 5674be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Override 5684be551523e8e36b5a1d480af456bfb392416882cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 5694be551523e8e36b5a1d480af456bfb392416882cYigit Boyar layoutRange(recycler, 0, 2); 5704be551523e8e36b5a1d480af456bfb392416882cYigit Boyar layoutLatch.countDown(); 5714be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 5724be551523e8e36b5a1d480af456bfb392416882cYigit Boyar 5734be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Nullable 5744be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Override 5754be551523e8e36b5a1d480af456bfb392416882cYigit Boyar public View onFocusSearchFailed(View focused, int direction, 5764be551523e8e36b5a1d480af456bfb392416882cYigit Boyar RecyclerView.Recycler recycler, 5774be551523e8e36b5a1d480af456bfb392416882cYigit Boyar RecyclerView.State state) { 5784be551523e8e36b5a1d480af456bfb392416882cYigit Boyar try { 5794be551523e8e36b5a1d480af456bfb392416882cYigit Boyar View view = recycler.getViewForPosition(state.getItemCount() - 1); 5804be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } catch (Throwable t) { 5814be551523e8e36b5a1d480af456bfb392416882cYigit Boyar postExceptionToInstrumentation(t); 5824be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 5834be551523e8e36b5a1d480af456bfb392416882cYigit Boyar return null; 5844be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 5854be551523e8e36b5a1d480af456bfb392416882cYigit Boyar }; 5864be551523e8e36b5a1d480af456bfb392416882cYigit Boyar recyclerView.setLayoutManager(tlm); 5874be551523e8e36b5a1d480af456bfb392416882cYigit Boyar final TestAdapter adapter = new TestAdapter(10) { 5884be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Override 5894be551523e8e36b5a1d480af456bfb392416882cYigit Boyar public void onBindViewHolder(TestViewHolder holder, int position) { 5904be551523e8e36b5a1d480af456bfb392416882cYigit Boyar super.onBindViewHolder(holder, position); 5914be551523e8e36b5a1d480af456bfb392416882cYigit Boyar holder.itemView.setFocusable(false); 5924be551523e8e36b5a1d480af456bfb392416882cYigit Boyar holder.itemView.setFocusableInTouchMode(false); 5934be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 5944be551523e8e36b5a1d480af456bfb392416882cYigit Boyar }; 5954be551523e8e36b5a1d480af456bfb392416882cYigit Boyar recyclerView.setAdapter(adapter); 5964be551523e8e36b5a1d480af456bfb392416882cYigit Boyar tlm.expectLayouts(1); 5974be551523e8e36b5a1d480af456bfb392416882cYigit Boyar setRecyclerView(recyclerView); 5984be551523e8e36b5a1d480af456bfb392416882cYigit Boyar tlm.waitForLayout(1); 5994be551523e8e36b5a1d480af456bfb392416882cYigit Boyar runTestOnUiThread(new Runnable() { 6004be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Override 6014be551523e8e36b5a1d480af456bfb392416882cYigit Boyar public void run() { 6024be551523e8e36b5a1d480af456bfb392416882cYigit Boyar adapter.mItems.remove(9); 6034be551523e8e36b5a1d480af456bfb392416882cYigit Boyar adapter.notifyItemRemoved(9); 6044be551523e8e36b5a1d480af456bfb392416882cYigit Boyar recyclerView.focusSearch(recyclerView.getChildAt(1), View.FOCUS_DOWN); 6054be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 6064be551523e8e36b5a1d480af456bfb392416882cYigit Boyar }); 6074be551523e8e36b5a1d480af456bfb392416882cYigit Boyar checkForMainThreadException(); 6084be551523e8e36b5a1d480af456bfb392416882cYigit Boyar } 6094be551523e8e36b5a1d480af456bfb392416882cYigit Boyar 6104be551523e8e36b5a1d480af456bfb392416882cYigit Boyar @Test 6113e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar public void testFocusSearchWithRemovedFocusedItem() throws Throwable { 6123e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 6133e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar recyclerView.setItemAnimator(null); 6143e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar TestLayoutManager tlm = new LayoutAllLayoutManager(); 6153e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar recyclerView.setLayoutManager(tlm); 6163e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar final TestAdapter adapter = new TestAdapter(10) { 6173e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar @Override 6183e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar public void onBindViewHolder(TestViewHolder holder, int position) { 6193e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar super.onBindViewHolder(holder, position); 6203e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar holder.itemView.setFocusable(true); 6213e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar holder.itemView.setFocusableInTouchMode(true); 6223e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar } 6233e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar }; 6243e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar recyclerView.setAdapter(adapter); 6253e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar tlm.expectLayouts(1); 6263e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar setRecyclerView(recyclerView); 6273e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar tlm.waitForLayout(1); 6283e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar final RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(9); 6293e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar requestFocus(toFocus.itemView, true); 6303e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar assertThat("test sanity", toFocus.itemView.hasFocus(), is(true)); 6313e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar runTestOnUiThread(new Runnable() { 6323e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar @Override 6333e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar public void run() { 6343e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar adapter.mItems.remove(9); 6353e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar adapter.notifyItemRemoved(9); 6363e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar recyclerView.focusSearch(toFocus.itemView, View.FOCUS_DOWN); 6373e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar } 6383e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar }); 6393e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar checkForMainThreadException(); 6403e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar } 6413e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar 6423e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar 6433e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar @Test 6447bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar public void testFocusSearchFailFrozen() throws Throwable { 645ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 6467bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar final CountDownLatch focusLatch = new CountDownLatch(1); 647ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 648ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 649ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 650ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 651ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 652ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 653ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 654ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 655ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 656ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 657ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 658ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 659ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 660ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 661ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 662ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 663ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 664ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 665ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 666121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar public View onFocusSearchFailed(View focused, int direction, 667121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state) { 668ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 6697bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar focusLatch.countDown(); 670ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 671ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 672ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 673ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 674ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 675ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 676ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 677ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 678ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 679ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1); 680959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", requestFocus(c, true)); 681959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", c.hasFocus()); 682ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 6834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar focusSearch(recyclerView, c, View.FOCUS_DOWN); 684ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("onFocusSearchFailed should not be called when layout is frozen", 685ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 0, focusSearchCalled.get()); 686ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 687d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar focusSearch(c, View.FOCUS_DOWN); 6887bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar assertTrue(focusLatch.await(2, TimeUnit.SECONDS)); 689ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(1, focusSearchCalled.get()); 690ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 691ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 692d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar public View focusSearch(final ViewGroup parent, final View focused, final int direction) 6934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar throws Throwable { 694d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar final View[] result = new View[1]; 6954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar runTestOnUiThread(new Runnable() { 6964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Override 6974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void run() { 698d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar result[0] = parent.focusSearch(focused, direction); 6994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 7004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar }); 701d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar return result[0]; 7024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 7034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 704ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 7050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void frozenAndChangeAdapter() throws Throwable { 706ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView recyclerView = new RecyclerView(getActivity()); 707ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 708ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu final AtomicInteger focusSearchCalled = new AtomicInteger(0); 709ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestLayoutManager tlm = new TestLayoutManager() { 710ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 711ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollHorizontally() { 712ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 713ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 714ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 715ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 716ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public boolean canScrollVertically() { 717ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return true; 718ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 719ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 720ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 721ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 722ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutRange(recycler, 0, 10); 723ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu layoutLatch.countDown(); 724ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 725ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 726ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Override 727ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler, 728ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu RecyclerView.State state) { 729ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu focusSearchCalled.addAndGet(1); 730ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu return null; 731ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 732ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu }; 733ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter = new TestAdapter(100); 734ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setAdapter(adapter); 735ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu recyclerView.setLayoutManager(tlm); 736ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.expectLayouts(1); 737ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setRecyclerView(recyclerView); 738ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.waitForLayout(2); 739ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 740ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 741ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter2 = new TestAdapter(1000); 742ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setAdapter(adapter2); 743ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 744ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter2, recyclerView.getAdapter()); 745ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 746ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 747ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu TestAdapter adapter3 = new TestAdapter(1000); 748ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu swapAdapter(adapter3, true); 749ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertFalse(recyclerView.isLayoutFrozen()); 750ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertSame(adapter3, recyclerView.getAdapter()); 751ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 752ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 753ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu @Test 7548fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreChanged() throws Throwable { 7558fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7568fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7578fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7588fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeChanged(3, 0); 7598fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7608fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7618fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7628fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7638fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7648fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreChangedWithPayload() throws Throwable { 7658fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7668fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7678fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7688fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeChanged(0, 0, new Object()); 7698fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7708fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7718fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7728fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7738fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7748fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreAdded() throws Throwable { 7758fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7768fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7778fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7788fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeInserted(3, 0); 7798fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7808fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7818fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7828fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7838fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7848fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIf0ItemsAreRemoved() throws Throwable { 7858fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7868fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7878fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7888fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemRangeRemoved(3, 0); 7898fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7908fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 7918fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 7928fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 7938fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 7948fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void noLayoutIfItemMovedIntoItsOwnPlace() throws Throwable { 7958fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar unnecessaryNotifyEvents(new AdapterRunnable() { 7968fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 7978fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run(TestAdapter adapter) throws Throwable { 7988fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar adapter.notifyItemMoved(3, 3); 7998fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8008fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 8018fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8028fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 8038fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void unnecessaryNotifyEvents(final AdapterRunnable action) throws Throwable { 8048fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 8058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar final TestAdapter adapter = new TestAdapter(5); 8068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 8078fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 8088fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 8098fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar super.onLayoutChildren(recycler, state); 8108fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar layoutLatch.countDown(); 8118fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8128fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }; 8138fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar recyclerView.setLayoutManager(tlm); 8148fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar recyclerView.setAdapter(adapter); 8158fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.expectLayouts(1); 8168fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar setRecyclerView(recyclerView); 8178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.waitForLayout(1); 8188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar // ready 8198fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.expectLayouts(1); 8208fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar runTestOnUiThread(new Runnable() { 8218fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Override 8228fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar public void run() { 8238fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar try { 8248fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar action.run(adapter); 8258fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } catch (Throwable throwable) { 8268fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar postExceptionToInstrumentation(throwable); 8278fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8288fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar }); 8308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar tlm.assertNoLayout("dummy event should not trigger a layout", 1); 8318fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar checkForMainThreadException(); 8328fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar } 8338fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar 8348fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar @Test 8350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollToPositionCallback() throws Throwable { 8364965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 8374965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 8384965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar int scrollPos = RecyclerView.NO_POSITION; 8391a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 8404965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 8414965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 8424965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutLatch.countDown(); 8434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar if (scrollPos == RecyclerView.NO_POSITION) { 8444965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, 0, 10); 8454965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } else { 8464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar layoutRange(recycler, scrollPos, scrollPos + 10); 8474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 8484965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 8491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 8504965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 8514965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void scrollToPosition(int position) { 8524965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollPos = position; 8534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayout(); 8544965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 8554965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }; 8564965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setLayoutManager(tlm); 8574965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar TestAdapter adapter = new TestAdapter(100); 8584965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setAdapter(adapter); 8594965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger rvCounter = new AtomicInteger(0); 8604965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar final AtomicInteger viewGroupCounter = new AtomicInteger(0); 8614965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.getViewTreeObserver().addOnScrollChangedListener( 8624965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar new ViewTreeObserver.OnScrollChangedListener() { 8634965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 8644965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrollChanged() { 8654965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.incrementAndGet(); 8664965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 8674965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 8684965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 8694965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar @Override 8704965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 8714965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar rvCounter.incrementAndGet(); 8724965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar super.onScrolled(recyclerView, dx, dy); 8734965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 8744965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar }); 8754965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 8763f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 8774965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar setRecyclerView(recyclerView); 8784965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 8793f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 8803f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 8813f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar 8823f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get()); 8833f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called for initialization", 1, 8844965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar viewGroupCounter.get()); 8854965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 886ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 887ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu scrollToPosition(3); 888ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu tlm.assertNoLayout("scrollToPosition should be ignored", 2); 889ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 8904965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar scrollToPosition(3); 8914965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 8923f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("RV on scroll should be called", 2, rvCounter.get()); 8933f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get()); 8944965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.expectLayouts(1); 8954965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar requestLayoutOnUIThread(recyclerView); 8964965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar tlm.waitForLayout(2); 8973f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar // wait for draw :/ 8983f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar Thread.sleep(1000); 8994965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, rvCounter.get()); 9004965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get()); 901e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 902e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 903e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 904e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeExpand() throws Throwable { 905e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{3, 6}); 906e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 907e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 908e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 909e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeShrink() throws Throwable { 910e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{3, 5}); 911e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 912e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 913e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 914e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeExpand2() throws Throwable { 915e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{2, 5}); 916e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 917e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 918e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Test 919e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void scrollCalllbackOnVisibleRangeShrink2() throws Throwable { 920e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{2, 6}); 921e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 922e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 923e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar private void scrollCallbackOnVisibleRangeChange(int itemCount, final int[] beforeRange, 924e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final int[] afterRange) throws Throwable { 925e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 926e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final AtomicBoolean beforeState = new AtomicBoolean(true); 927e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 928e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar @Override 929e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 930e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar detachAndScrapAttachedViews(recycler); 931e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar int[] range = beforeState.get() ? beforeRange : afterRange; 932e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar layoutRange(recycler, range[0], range[1]); 933e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar layoutLatch.countDown(); 934e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar } 935e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar }; 936e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.setLayoutManager(tlm); 937e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar final TestAdapter adapter = new TestAdapter(itemCount); 938e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.setAdapter(adapter); 939e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.expectLayouts(1); 940e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar setRecyclerView(recyclerView); 941e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.waitForLayout(1); 942e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar 943e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar RecyclerView.OnScrollListener mockListener = mock(RecyclerView.OnScrollListener.class); 944e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar recyclerView.addOnScrollListener(mockListener); 945e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar verify(mockListener, never()).onScrolled(any(RecyclerView.class), anyInt(), anyInt()); 9464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar 947e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.expectLayouts(1); 948e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar beforeState.set(false); 949e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar requestLayoutOnUIThread(recyclerView); 950e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar tlm.waitForLayout(2); 951e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar checkForMainThreadException(); 952e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar verify(mockListener).onScrolled(recyclerView, 0, 0); 9534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar } 954670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 955be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 9562e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void addItemOnScroll() throws Throwable { 9572e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 9582e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final AtomicInteger start = new AtomicInteger(0); 9592e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 9602e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Override 9612e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 9622e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar layoutRange(recycler, start.get(), start.get() + 10); 9632e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar layoutLatch.countDown(); 9642e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9652e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar }; 9662e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.setLayoutManager(tlm); 9672e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final TestAdapter adapter = new TestAdapter(100); 9682e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.setAdapter(adapter); 9692e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.expectLayouts(1); 9702e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar setRecyclerView(recyclerView); 9712e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.waitForLayout(1); 9722e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final Throwable[] error = new Throwable[1]; 9732e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar final AtomicBoolean calledOnScroll = new AtomicBoolean(false); 9742e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 9752e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Override 9762e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 9772e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar super.onScrolled(recyclerView, dx, dy); 9782e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar calledOnScroll.set(true); 9792e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar try { 9802e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar adapter.addAndNotify(5, 20); 9812e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } catch (Throwable throwable) { 9822e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar error[0] = throwable; 9832e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9842e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9852e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar }); 9862e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar start.set(4); 9872e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(false)); 9882e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.expectLayouts(1); 9892e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar requestLayoutOnUIThread(recyclerView); 9902e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar tlm.waitForLayout(2); 9912e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar checkForMainThreadException(); 9922e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(true)); 9932e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar MatcherAssert.assertThat(error[0], CoreMatchers.nullValue()); 9942e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar } 9952e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar 9962e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar @Test 9970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqual() throws Throwable { 998670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, 1000, 1000); 999670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1000670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1001be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVertical() throws Throwable { 1003670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, 1000, 1000); 1004670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1005670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1006be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontal() throws Throwable { 1008670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, 1000, 1000); 1009670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1010670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1011be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnly() throws Throwable { 1013670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, 1000, 0); 1014670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1015670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1016be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnly() throws Throwable { 1018670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, 1000); 1019670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1020670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1021be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionEqualReverse() throws Throwable { 1023670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 3, -1000, -1000); 1024670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1025670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1026be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreVerticalReverse() throws Throwable { 1028670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(2, 3, -1000, -1000); 1029670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1030670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1031be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable { 1033670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 2, -1000, -1000); 1034670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1035670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1036be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollHorizontalOnlyReverse() throws Throwable { 1038670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(3, 0, -1000, 0); 1039670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1040670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1041be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 10420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollVerticalOnlyReverse() throws Throwable { 1043670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrollInBothDirection(0, 3, 0, -1000); 1044670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1045670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1046670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount, 1047670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar int horizontalVelocity, int verticalVelocity) 1048670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar throws Throwable { 1049670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1050670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount); 1051670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount); 1052670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1053670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1054670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 1055670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 1056670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1057670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1058670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1059670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 1060670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 1061670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1062670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1063670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1064670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1065670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 1066670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 1067670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1068670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1069670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1070670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 1071670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1072670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (verticalCounter.get() > 0) { 1073670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.decrementAndGet(); 1074670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dy; 1075670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1076670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 1077670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1078670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1079670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1080670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 1081670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1082670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (horizontalCounter.get() > 0) { 1083670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.decrementAndGet(); 1084670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return dx; 1085670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1086670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return 0; 1087670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1088670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 1089670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 1090670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 1091670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 1092670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 1093670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 1094670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 1095670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity)); 1096670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0, 1097670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar horizontalCounter.get()); 1098670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0, 1099670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar verticalCounter.get()); 1100670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1101670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1102be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragHorizontal() throws Throwable { 1104cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL); 1105670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1106670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1107be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dragVertical() throws Throwable { 1109cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL); 1110670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1111670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1112be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingHorizontal() throws Throwable { 1114cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING); 1115670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1116670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1117be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 11180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void flingVertical() throws Throwable { 1119cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING); 1120670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1121670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1122f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 11230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVertical() throws Throwable { 1124a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1125f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1126f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1127cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 1128f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1129f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1130f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes @Test 11310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontal() throws Throwable { 1132a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1133f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1134f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1135cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 1136f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1137670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1138d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 11390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragHorizontalCallsStopNestedScroll() throws Throwable { 1140a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1141d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1142d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1143d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0); 1144d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 1145d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 1146d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 1147d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes @Test 11480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void nestedDragVerticalCallsStopNestedScroll() throws Throwable { 1149a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar TestedFrameLayout tfl = getActivity().getContainer(); 1150d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1151d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME); 1152d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes scrollInOtherOrientationTest(FLAG_VERTICAL, 0); 1153d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled()); 1154d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes } 1155d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes 1156cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(int flags) 1157f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes throws Throwable { 1158364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar scrollInOtherOrientationTest(flags, flags); 1159f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } 1160f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1161cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable { 1162670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1163670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false); 1164670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean scrolledVertical = new AtomicBoolean(false); 1165f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes 1166f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes final TestLayoutManager tlm = new TestLayoutManager() { 1167670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1168670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollHorizontally() { 1169cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_HORIZONTAL) != 0; 1170670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1171670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1172670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1173670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public boolean canScrollVertically() { 1174cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar return (flags & FLAG_VERTICAL) != 0; 1175670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1176670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1177670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1178670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1179670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutRange(recycler, 0, 10); 1180670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar layoutLatch.countDown(); 1181670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1182670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1183670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1184670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 1185670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1186670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledVertical.set(true); 1187f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollVerticallyBy(dy, recycler, state); 1188670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1189670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1190670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1191670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 1192670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar RecyclerView.State state) { 1193670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar scrolledHorizontal.set(true); 1194f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes return super.scrollHorizontallyBy(dx, recycler, state); 1195670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1196670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }; 1197670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar TestAdapter adapter = new TestAdapter(100); 1198670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setAdapter(adapter); 1199670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar recyclerView.setLayoutManager(tlm); 1200670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.expectLayouts(1); 1201670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar setRecyclerView(recyclerView); 1202670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar tlm.waitForLayout(2); 1203cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar if ( (flags & FLAG_FLING) != 0 ) { 1204cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar int flingVelocity = (mRecyclerView.getMaxFlingVelocity() + 1205cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getMinFlingVelocity()) / 2; 1206cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0, 1207cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar fling(flingVelocity, flingVelocity)); 1208f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes } else { // drag 12090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP, 1210cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2); 1211670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1212f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount, 1213cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get()); 1214f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount, 1215cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get()); 1216670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1217670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1218670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar private boolean fling(final int velocityX, final int velocityY) throws Throwable { 1219670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar final AtomicBoolean didStart = new AtomicBoolean(false); 1220670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar runTestOnUiThread(new Runnable() { 1221670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar @Override 1222670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar public void run() { 1223670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar boolean result = mRecyclerView.fling(velocityX, velocityY); 1224670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar didStart.set(result); 1225670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1226670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar }); 1227670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar if (!didStart.get()) { 1228670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return false; 1229670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1230959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar waitForIdleScroll(mRecyclerView); 1231670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar return true; 1232670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar } 1233670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar 1234959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar private void assertPendingUpdatesAndLayoutTest(final AdapterRunnable runnable) throws Throwable { 1235959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1236959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1237959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1238959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 1239959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar layoutManager.expectLayouts(1); 1240da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar runTestOnUiThread(new Runnable() { 1241da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1242da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 1243959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar try { 1244959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar runnable.run(testAdapter); 1245959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } catch (Throwable throwable) { 1246959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar fail("runnable has thrown an exception"); 1247959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1248da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 1249da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1250da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1251959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar layoutManager.waitForLayout(1); 1252da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 1253959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar checkForMainThreadException(); 1254da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1255da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1256da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm, 1257da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter adapter, boolean waitForFirstLayout) throws Throwable { 1258da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setLayoutManager(tlm); 1259da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setAdapter(adapter); 1260da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar if (waitForFirstLayout) { 1261da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.expectLayouts(1); 1262da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 1263da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar tlm.waitForLayout(1); 1264da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } else { 1265da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 1266da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1267da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1268da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1269be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void hasPendingUpdatesBeforeFirstLayout() throws Throwable { 1271da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1272da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1273da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1274da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, false); 1275da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue(mRecyclerView.hasPendingAdapterUpdates()); 1276da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1277da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1278be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 12790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noPendingUpdatesAfterLayout() throws Throwable { 1280da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1281da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestLayoutManager layoutManager = new DumbLayoutManager(); 1282da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1283da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setupBasic(recyclerView, layoutManager, testAdapter, true); 1284da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertFalse(mRecyclerView.hasPendingAdapterUpdates()); 1285da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1286da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1287be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 1288959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsRemoved() throws Throwable { 1289959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1290da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1291959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1292959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.deleteAndNotify(1, 1); 1293da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1294da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1295959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1296959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1297959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsInserted() throws Throwable { 1298959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1299da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1300959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1301959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.addAndNotify(2, 1); 1302da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1303da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1304959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1305959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1306959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsMoved() throws Throwable { 1307959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1308da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1309959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1310959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.moveItem(2, 3, true); 1311da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1312da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1313959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1314959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1315959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterItemIsChanged() throws Throwable { 1316959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1317da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1318959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) throws Throwable { 1319959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar testAdapter.changeAndNotify(2, 1); 1320da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1321da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1322959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar } 1323959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar @Test 1324959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void hasPendingUpdatesAfterDataSetIsChanged() throws Throwable { 1325959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertPendingUpdatesAndLayoutTest(new AdapterRunnable() { 1326da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 1327959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar public void run(TestAdapter testAdapter) { 1328959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 1329da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1330da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 1331da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 1332da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 1333be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaAdapter() throws Throwable { 1335e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(true, false); 1336e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1337e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1338be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateRecycleViaTransientStateCleanup() throws Throwable { 1340e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, true); 1341e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1342e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1343be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 13440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void transientStateDontRecycle() throws Throwable { 1345e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar transientStateRecycleTest(false, false); 1346e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1347e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1348e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState) 1349e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar throws Throwable { 1350e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> failedToRecycle = new ArrayList<View>(); 1351e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar final List<View> recycled = new ArrayList<View>(); 1352e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestAdapter testAdapter = new TestAdapter(10) { 1353e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1354e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public boolean onFailedToRecycleView( 1355e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestViewHolder holder) { 1356e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar failedToRecycle.add(holder.itemView); 1357e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (unsetTransientState) { 1358e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(holder.itemView, false); 1359e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1360e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar return succeed; 1361e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1362e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1363e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1364e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 1365e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recycled.add(holder.itemView); 1366e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar super.onViewRecycled(holder); 1367e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1368e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 1369e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1370e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar @Override 1371e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1372e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (getChildCount() == 0) { 1373e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar detachAndScrapAttachedViews(recycler); 1374e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutRange(recycler, 0, 5); 1375e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } else { 1376e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar removeAndRecycleAllViews(recycler); 1377e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1378e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar if (layoutLatch != null) { 1379e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar layoutLatch.countDown(); 1380e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1381e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1382e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar }; 1383e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1384e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setAdapter(testAdapter); 1385e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setLayoutManager(tlm); 1386e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar recyclerView.setItemAnimator(null); 1387e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setRecyclerView(recyclerView); 1388e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar getInstrumentation().waitForIdleSync(); 1389e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // make sure we have enough views after this position so that we'll receive the on recycled 1390e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar // callback 1391e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar View view = recyclerView.getChildAt(3);//this has to be greater than def cache size. 1392e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar setHasTransientState(view, true); 1393e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.expectLayouts(1); 1394e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar requestLayoutOnUIThread(recyclerView); 1395e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar tlm.waitForLayout(2); 1396e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1397e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertTrue(failedToRecycle.contains(view)); 1398e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar assertEquals(succeed || unsetTransientState, recycled.contains(view)); 1399e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1400e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 1401be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionInvalidation() throws Throwable { 1403e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1404e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestAdapter adapter = new TestAdapter(10); 1405e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 1406e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 1407e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1408e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1409e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar layoutLatch.countDown(); 1410e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1411e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }; 1412e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setAdapter(adapter); 1413e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.setLayoutManager(tlm); 1414e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.expectLayouts(1); 1415e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView); 1416e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar tlm.waitForLayout(1); 1417e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar runTestOnUiThread(new Runnable() { 1418e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar @Override 1419e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar public void run() { 14201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 1421e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertNotSame("adapter positions should not be undefined", 1422e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 1423e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 1424e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1425e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar adapter.notifyDataSetChanged(); 14261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < tlm.getChildCount(); i++) { 1427e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar assertSame("adapter positions should be undefined", 1428e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar recyclerView.getChildAdapterPosition(tlm.getChildAt(i)), 1429e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar RecyclerView.NO_POSITION); 1430e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1431e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1432e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar }); 1433e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar } 1434e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 1435be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsBasic() throws Throwable { 1437115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(null); 1438115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1439115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1440be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItems() throws Throwable { 1442115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1443115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1444115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1445115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(3, 4); 1446115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1447115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1448115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1449115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1450be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsRemoveItemsBefore() throws Throwable { 1452115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1453115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1454115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1455115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.deleteAndNotify(0, 1); 1456115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1457115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1458115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1459115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1460be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsBefore() throws Throwable { 1462115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1463115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1464115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1465115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(0, 5); 1466115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1467115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1468115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1469115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1470be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsAddItemsInside() throws Throwable { 1472115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1473115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1474115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1475115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.addAndNotify(3, 2); 1476115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1477115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1478115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1479115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1480be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsMoveItems() throws Throwable { 1482115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1483115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1484115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1485115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.moveAndNotify(3, 5); 1486115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1487115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1488115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1489115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1490be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 14910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterPositionsNotifyDataSetChanged() throws Throwable { 1492115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterPositionsTest(new AdapterRunnable() { 1493115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1494115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run(TestAdapter adapter) throws Throwable { 1495115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.clear(); 14961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < 20; i++) { 1497115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.mItems.add(new Item(i, "added item")); 1498115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1499115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapter.notifyDataSetChanged(); 1500115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1501115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1502115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1503115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1504be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 15050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable { 1506619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final AtomicBoolean failedToRecycle = new AtomicBoolean(false); 1507619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 1508619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1509619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1510619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1511619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 1512619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1513619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 1514619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1515619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1516619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 1517619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1518619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public boolean onFailedToRecycleView( 1519619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestViewHolder holder) { 1520619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar failedToRecycle.set(true); 1521619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar return false; 1522619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1523619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1524619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 1525619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 1526619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1527619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 1528619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 1529619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 1530619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar runTestOnUiThread(new Runnable() { 1531619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1532619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void run() { 1533619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar ViewCompat.setHasTransientState(vh.itemView, true); 1534619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1535619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1536619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1537619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 1538619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 1539619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 1540619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 1541619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 1542619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1543619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 1544619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 1545619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1546619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1547619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 1548619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(failedToRecycle.get()); 1549619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 1550619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 1551619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1552619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 1553be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 15540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable { 1555619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 1556619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1557619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1558619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1559619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar detachAndScrapAttachedViews(recycler); 1560619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1561619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar layoutLatch.countDown(); 1562619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1563619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }; 1564619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar TestAdapter adapter = new TestAdapter(10); 1565619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setAdapter(adapter); 1566619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.setLayoutManager(tlm); 1567619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1568619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar setRecyclerView(rv); 1569619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(1); 1570619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0)); 1571619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.expectLayouts(1); 1572619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar adapter.deleteAndNotify(0, 10); 1573619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar tlm.waitForLayout(2); 1574619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar final CountDownLatch animationsLatch = new CountDownLatch(1); 1575619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar rv.getItemAnimator().isRunning( 1576619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { 1577619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar @Override 1578619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar public void onAnimationsFinished() { 1579619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar animationsLatch.countDown(); 1580619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1581619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar }); 1582619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertTrue(animationsLatch.await(2, TimeUnit.SECONDS)); 1583619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar assertNull(vh.mOwnerRecyclerView); 1584619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar checkForMainThreadException(); 1585619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar } 1586619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar 1587bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Test 1588bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void duplicateAdapterPositionTest() throws Throwable { 1589bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1590bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 1591bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1592bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1593bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar detachAndScrapAttachedViews(recycler); 1594bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 1595bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (!state.isPreLayout()) { 1596bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar while (!recycler.getScrapList().isEmpty()) { 1597bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder viewHolder = recycler.getScrapList().get(0); 1598bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar addDisappearingView(viewHolder.itemView, 0); 1599bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1600bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1601bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar layoutLatch.countDown(); 1602bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1603bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1604bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1605bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public boolean supportsPredictiveItemAnimations() { 1606bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar return true; 1607bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1608bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar }; 1609bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator(); 1610bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar animator.setSupportsChangeAnimations(true); 1611bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar animator.setChangeDuration(10000); 1612bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.setHasStableIds(true); 1613bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final TestRecyclerView recyclerView = new TestRecyclerView(getActivity()); 1614bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setLayoutManager(tlm); 1615bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setAdapter(testAdapter); 1616bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.setItemAnimator(animator); 1617bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1618bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.expectLayouts(1); 1619bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar setRecyclerView(recyclerView); 1620bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.waitForLayout(2); 1621bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1622bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.expectLayouts(2); 1623bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.mItems.get(2).mType += 2; 1624bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final int itemId = testAdapter.mItems.get(2).mId; 1625bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar testAdapter.changeAndNotify(2, 1); 1626bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.waitForLayout(2); 1627bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1628bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar runTestOnUiThread(new Runnable() { 1629bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 1630bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void run() { 1631bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat("test sanity", recyclerView.getChildCount(), CoreMatchers.is(11)); 1632bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now mangle the order and run the test 1633bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder hidden = null; 1634bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder updated = null; 1635bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar for (int i = 0; i < recyclerView.getChildCount(); i ++) { 1636bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar View view = recyclerView.getChildAt(i); 1637bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 1638bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (vh.getAdapterPosition() == 2) { 1639bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (mRecyclerView.mChildHelper.isHidden(view)) { 1640bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(hidden, CoreMatchers.nullValue()); 1641bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar hidden = vh; 1642bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } else { 1643bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(updated, CoreMatchers.nullValue()); 1644bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar updated = vh; 1645bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1646bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1647bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1648bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(hidden, CoreMatchers.notNullValue()); 1649bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(updated, CoreMatchers.notNullValue()); 1650bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1651bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.eatRequestLayout(); 1652bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1653bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // first put the hidden child back 1654bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int index1 = mRecyclerView.indexOfChild(hidden.itemView); 1655bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int index2 = mRecyclerView.indexOfChild(updated.itemView); 1656bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index1 < index2) { 1657bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // swap views 1658bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar swapViewsAtIndices(recyclerView, index1, index2); 1659bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1660bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView)); 1661bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1662bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1663bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1664bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1665bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1666bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1667bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1668bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1669bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now swap back 1670bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar swapViewsAtIndices(recyclerView, index1, index2); 1671bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1672bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView)); 1673bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1674bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1675bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1676bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1677bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1678bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(updated)); 1679bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1680bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // now remove updated. re-assert fallback to the hidden one 1681bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar tlm.removeView(updated.itemView); 1682bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1683bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(tlm.findViewByPosition(2), CoreMatchers.nullValue()); 1684bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForAdapterPosition(2), 1685bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1686bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForLayoutPosition(2), 1687bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1688bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar assertThat(recyclerView.findViewHolderForItemId(itemId), 1689bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar CoreMatchers.sameInstance(hidden)); 1690bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1691bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar }); 1692bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1693bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1694bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1695bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar private void swapViewsAtIndices(TestRecyclerView recyclerView, int index1, int index2) { 1696bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index1 == index2) { 1697bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar return; 1698bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1699bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (index2 < index1) { 1700bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar int tmp = index1; 1701bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar index1 = index2; 1702bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar index2 = tmp; 1703bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1704bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final View v1 = recyclerView.getChildAt(index1); 1705bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar final View v2 = recyclerView.getChildAt(index2); 1706bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar boolean v1Hidden = recyclerView.mChildHelper.isHidden(v1); 1707bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar boolean v2Hidden = recyclerView.mChildHelper.isHidden(v2); 1708bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar // must unhide before swap otherwise bucket indices will become invalid. 1709bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v1Hidden) { 1710bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.unhide(v1); 1711bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1712bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v2Hidden) { 1713bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.unhide(v2); 1714bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1715bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.detachViewFromParent(index2); 1716bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.attachViewToParent(v2, index1, v2.getLayoutParams()); 1717bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.detachViewFromParent(index1 + 1); 1718bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar recyclerView.attachViewToParent(v1, index2, v1.getLayoutParams()); 1719bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1720bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v1Hidden) { 1721bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.hide(v1); 1722bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1723bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar if (v2Hidden) { 1724bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar mRecyclerView.mChildHelper.hide(v2); 1725bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1726bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 1727bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 1728115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable { 1729115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 1730115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 1731115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1732115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1733115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 1734115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutRange(recycler, Math.min(state.getItemCount(), 2) 1735115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , Math.min(state.getItemCount(), 7)); 1736115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutLatch.countDown(); 1737115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 1738115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 1739115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1740115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1741115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }; 1742115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 1743115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setLayoutManager(tlm); 1744115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.setAdapter(testAdapter); 1745115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.expectLayouts(1); 1746115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar setRecyclerView(recyclerView); 1747115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tlm.waitForLayout(1); 1748115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar runTestOnUiThread(new Runnable() { 1749115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar @Override 1750115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public void run() { 1751115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar try { 1752115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int count = recyclerView.getChildCount(); 1753115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar Map<View, Integer> layoutPositions = new HashMap<View, Integer>(); 1754115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertTrue("test sanity", count > 0); 17551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (int i = 0; i < count; i++) { 1756115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1757115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view); 1758115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1759115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " + index, vh, 1760115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1761115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("get adapter position should return correct index", index, 1762115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1763115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.put(view, vh.mPosition); 1764115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1765115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (adapterChanges != null) { 1766115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar adapterChanges.run(testAdapter); 1767115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar for (int i = 0; i < count; i++) { 1768115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar View view = recyclerView.getChildAt(i); 1769115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar TestViewHolder vh = (TestViewHolder) recyclerView 1770115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar .getChildViewHolder(view); 1771115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int index = testAdapter.mItems.indexOf(vh.mBoundItem); 1772115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (index >= 0) { 1773115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertEquals("should be able to find VH with adapter position " 17741a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar + index, vh, 1775115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar recyclerView.findViewHolderForAdapterPosition(index)); 1776115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1777115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("get adapter position should return correct index", index, 1778115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh.getAdapterPosition()); 1779115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar assertSame("should be able to find view with layout position", 1780115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar vh, mRecyclerView.findViewHolderForLayoutPosition( 1781115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar layoutPositions.get(view))); 1782115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1783115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1784115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1785115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 1786115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } catch (Throwable t) { 1787115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar postExceptionToInstrumentation(t); 1788115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1789115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 1790115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar }); 1791115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar checkForMainThreadException(); 1792e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar } 1793e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar 1794be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 17950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScroll() throws Throwable { 1796bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1797bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1798bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1799bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1800bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1801bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1802bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1803bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1804bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1805bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1806bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1807bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1808bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1809bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1810bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1811bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1812bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1813bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1814bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1815bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1816bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1817bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1818bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1819bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1820bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1821bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1822bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1823bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1824bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1825be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForSmoothScrollWithStop() throws Throwable { 1827bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1828bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1829bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1830bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1831bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1832bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1833bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1834bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1835bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1836bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1837bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1838bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1839bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1840bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1841bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1842bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1843bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1844bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1845bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1846bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1847bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.smoothScrollBy(0, 500); 1848bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1849bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1850bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1851bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1852bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1853bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1854bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1855bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1856bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1857bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1858bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1859bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1860bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1861bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1862bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1863be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFling() throws Throwable { 1865bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1866bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1867bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1868bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1869bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1870bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1871bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1872bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1873bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1874bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(2); 1875bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1876bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1877bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1878bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1879bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1880bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1881bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1882bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1883bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1884bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f; 1885bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1886bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1887bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1888bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1889bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1890bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1891bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1892bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1893bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1894bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1895bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1896bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1897be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 18980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateForFlingWithStop() throws Throwable { 1899bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1900bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1901bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1902bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1903bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1904bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1905bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1906bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1907bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1908bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final CountDownLatch latch = new CountDownLatch(1); 1909bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1910bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1911bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1912bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1913bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.countDown(); 1914bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1915bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1916bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final ViewConfiguration vc = ViewConfiguration.get(getActivity()); 1917bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final float fling = vc.getScaledMinimumFlingVelocity() 1918bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f; 1919bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1920bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1921bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1922bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.fling(0, Math.round(fling)); 1923bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1924bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1925bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar latch.await(5, TimeUnit.SECONDS); 1926bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1927bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1928bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1929bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar mRecyclerView.stopScroll(); 1930bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1931bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1932bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1933bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]); 1934bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1935bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]); 1936bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1937bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1938be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 19390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollStateDrag() throws Throwable { 1940bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 1941bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar TestLayoutManager tlm = new TestLayoutManager(); 1942bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 1943bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setAdapter(testAdapter); 1944bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setLayoutManager(tlm); 1945bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar setRecyclerView(recyclerView); 1946bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1947bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState()); 1948bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar final int[] stateCnts = new int[10]; 1949bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 1950bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1951bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 1952bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar stateCnts[newState] = stateCnts[newState] + 1; 1953bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1954bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1955bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar drag(mRecyclerView, 0, 0, 0, 500, 5); 1956bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]); 1957bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_IDLE]); 1958bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]); 1959bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1960bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1961bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY, 1962bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar int stepCount) throws Throwable { 1963bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long downTime = SystemClock.uptimeMillis(); 1964bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar long eventTime = SystemClock.uptimeMillis(); 1965bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1966bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float y = fromY; 1967bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float x = fromX; 1968bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1969bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float yStep = (toY - fromY) / stepCount; 1970bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar float xStep = (toX - fromX) / stepCount; 1971bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1972bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent event = MotionEvent.obtain(downTime, eventTime, 1973bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar MotionEvent.ACTION_DOWN, x, y, 0); 1974bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1975bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar for (int i = 0; i < stepCount; ++i) { 1976bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar y += yStep; 1977bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar x += xStep; 1978bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1979bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 1980bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1981bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1982bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1983bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar eventTime = SystemClock.uptimeMillis(); 1984bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 1985bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar sendTouch(view, event); 1986bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar getInstrumentation().waitForIdleSync(); 1987bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1988bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 1989bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable { 1990bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar runTestOnUiThread(new Runnable() { 1991bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 1992bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public void run() { 1993bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar if (view.onInterceptTouchEvent(event)) { 1994bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar view.onTouchEvent(event); 1995bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1996bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1997bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar }); 1998bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 1999bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 2000be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 20010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleScrap() throws Throwable { 200266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(false); 200366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeRecyclerView(); 200466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycleScrapTest(true); 200566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 200666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 200766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void recycleScrapTest(final boolean useRecycler) throws Throwable { 200866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestAdapter testAdapter = new TestAdapter(10); 200966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 201066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 201166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar @Override 201266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2013e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar ViewInfoStore infoStore = mRecyclerView.mViewInfoStore; 201466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (test.get()) { 201566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar try { 201666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar detachAndScrapAttachedViews(recycler); 201766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) { 201866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 201966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView(recycler.getScrapList().get(i).itemView); 202066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 202166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView(recycler.getScrapList().get(i).itemView, 202266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler); 202366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 202466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 2025e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 2026e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) { 202766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar if (useRecycler) { 202866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recycler.recycleView( 2029e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView); 203066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } else { 203166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar removeAndRecycleView( 2032e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.valueAt(i).itemView, 2033e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar recycler); 203466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 203566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 203666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 203766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("no scrap should be left over", 0, recycler.getScrapCount()); 203866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("pre layout map should be empty", 0, 2039e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPreLayout(infoStore)); 204066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post layout map should be empty", 0, 2041e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar InfoStoreTrojan.sizeOfPostLayout(infoStore)); 2042e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar if (infoStore.mOldChangedHolders != null) { 204366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar assertEquals("post old change map should be empty", 0, 2044e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar infoStore.mOldChangedHolders.size()); 204566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 204666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } catch (Throwable t) { 204766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar postExceptionToInstrumentation(t); 204866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 204966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar 205066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 205166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutRange(recycler, 0, 5); 205266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar layoutLatch.countDown(); 205366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar super.onLayoutChildren(recycler, state); 205466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 205566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar }; 205666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 205766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setAdapter(testAdapter); 205866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar recyclerView.setLayoutManager(lm); 2059121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true); 206066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 206166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar setRecyclerView(recyclerView); 206266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 206366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar test.set(true); 206466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.expectLayouts(1); 206566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar testAdapter.changeAndNotify(3, 1); 206666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar lm.waitForLayout(2); 206766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar checkForMainThreadException(); 206866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar } 206922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 2070be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 20714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable { 20725cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar accessRecyclerOnOnMeasureTest(true); 20735cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 20745cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 2075be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 20764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable { 20774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar accessRecyclerOnOnMeasureTest(false); 20784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 20794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar 20804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar @Test 20810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable { 2082cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar smoothScrollTest(true); 2083cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar } 2084cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar 2085cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar @Test 20860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithRemovedItems() throws Throwable { 2087ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar smoothScrollTest(false); 2088ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2089ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2090ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollTest(final boolean removeItem) throws Throwable { 2091ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final LinearSmoothScroller[] lss = new LinearSmoothScroller[1]; 2092ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStart = new CountDownLatch(1); 2093ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final CountDownLatch calledOnStop = new CountDownLatch(1); 2094ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int visibleChildCount = 10; 2095ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2096ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int start = 0; 2097ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2098ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2099ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2100ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onLayoutChildren(recycler, state); 2101ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutRange(recycler, start, visibleChildCount); 2102ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar layoutLatch.countDown(); 2103ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2104ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2105ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2106ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 2107ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar RecyclerView.State state) { 2108ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar start++; 2109ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2110ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:" 2111ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar + visibleChildCount); 2112ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2113ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar removeAndRecycleAllViews(recycler); 2114c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar layoutRange(recycler, start, 2115c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar Math.max(state.getItemCount(), start + visibleChildCount)); 2116ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return dy; 2117ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2118ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2119ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2120ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public boolean canScrollVertically() { 2121ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return true; 2122ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2123ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2124ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2125ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 2126ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar int position) { 2127ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar LinearSmoothScroller linearSmoothScroller = 2128ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 2129ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2130ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 2131ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar return new PointF(0, 1); 2132ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2133ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2134ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2135ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStart() { 2136ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStart(); 2137ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStart.countDown(); 2138ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2139ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2140ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2141ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar protected void onStop() { 2142ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar super.onStop(); 2143ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.countDown(); 2144ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2145ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 2146ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar linearSmoothScroller.setTargetPosition(position); 2147ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lss[0] = linearSmoothScroller; 2148ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar startSmoothScroll(linearSmoothScroller); 2149ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2150ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }; 2151ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 2152ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 2153ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setLayoutManager(lm); 2154ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.setAdapter(testAdapter); 2155ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.expectLayouts(1); 2156ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar setRecyclerView(rv); 2157ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar lm.waitForLayout(1); 2158ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar // regular scroll 2159ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int targetPosition = visibleChildCount * (removeItem ? 30 : 4); 2160ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 2161ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2162ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2163ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar rv.smoothScrollToPosition(targetPosition); 2164ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2165ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 2166ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2167ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "scrolling to target position " + targetPosition); 2168ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2169ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS)); 2170ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (removeItem) { 2171ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar final int newTarget = targetPosition - 10; 2172ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1); 217390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar final CountDownLatch targetCheck = new CountDownLatch(1); 2174ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar runTestOnUiThread(new Runnable() { 2175ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2176ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2177ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar ViewCompat.postOnAnimationDelayed(rv, new Runnable() { 2178ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar @Override 2179ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar public void run() { 2180ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar try { 2181ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertEquals("scroll position should be updated to next available", 2182ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar newTarget, lss[0].getTargetPosition()); 2183ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } catch (Throwable t) { 2184ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar postExceptionToInstrumentation(t); 2185ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 218690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.countDown(); 2187ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 218890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }, 50); 2189ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2190ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar }); 219190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertTrue("target position should be checked on time ", 219290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar targetCheck.await(10, TimeUnit.SECONDS)); 2193ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2194ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS)); 2195ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2196ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("should scroll to new target " + newTarget 2197115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , rv.findViewHolderForLayoutPosition(newTarget)); 2198ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar if (DEBUG) { 2199ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar Log.d(TAG, "on stop has been called on time"); 2200ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2201ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } else { 2202ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertTrue("on stop should be called eventually", 2203ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar calledOnStop.await(30, TimeUnit.SECONDS)); 2204ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar assertNotNull("scroll to position should succeed", 2205115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar rv.findViewHolderForLayoutPosition(targetPosition)); 2206ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2207ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar checkForMainThreadException(); 2208ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar } 2209ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar 2210be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 22110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void consecutiveSmoothScroll() throws Throwable { 221278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger visibleChildCount = new AtomicInteger(10); 221378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger totalScrolled = new AtomicInteger(0); 221478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 221578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar int start = 0; 221678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 221778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 221878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 221978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar super.onLayoutChildren(recycler, state); 222078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutRange(recycler, start, visibleChildCount.get()); 222178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar layoutLatch.countDown(); 222278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 222378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 222478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 222578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 222678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar RecyclerView.State state) { 222778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar totalScrolled.set(totalScrolled.get() + dy); 222878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return dy; 222978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 223078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 223178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 223278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public boolean canScrollVertically() { 223378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar return true; 223478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 223578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }; 223678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 223778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar TestAdapter testAdapter = new TestAdapter(500); 223878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setLayoutManager(lm); 223978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.setAdapter(testAdapter); 224078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.expectLayouts(1); 224178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar setRecyclerView(rv); 224278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar lm.waitForLayout(1); 224378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 224478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 224578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 224678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 2000); 224778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 224878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 224978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(250); 225078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final AtomicInteger scrollAmt = new AtomicInteger(); 225178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar runTestOnUiThread(new Runnable() { 225278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar @Override 225378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar public void run() { 225478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 225578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar scrollAmt.set(soFar); 225678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar rv.smoothScrollBy(0, 5000 - soFar); 225778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 225878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar }); 22591a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar while (rv.getScrollState() != SCROLL_STATE_IDLE) { 226078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar Thread.sleep(100); 226178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 226278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar final int soFar = totalScrolled.get(); 226378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar assertEquals("second scroll should be competed properly", 5000, soFar); 226478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar } 226578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar 22665cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations) 22675cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar throws Throwable { 22685cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 22695cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10); 22705cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 22715cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 22725cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 22735cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onLayoutChildren(recycler, state); 22745cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 22755cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 22765cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 22775cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } catch (Throwable t) { 22785cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 22795cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } finally { 22805cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar layoutLatch.countDown(); 22815cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22825cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22835cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 22845cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 22855cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 22865cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar int widthSpec, int heightSpec) { 22875cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar try { 22885cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar // make sure we access all views 22895cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar for (int i = 0; i < state.getItemCount(); i++) { 22905cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar View view = recycler.getViewForPosition(i); 22915cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertNotNull(view); 22925cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar assertEquals(i, getPosition(view)); 22935cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 22944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar if (!state.isPreLayout()) { 22954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar assertEquals(state.toString(), 22964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar expectedOnMeasureStateCount.get(), state.getItemCount()); 22974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar } 2298824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 22995cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar postExceptionToInstrumentation(t); 23005cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 23015cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar super.onMeasure(recycler, state, widthSpec, heightSpec); 23025cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 23035cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 23045cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar @Override 23055cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar public boolean supportsPredictiveItemAnimations() { 23065cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar return enablePredictiveAnimations; 23075cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 23085cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar }; 23095cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 23105cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 23115cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setAdapter(testAdapter); 23125cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar recyclerView.setLayoutManager(lm); 23135cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 23145cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar setRecyclerView(recyclerView); 23155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 23165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 23175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.expectLayouts(1); 23185cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar if (!enablePredictiveAnimations) { 23195cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar expectedOnMeasureStateCount.set(15); 23205cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 23215cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar testAdapter.addAndNotify(4, 5); 23225cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar lm.waitForLayout(2); 23235cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar checkForMainThreadException(); 23245cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar } 23255cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar 2326be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setCompatibleAdapter() throws Throwable { 23280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, true); 23290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 23300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, true); 23310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 23320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(true, false); 23330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 23340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar compatibleAdapterTest(false, false); 23350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar removeRecyclerView(); 23360b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23370b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 23380b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews) 23390b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar throws Throwable { 23400b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 23410b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final AtomicInteger recycledViewCount = new AtomicInteger(); 23420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 23430b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 23440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 23450b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 23460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 23470b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 23490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 23500b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 23510b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23520b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23540b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 23550b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 23560b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 23570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 23580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() { 23590b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 23600b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onViewRecycled(RecyclerView.ViewHolder holder) { 23610b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recycledViewCount.incrementAndGet(); 23620b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23630b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }); 23640b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 23650b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 23660b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 23670b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 23680b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 23690b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews); 23700b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 23710b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 23720b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar if (removeAndRecycleExistingViews) { 23730b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertTrue("Previous views should be recycled", recycledViewCount.get() > 0); 23740b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } else { 23750b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar assertEquals("No views should be recycled if adapters are compatible and developer " 23760b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar + "did not request a recycle", 0, recycledViewCount.get()); 23770b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23780b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23790b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 2380be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 23810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setIncompatibleAdapter() throws Throwable { 23820b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(true); 23830b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar incompatibleAdapterTest(false); 23840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 23850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 23860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable { 23870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 23880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 23890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 23900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 23910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super.onLayoutChildren(recycler, state); 23920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar try { 23930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 23940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } catch (Throwable t) { 23960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar postExceptionToInstrumentation(t); 23970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } finally { 23980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar layoutLatch.countDown(); 23990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 24000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 24010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar }; 24020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 24030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 24040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setAdapter(testAdapter); 24050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar recyclerView.setLayoutManager(lm); 24060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 24070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setRecyclerView(recyclerView, !useCustomPool); 24080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 24090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 24100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.expectLayouts(1); 24110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar setAdapter(new TestAdapter2(10)); 24120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar lm.waitForLayout(2); 24130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar checkForMainThreadException(); 24140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 24150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 2416be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleIgnored() throws Throwable { 24186e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 24196e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 24206e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 24216e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 24226e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutRange(recycler, 0, 5); 24236e560171b774afafd572b1896becac7b308a92e6Yigit Boyar layoutLatch.countDown(); 24246e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 24256e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }; 24266e560171b774afafd572b1896becac7b308a92e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 24276e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setAdapter(adapter); 24286e560171b774afafd572b1896becac7b308a92e6Yigit Boyar recyclerView.setLayoutManager(lm); 24296e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.expectLayouts(1); 24306e560171b774afafd572b1896becac7b308a92e6Yigit Boyar setRecyclerView(recyclerView); 24316e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.waitForLayout(2); 24326e560171b774afafd572b1896becac7b308a92e6Yigit Boyar runTestOnUiThread(new Runnable() { 24336e560171b774afafd572b1896becac7b308a92e6Yigit Boyar @Override 24346e560171b774afafd572b1896becac7b308a92e6Yigit Boyar public void run() { 24356e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child1 = lm.findViewByPosition(0); 24366e560171b774afafd572b1896becac7b308a92e6Yigit Boyar View child2 = lm.findViewByPosition(1); 24376e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child1); 24386e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.ignoreView(child2); 24396e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 24406e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleAllViews(recyclerView.mRecycler); 24416e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should not be recycled or removed", 2, 24426e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.getChildCount()); 24436e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 24446e560171b774afafd572b1896becac7b308a92e6Yigit Boyar Throwable[] throwables = new Throwable[1]; 24456e560171b774afafd572b1896becac7b308a92e6Yigit Boyar try { 24466e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAndRecycleView(child1, mRecyclerView.mRecycler); 24476e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } catch (Throwable t) { 24486e560171b774afafd572b1896becac7b308a92e6Yigit Boyar throwables[0] = t; 24496e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 24506e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertTrue("Trying to recycle an ignored view should throw IllegalArgException " 24515cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar , throwables[0] instanceof IllegalArgumentException); 24526e560171b774afafd572b1896becac7b308a92e6Yigit Boyar lm.removeAllViews(); 24536e560171b774afafd572b1896becac7b308a92e6Yigit Boyar assertEquals("ignored child should be removed as well ", 0, lm.getChildCount()); 24546e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 24556e560171b774afafd572b1896becac7b308a92e6Yigit Boyar }); 24566e560171b774afafd572b1896becac7b308a92e6Yigit Boyar } 24576e560171b774afafd572b1896becac7b308a92e6Yigit Boyar 2458be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findIgnoredByPosition() throws Throwable { 2460f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 2461f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 2462f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 2463f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2464f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar detachAndScrapAttachedViews(recycler); 2465f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutRange(recycler, 0, 5); 2466f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar layoutLatch.countDown(); 2467f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2468f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }; 2469f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2470f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setAdapter(adapter); 2471f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar recyclerView.setLayoutManager(lm); 2472f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 2473f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar setRecyclerView(recyclerView); 2474f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(2); 2475f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar Thread.sleep(5000); 2476f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final int pos = 1; 2477f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar final View[] ignored = new View[1]; 2478f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar runTestOnUiThread(new Runnable() { 2479f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar @Override 2480f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar public void run() { 2481f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View child = lm.findViewByPosition(pos); 2482f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.ignoreView(child); 2483f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar ignored[0] = child; 2484f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2485f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar }); 2486f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("ignored child should not be null", ignored[0]); 2487f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNull("find view by position should not return ignored child", 2488f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.findViewByPosition(pos)); 2489f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.expectLayouts(1); 2490f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 2491f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar lm.waitForLayout(1); 2492f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertEquals("child count should be ", 6, lm.getChildCount()); 2493f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar View replacement = lm.findViewByPosition(pos); 2494f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotNull("re-layout should replace ignored child w/ another one", replacement); 2495f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar assertNotSame("replacement should be a different view", replacement, ignored[0]); 2496f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar } 2497f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar 2498be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 24990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateAllDecorOffsets() throws Throwable { 2500bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final TestAdapter adapter = new TestAdapter(10); 2501bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2502bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true); 2503bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setAdapter(adapter); 2504bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(4); 2505bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() { 2506bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 2507bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar TestLayoutManager testLayoutManager = new TestLayoutManager() { 2508bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2509bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2510bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar try { 2511bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // test 2512824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 2513bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar View child = getChildAt(i); 2514bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2515bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar child.getLayoutParams(); 2516bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 2517bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets validation for VH should have expected value.", 2518bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 2519bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2520bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) { 2521bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2522bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar vh.itemView.getLayoutParams(); 2523bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals( 2524bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar "Decor insets invalidation in cache for VH should have expected " 2525bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar + "value.", 2526bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.get(), lp.mInsetsDirty); 2527bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2528bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar detachAndScrapAttachedViews(recycler); 2529bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutRange(recycler, 0, layoutCount.get()); 2530bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } catch (Throwable t) { 2531bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar postExceptionToInstrumentation(t); 2532bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } finally { 2533bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutLatch.countDown(); 2534bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2535bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2536bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2537bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2538bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public boolean supportsPredictiveItemAnimations() { 2539bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar return false; 2540bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2541bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }; 2542bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // first layout 2543bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setItemViewCacheSize(5); 2544bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.setLayoutManager(testLayoutManager); 2545bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2546e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar setRecyclerView(recyclerView, true, false); 2547bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 2548bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2549bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2550bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 2551bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2552bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2553bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 2554bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2555bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2556bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2557bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/o an item decorator 2558e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar 2559bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2560bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2561bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2562bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.assertNoLayout("layout should not happen", 2); 2563bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2564bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2565bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // set item decorator, should invalidate 2566bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2567bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2568bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar addItemDecoration(mRecyclerView, dummyItemDecoration); 2569bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2570bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2571bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2572bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // re-layout w/o any change 2573bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2574bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2575bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(recyclerView); 2576bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2577bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2578bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2579bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // invalidate w/ item decorator 2580bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2581bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2582bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2583bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2584bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(2); 2585bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2586bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2587bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // trigger cache. 2588bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(3); 2589bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(false); 2590bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2591bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar requestLayoutOnUIThread(mRecyclerView); 2592bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2593bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2594bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size()); 2595bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2596bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar layoutCount.set(5); 2597bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2598bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2599bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidateDecorOffsets(recyclerView); 2600bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2601bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2602bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2603bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar // remove item decorator 2604bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar invalidatedOffsets.set(true); 2605bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.expectLayouts(1); 2606bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar removeItemDecoration(mRecyclerView, dummyItemDecoration); 2607bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar testLayoutManager.waitForLayout(1); 2608bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar checkForMainThreadException(); 2609bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2610bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2611bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void addItemDecoration(final RecyclerView recyclerView, final 2612824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 2613bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2614bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2615bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2616bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.addItemDecoration(itemDecoration); 2617bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2618bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2619bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2620bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2621bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void removeItemDecoration(final RecyclerView recyclerView, final 2622bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar RecyclerView.ItemDecoration itemDecoration) throws Throwable { 2623bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2624bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2625bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2626bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.removeItemDecoration(itemDecoration); 2627bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2628bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2629bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2630bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2631bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable { 2632bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar runTestOnUiThread(new Runnable() { 2633bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar @Override 2634bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar public void run() { 2635bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar recyclerView.invalidateItemDecorations(); 2636bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2637bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar }); 2638bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar } 2639bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar 2640be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 26410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void invalidateDecorOffsets() throws Throwable { 2642cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final TestAdapter adapter = new TestAdapter(10); 2643cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.setHasStableIds(true); 2644cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 2645cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setAdapter(adapter); 2646cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2647cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase final Map<Long, Boolean> changes = new HashMap<Long, Boolean>(); 2648cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2649cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 2650cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 2651cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2652cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase try { 2653cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (changes.size() > 0) { 2654cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase // test 2655824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < getChildCount(); i++) { 2656cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase View child = getChildAt(i); 2657cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) 2658cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase child.getLayoutParams(); 2659cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase RecyclerView.ViewHolder vh = lp.mViewHolder; 2660cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase if (!changes.containsKey(vh.getItemId())) { 2661cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase continue; //nothing to test 2662cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2663cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase assertEquals( 2664cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase "Decord insets validation for VH should have expected value.", 2665cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.get(vh.getItemId()).booleanValue(), 2666cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase lp.mInsetsDirty); 2667cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2668cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2669cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase detachAndScrapAttachedViews(recycler); 2670cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutRange(recycler, 0, state.getItemCount()); 2671cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } catch (Throwable t) { 2672cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase postExceptionToInstrumentation(t); 2673cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } finally { 2674cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase layoutLatch.countDown(); 2675cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2676cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2677cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2678cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase @Override 2679cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase public boolean supportsPredictiveItemAnimations() { 2680cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase return false; 2681cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2682cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase }; 2683cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase recyclerView.setLayoutManager(testLayoutManager); 2684cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2685cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase setRecyclerView(recyclerView); 2686cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2687cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int itemAddedTo = 5; 2688cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = 0; i < itemAddedTo; i++) { 2689115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 2690cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2691cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) { 2692115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 2693cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2694cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2695cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.addAndNotify(5, 1); 2696cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2697cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2698cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2699cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase changes.clear(); 2700cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase int[] changedItems = new int[]{3, 5, 6}; 2701824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 2702115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false); 2703cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2704824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < changedItems.length; i++) { 27051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItems[i]).getItemId(), 27061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar true); 2707cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2708cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2709cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changePositionsAndNotify(changedItems); 2710cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2711cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2712cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2713824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar for (int i = 0; i < adapter.getItemCount(); i++) { 2714115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true); 2715cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2716cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.expectLayouts(1); 2717cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 2718cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase testLayoutManager.waitForLayout(2); 2719cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase checkForMainThreadException(); 2720cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase } 2721cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2722be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 27230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void movingViaStableIds() throws Throwable { 2724c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(true); 2725c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 2726c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar stableIdsMoveTest(false); 2727c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar removeRecyclerView(); 2728c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2729c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2730c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable { 2731c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 2732c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.setHasStableIds(true); 2733c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final AtomicBoolean test = new AtomicBoolean(false); 2734c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewFromIndex = 3; 2735c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final int movedViewToIndex = 6; 2736c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar final View[] movedView = new View[1]; 2737c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 2738c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2739c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 2740c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar detachAndScrapAttachedViews(recycler); 2741c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar try { 2742c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (test.get()) { 2743c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar if (state.isPreLayout()) { 2744c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewFromIndex, true); 2745c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In pre layout, should be able to get moved view w/ old " 2746c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 2747c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 2748c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 2749c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 2750c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 2751c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } else { 2752c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar View view = recycler.getViewForPosition(movedViewToIndex, true); 2753c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertSame("In post layout, should be able to get moved view w/ new " 2754c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar + "position", movedView[0], view); 2755c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view); 2756c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar assertTrue("it should come from scrap", holder.wasReturnedFromScrap()); 2757c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar // clear scrap flag 2758c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar holder.clearReturnedFromScrapFlag(); 2759c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2760c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2761c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 2762c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } catch (Throwable t) { 2763c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar postExceptionToInstrumentation(t); 2764c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } finally { 2765c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar layoutLatch.countDown(); 2766c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2767c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2768c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2769c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2770c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2771c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2772c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public boolean supportsPredictiveItemAnimations() { 2773c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar return supportsPredictive; 2774c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2775c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }; 2776c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar RecyclerView recyclerView = new RecyclerView(this.getActivity()); 2777c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setAdapter(testAdapter); 2778c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar recyclerView.setLayoutManager(lm); 2779c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(1); 2780c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar setRecyclerView(recyclerView); 2781c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(1); 2782c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar 2783c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar movedView[0] = recyclerView.getChildAt(movedViewFromIndex); 2784c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar test.set(true); 2785c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.expectLayouts(supportsPredictive ? 2 : 1); 2786c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar runTestOnUiThread(new Runnable() { 2787c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar @Override 2788c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar public void run() { 2789c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar Item item = testAdapter.mItems.remove(movedViewFromIndex); 2790c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.mItems.add(movedViewToIndex, item); 2791c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemRemoved(movedViewFromIndex); 2792c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar testAdapter.notifyItemInserted(movedViewToIndex); 2793c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2794c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar }); 2795c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.waitForLayout(2); 2796c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar checkForMainThreadException(); 2797c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar } 2798cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase 2799be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringLayout() throws Throwable { 28010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() { 28020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 28050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() { 28090bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28100bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 28120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() { 28160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 28190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() { 28220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 28250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeInMainThreadTest(String msg, 28300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onLayoutRunnable) throws Throwable { 283166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 28320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final AtomicBoolean doneFirstLayout = new AtomicBoolean(false); 28330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(10); 28340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 28350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 28370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 28380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 28390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 28400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (doneFirstLayout.get()) { 28410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onLayoutRunnable.run(); 28420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 28440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 28450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 28460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 28470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 28510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 28520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 28530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 28540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 28550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 28560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 28570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar doneFirstLayout.set(true); 28580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 28590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar requestLayoutOnUIThread(recyclerView); 28600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 28610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 28620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 286366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar getMainThreadException() instanceof IllegalStateException); 28640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2866be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 28670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScroll() throws Throwable { 28680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int orientation : new int[]{OrientationHelper.HORIZONTAL, 28690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar OrientationHelper.VERTICAL}) { 28700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyDataSetChanged", orientation, 28710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar new Runnable() { 28720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyDataSetChanged(); 28750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() { 28780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemChanged(2); 28810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() { 28850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemInserted(2); 28880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() { 28910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 28920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void run() { 28930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar mRecyclerView.getAdapter().notifyItemRemoved(2); 28940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }); 28960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 28980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 28990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void adapterChangeDuringScrollTest(String msg, final int orientation, 29000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar final Runnable onScrollRunnable) throws Throwable { 290166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 29020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestAdapter testAdapter = new TestAdapter(100); 29030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar TestLayoutManager lm = new TestLayoutManager() { 29040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 29050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 29060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.onLayoutChildren(recycler, state); 29070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 29080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutRange(recycler, 0, 10); 29090bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 29100bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 29110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 29120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 29130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 29160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 29170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollVertically() { 29180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.VERTICAL; 29190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 29210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 29220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public boolean canScrollHorizontally() { 29230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return orientation == OrientationHelper.HORIZONTAL; 29240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 29260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int mockScroll() { 29270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar try { 29280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar onScrollRunnable.run(); 29290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } catch (Throwable t) { 29300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar postExceptionToInstrumentation(t); 29310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } finally { 29320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar layoutLatch.countDown(); 29330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return 0; 29350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 29370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 29380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 29390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 29400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 29410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 29430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 29440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 29450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView.State state) { 29460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar return mockScroll(); 29470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar }; 29490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar RecyclerView recyclerView = new RecyclerView(getActivity()); 29500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setLayoutManager(lm); 29510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar recyclerView.setAdapter(testAdapter); 29520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 29530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar setRecyclerView(recyclerView); 29540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 29550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.expectLayouts(1); 29560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar scrollBy(200); 29570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar lm.waitForLayout(2); 29580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar removeRecyclerView(); 29590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("Invalid data updates should be caught:" + msg, 296066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar getMainThreadException() instanceof IllegalStateException); 29610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 29620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2963be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 29640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleOnDetach() throws Throwable { 296549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 296649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestAdapter testAdapter = new TestAdapter(10); 296749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final AtomicBoolean didRunOnDetach = new AtomicBoolean(false); 296849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 296949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 297049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 297149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onLayoutChildren(recycler, state); 297249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutRange(recycler, 0, state.getItemCount() - 1); 297349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar layoutLatch.countDown(); 297449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 297549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 297649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 297749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 297849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar super.onDetachedFromWindow(view, recycler); 297949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar didRunOnDetach.set(true); 298049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeAndRecycleAllViews(recycler); 298149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 298249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar }; 298349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setAdapter(testAdapter); 298449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar recyclerView.setLayoutManager(lm); 298549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.expectLayouts(1); 298649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar setRecyclerView(recyclerView); 298749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar lm.waitForLayout(2); 298849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar removeRecyclerView(); 298949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get()); 299049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertEquals("All children should be recycled", recyclerView.getChildCount(), 0); 299149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 29920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 2993be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 29940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesWhileDetached() throws Throwable { 2995bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 2996bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 2997bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 2998bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 2999bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 3000bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 3001bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3002bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 3003bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 3004bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 3005bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 3006bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 3007bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 3008bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 3009bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 3010bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 3011bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 3012bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 3013bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 3014bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 3015bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 3016be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updatesAfterDetach() throws Throwable { 3018bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3019bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int initialAdapterSize = 20; 3020bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 3021bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final AtomicInteger layoutCount = new AtomicInteger(0); 3022bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 3023bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 3024bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3025bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar super.onLayoutChildren(recycler, state); 3026bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutRange(recycler, 0, 5); 3027bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.incrementAndGet(); 3028bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutLatch.countDown(); 3029bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 3030bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }; 3031bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setAdapter(adapter); 3032bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setLayoutManager(lm); 3033bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 3034bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar recyclerView.setHasFixedSize(true); 3035bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar setRecyclerView(recyclerView); 3036bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.waitForLayout(2); 3037bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.expectLayouts(1); 3038bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar final int prevLayoutCount = layoutCount.get(); 3039bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar runTestOnUiThread(new Runnable() { 3040bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar @Override 3041bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar public void run() { 3042bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar try { 3043bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar adapter.addAndNotify(4, 5); 3044bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar removeRecyclerView(); 3045bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } catch (Throwable throwable) { 304690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar postExceptionToInstrumentation(throwable); 3047bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 3048bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 3049bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar }); 305090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 3051bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar 3052bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar lm.assertNoLayout("When RV is not attached, layout should not happen", 1); 3053bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar assertEquals("No extra layout should happen when detached", prevLayoutCount, 3054bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar layoutCount.get()); 3055bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar } 305649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 3057be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 30580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedWithStableIds() throws Throwable { 3059e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int defaultViewType = 1; 3060e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Item, Integer> viewTypeMap = new HashMap<Item, Integer>(); 3061e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final Map<Integer, Integer> oldPositionToNewPositionMapping = 3062e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new HashMap<Integer, Integer>(); 3063e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 3064e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3065e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public int getItemViewType(int position) { 3066e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Integer type = viewTypeMap.get(mItems.get(position)); 3067e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return type == null ? defaultViewType : type; 3068e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3069e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 3070e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3071e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 3072e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 3073e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3074e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 3075e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 3076e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final ArrayList<Item> previousItems = new ArrayList<Item>(); 3077e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar previousItems.addAll(adapter.mItems); 3078e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 3079e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicInteger layoutStart = new AtomicInteger(50); 3080e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final AtomicBoolean validate = new AtomicBoolean(false); 3081e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int childCount = 10; 3082e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 3083e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3084e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3085e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 3086e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar super.onLayoutChildren(recycler, state); 3087e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3088e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("Cached views should be kept", 5, recycler 3089e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .mCachedViews.size()); 3090e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.mCachedViews) { 3091e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 30920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 30930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 3094e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 3095e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3096e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3097e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar detachAndScrapAttachedViews(recycler); 3098e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3099e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("cache size should stay the same", 5, 3100e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.mCachedViews.size()); 3101e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("all views should be scrapped", childCount, 3102e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recycler.getScrapList().size()); 3103e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.getScrapList()) { 3104e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // TODO create test case for type change 3105e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 31060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertTrue("view holder should be marked for update", 31070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar tvh.needsUpdate()); 3108e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertTrue("view holder should be marked as invalid", tvh.isInvalid()); 3109e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3110e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3111e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 3112e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (validate.get()) { 3113e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < getChildCount(); i++) { 3114e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = getChildAt(i); 3115e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar TestViewHolder tvh = (TestViewHolder) mRecyclerView 3116e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar .getChildViewHolder(view); 3117115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int oldPos = previousItems.indexOf(tvh.mBoundItem); 3118e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals("view holder's position should be correct", 3119e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.get(oldPos).intValue(), 3120115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar tvh.getLayoutPosition()); 31210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar ; 31220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 3123e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3124e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable t) { 3125e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(t); 3126e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } finally { 3127e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutLatch.countDown(); 3128e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3129e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3130e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 3131e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3132e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemAnimator(null); 3133e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setAdapter(adapter); 3134e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setLayoutManager(lm); 3135e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar recyclerView.setItemViewCacheSize(10); 3136e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3137e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setRecyclerView(recyclerView); 3138e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3139e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 3140e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar getInstrumentation().waitForIdleSync(); 3141e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar layoutStart.set(layoutStart.get() + 5);//55 3142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar requestLayoutOnUIThread(recyclerView); 3144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3145e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar validate.set(true); 3146e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.expectLayouts(1); 3147e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar runTestOnUiThread(new Runnable() { 3148e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 3149e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void run() { 3150e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar try { 3151e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.moveItems(false, 3152e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2}, 3153e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64}, 3154e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar new int[]{75, 58}); 3155e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar for (int i = 0; i < previousItems.size(); i++) { 3156e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item = previousItems.get(i); 3157e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item)); 3158e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3159cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 3160e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } catch (Throwable throwable) { 3161e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar postExceptionToInstrumentation(throwable); 3162e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3163e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3164e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }); 3165e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar lm.waitForLayout(2); 3166e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 3167e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 3168e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 3169be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 31700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSwap() throws Throwable { 3171824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(true); 3172824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3173824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3174be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 31750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void callbacksDuringAdapterSet() throws Throwable { 3176824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar callbacksDuringAdapterChange(false); 3177824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3178824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3179824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void callbacksDuringAdapterChange(boolean swap) throws Throwable { 3180824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter() 3181824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 3182824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter() 3183824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar : createOwnerCheckingAdapter(); 3184824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3185824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3186824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3187824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3188824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar try { 3189824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 3190824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } catch (Throwable t) { 3191824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar postExceptionToInstrumentation(t); 3192824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3193824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar layoutLatch.countDown(); 3194824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3195824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3196824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3197824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setAdapter(adapter1); 3198824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar rv.setLayoutManager(tlm); 3199824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 3200824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setRecyclerView(rv); 3201824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 3202824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3203824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.expectLayouts(1); 3204824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar if (swap) { 3205824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar swapAdapter(adapter2, true); 3206824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } else { 3207824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar setAdapter(adapter2); 3208824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3209824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3210824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar tlm.waitForLayout(1); 3211824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar checkForMainThreadException(); 3212824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3213824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3214824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createOwnerCheckingAdapter() { 3215824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 3216824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3217824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 3218824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 3219824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 3220824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 3221824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3222824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3223824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3224824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 3225824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 3226824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on bind should be called w/ the creator adapter", this, holder.mData); 3227824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3228824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3229824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3230824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 3231824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar int viewType) { 3232824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType); 3233824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar vh.mData = this; 3234824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return vh; 3235824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3236824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3237824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3238824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3239824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar private TestAdapter2 createBinderCheckingAdapter() { 3240824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar return new TestAdapter2(10) { 3241824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3242824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onViewRecycled(TestViewHolder2 holder) { 3243824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar assertSame("on recycled should be called w/ the creator adapter", this, 3244824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData); 3245824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = null; 3246824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onViewRecycled(holder); 3247824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3248824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3249824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar @Override 3250824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 3251824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar super.onBindViewHolder(holder, position); 3252824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar holder.mData = this; 3253824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3254824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar }; 3255824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar } 3256824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 3257be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 32580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findViewById() throws Throwable { 32595ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(false); 32605ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar removeRecyclerView(); 32615ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar findViewByIdTest(true); 32625ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32635ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 32645ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void findViewByIdTest(final boolean supportPredictive) throws Throwable { 32655ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 32665ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int initialAdapterSize = 20; 32675ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final TestAdapter adapter = new TestAdapter(initialAdapterSize); 32685ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteStart = 6; 32695ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final int deleteCount = 5; 32705ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setAdapter(adapter); 32715ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar final AtomicBoolean assertPositions = new AtomicBoolean(false); 32725ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestLayoutManager lm = new TestLayoutManager() { 32735ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 32745ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 32755ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar super.onLayoutChildren(recycler, state); 32765ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (assertPositions.get()) { 32775ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar if (state.isPreLayout()) { 32780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteStart; i++) { 32795ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 32805ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position for existing items should work " 32815ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "fine", view); 32825ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 32835ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32845ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32855ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < deleteCount; i++) { 32875ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i + deleteStart); 32885ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull("find view by position should work fine for removed " 32895ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar + "views in pre-layout", view); 32905ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertTrue("view should be marked as removed", 32915ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32925ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 32935ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 32945ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar for (int i = deleteStart + deleteCount; i < 20; i++) { 32955ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 32965ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertNotNull(view); 32975ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 32985ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 32995ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 33005ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33015ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } else { 33020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar for (int i = 0; i < initialAdapterSize - deleteCount; i++) { 33035ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar View view = findViewByPosition(i); 3304fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar assertNotNull("find view by position for existing item " + i + 3305fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar " should work fine. child count:" + getChildCount(), view); 33065ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar TestViewHolder viewHolder = 33075ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar (TestViewHolder) mRecyclerView.getChildViewHolder(view); 33085ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertSame("should be the correct item " + viewHolder 3309115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar , viewHolder.mBoundItem, 33105ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.mItems.get(viewHolder.mPosition)); 33115ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertFalse("view should not be marked as removed", 33125ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar ((RecyclerView.LayoutParams) view.getLayoutParams()) 33135ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar .isItemRemoved()); 33145ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33155ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33165ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33175ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar detachAndScrapAttachedViews(recycler); 33185ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutRange(recycler, state.getItemCount() - 1, -1); 33195ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar layoutLatch.countDown(); 33205ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33215ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 33225ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar @Override 33235ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar public boolean supportsPredictiveItemAnimations() { 33245ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar return supportPredictive; 33255ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33265ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar }; 33275ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar recyclerView.setLayoutManager(lm); 33285ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(1); 33295ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar setRecyclerView(recyclerView); 33305ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 33315ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar getInstrumentation().waitForIdleSync(); 33325ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 33335ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar assertPositions.set(true); 33345ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.expectLayouts(supportPredictive ? 2 : 1); 33355ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1}); 33365ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar lm.waitForLayout(2); 33375ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar } 33385ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar 3339be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 33400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForCache() throws Throwable { 334122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 334222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestAdapter adapter = new TestAdapter(100) { 334322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 334422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public int getItemViewType(int position) { 334522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return viewType.get(); 334622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 334722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 334822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 334922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public long getItemId(int position) { 335022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar return mItems.get(position).mId; 335122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 335222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 335322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.setHasStableIds(true); 335422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final AtomicInteger layoutStart = new AtomicInteger(2); 335522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final int childCount = 10; 335622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 335722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 335822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 335922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar super.onLayoutChildren(recycler, state); 336022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar detachAndScrapAttachedViews(recycler); 336122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount); 336222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutLatch.countDown(); 336322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 336422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }; 336522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3366668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar recyclerView.setItemAnimator(null); 336722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setAdapter(adapter); 336822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setLayoutManager(lm); 336922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar recyclerView.setItemViewCacheSize(10); 337022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 337122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar setRecyclerView(recyclerView); 337222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 337322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar getInstrumentation().waitForIdleSync(); 337422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(4); // trigger a cache for 3,4 337522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 337622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar requestLayoutOnUIThread(recyclerView); 337722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 337822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar // 337922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar viewType.incrementAndGet(); 338022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar layoutStart.set(2); // go back to bring views from cache 338122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.expectLayouts(1); 338222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar adapter.mItems.remove(1); 3383cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 338422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar lm.waitForLayout(2); 338522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar runTestOnUiThread(new Runnable() { 338622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar @Override 338722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar public void run() { 338822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar for (int i = 2; i < 4; i++) { 3389115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i); 339022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar assertEquals("View holder's type should match latest type", viewType.get(), 339122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar vh.getItemViewType()); 339222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 339322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 339422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar }); 339522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar } 339622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar 3397be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 33980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void typeForExistingViews() throws Throwable { 33997e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final AtomicInteger viewType = new AtomicInteger(1); 34007e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int invalidatedCount = 2; 34017e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int layoutStart = 2; 34027e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestAdapter adapter = new TestAdapter(100) { 34037e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 34047e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public int getItemViewType(int position) { 34057e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return viewType.get(); 34067e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34077e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 34087e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 34097e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 34107e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar int position) { 34117e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onBindViewHolder(holder, position); 34127e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar if (position >= layoutStart && position < invalidatedCount + layoutStart) { 34137e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar try { 34147e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar assertEquals("holder type should match current view type at position " + 34157e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar position, viewType.get(), holder.getItemViewType()); 34167e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } catch (Throwable t) { 34177e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar postExceptionToInstrumentation(t); 34187e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34197e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34207e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34217e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 34227e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 34237e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public long getItemId(int position) { 34247e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar return mItems.get(position).mId; 34257e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34267e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 34277e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar adapter.setHasStableIds(true); 34287e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 34297e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final int childCount = 10; 34307e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final TestLayoutManager lm = new TestLayoutManager() { 34317e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar @Override 34327e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 34337e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar super.onLayoutChildren(recycler, state); 34347e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar detachAndScrapAttachedViews(recycler); 34357e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutRange(recycler, layoutStart, layoutStart + childCount); 34367e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar layoutLatch.countDown(); 34377e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34387e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar }; 34397e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 34407e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setAdapter(adapter); 34417e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar recyclerView.setLayoutManager(lm); 34427e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 34437e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar setRecyclerView(recyclerView); 34447e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 34457e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar getInstrumentation().waitForIdleSync(); 34467e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar viewType.incrementAndGet(); 34477e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.expectLayouts(1); 3448cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.changeAndNotify(layoutStart, invalidatedCount); 34497e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar lm.waitForLayout(2); 34507e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar checkForMainThreadException(); 34517e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar } 34527e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 34537e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar 3454be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 34550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void state() throws Throwable { 3456d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final TestAdapter adapter = new TestAdapter(10); 3457d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final RecyclerView recyclerView = new RecyclerView(getActivity()); 3458d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setAdapter(adapter); 3459d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setItemAnimator(null); 3460d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicInteger itemCount = new AtomicInteger(); 3461d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase final AtomicBoolean structureChanged = new AtomicBoolean(); 3462d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase TestLayoutManager testLayoutManager = new TestLayoutManager() { 3463d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3464d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 34658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar detachAndScrapAttachedViews(recycler); 3466d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutRange(recycler, 0, state.getItemCount()); 3467d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.set(state.getItemCount()); 3468d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.set(state.didStructureChange()); 3469d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase layoutLatch.countDown(); 3470d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3471d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }; 3472d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.setLayoutManager(testLayoutManager); 3473d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 3474d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 3475d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3476d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 3477a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar getActivity().getContainer().addView(recyclerView); 3478d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3479d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 348066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar testLayoutManager.waitForLayout(2); 3481d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 3482d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("item count in state should be correct", adapter.getItemCount() 3483d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase , itemCount.get()); 3484d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true for first layout", true, 3485d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 3486d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase Thread.sleep(1000); //wait for other layouts. 3487d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase testLayoutManager.expectLayouts(1); 3488d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase runTestOnUiThread(new Runnable() { 3489d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 3490d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase public void run() { 3491d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase recyclerView.requestLayout(); 3492d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 3493d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase }); 34948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3495d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("in second layout,structure changed should be false", false, 3496d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 34978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); // 3498b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.deleteAndNotify(3, 2); 34998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3500d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are removed, item count in state should be updated", 3501d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 3502d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 3503d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 3504d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 35058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.expectLayouts(1); 3506b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar adapter.addAndNotify(2, 5); 35078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar testLayoutManager.waitForLayout(2); 3508d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 3509d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("when items are added, item count in state should be updated", 3510d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase adapter.getItemCount(), 3511d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase itemCount.get()); 3512d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase assertEquals("structure changed should be true when items are removed", true, 3513d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase structureChanged.get()); 35140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 35150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 3516be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachWithoutLayoutManager() throws Throwable { 3518abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 3519abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar runTestOnUiThread(new Runnable() { 3520abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar @Override 3521abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar public void run() { 3522abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar try { 3523abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar setRecyclerView(recyclerView); 3524abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar removeRecyclerView(); 3525abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } catch (Throwable t) { 3526abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar postExceptionToInstrumentation(t); 3527abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3528abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3529abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar }); 3530abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar checkForMainThreadException(); 3531abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 3532abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 3533be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 35340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void updateHiddenView() throws Throwable { 35351a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 35361a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] preLayoutRange = new int[]{0, 10}; 35371a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] postLayoutRange = new int[]{0, 10}; 35381a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final AtomicBoolean enableGetViewTest = new AtomicBoolean(false); 3539959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar final List<Integer> disappearingPositions = new ArrayList<>(); 35401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestLayoutManager tlm = new TestLayoutManager() { 35411a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 35421a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public boolean supportsPredictiveItemAnimations() { 35431a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar return true; 35441a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35451a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 35461a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 35471a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 35481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 35491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final int[] layoutRange = state.isPreLayout() ? preLayoutRange 35501a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar : postLayoutRange; 35511a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar detachAndScrapAttachedViews(recycler); 35521a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutRange(recycler, layoutRange[0], layoutRange[1]); 35531a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar if (!state.isPreLayout()) { 35541a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar for (Integer position : disappearingPositions) { 35551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // test sanity. 35561a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar assertNull(findViewByPosition(position)); 35571a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final View view = recycler.getViewForPosition(position); 3558959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertNotNull(view); 35591a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar addDisappearingView(view); 35601a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar measureChildWithMargins(view, 0, 0); 35611a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // position item out of bounds. 35621a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar view.layout(0, -500, view.getMeasuredWidth(), 35631a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar -500 + view.getMeasuredHeight()); 35641a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35651a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35661a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable t) { 35671a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postExceptionToInstrumentation(t); 35681a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35691a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar layoutLatch.countDown(); 35701a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 35711a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }; 3572959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar recyclerView.getItemAnimator().setMoveDuration(4000); 3573959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar recyclerView.getItemAnimator().setRemoveDuration(4000); 35741a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar final TestAdapter adapter = new TestAdapter(100); 35751a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setAdapter(adapter); 35761a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar recyclerView.setLayoutManager(tlm); 35771a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(1); 35781a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar setRecyclerView(recyclerView); 35791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(1); 35801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 35811a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now, a child disappears 35821a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.add(0); 35831a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // layout one shifted 35841a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[0] = 1; 35851a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar postLayoutRange[1] = 11; 35861a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 35871a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.addAndNotify(8, 1); 35881a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 35891a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 35901a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 35911a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.expectLayouts(2); 35921a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar disappearingPositions.clear(); 35931a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar // now that item should be moving, invalidate it and delete it. 35941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar enableGetViewTest.set(true); 35951a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar runTestOnUiThread(new Runnable() { 35961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar @Override 35971a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar public void run() { 35981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar try { 3599959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertThat("test sanity, should still be animating", 3600959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar mRecyclerView.isAnimating(), CoreMatchers.is(true)); 36011a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.changeAndNotify(0, 1); 36021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar adapter.deleteAndNotify(0, 1); 36031a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } catch (Throwable throwable) { 3604959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar fail(throwable.getMessage()); 36051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 36061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 36071a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar }); 36081a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar tlm.waitForLayout(2); 36091a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar checkForMainThreadException(); 36101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar } 36111a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 3612be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnTop() throws Throwable { 36146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.TOP); 36156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3617be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeft() throws Throwable { 36196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT); 36206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3622be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRight() throws Throwable { 36246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT); 36256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3627be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnBottom() throws Throwable { 36296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.BOTTOM); 36306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3632be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnLeftRTL() throws Throwable { 36346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.LEFT, true); 36356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 36366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 36376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3639be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 36400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusBigViewOnRightRTL() throws Throwable { 36416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(Gravity.RIGHT, true); 36426d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL, 36436d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar mRecyclerView.getLayoutManager().getLayoutDirection()); 36446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity) throws Throwable { 36476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar focusTooBigViewTest(gravity, false); 36486d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 3649be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar 36506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable { 36516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 36526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 36536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL); 36546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vScrollDist = new AtomicInteger(0); 36566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hScrollDist = new AtomicInteger(0); 36576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger vDesiredDist = new AtomicInteger(0); 36586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final AtomicInteger hDesiredDist = new AtomicInteger(0); 36596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 36606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36626d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int getLayoutDirection() { 36636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR; 36646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 36666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 36676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 36686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar detachAndScrapAttachedViews(recycler); 36696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar final View view = recycler.getViewForPosition(0); 36706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar addView(view); 36716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar int left = 0, top = 0; 36726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.setBackgroundColor(Color.rgb(0, 0, 255)); 36736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar switch (gravity) { 36746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.LEFT: 36756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.RIGHT: 36766d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 36776d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5), 36786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY), 36796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9), 36806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST)); 36816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80 36826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar : 90; 36836d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = 0; 36846d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) { 36856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth()); 36866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 36876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hDesiredDist.set(left); 36886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 36896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 36906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.TOP: 36916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar case Gravity.BOTTOM: 36926d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.measure( 36936d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9), 36946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.AT_MOST), 36956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5), 36966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View.MeasureSpec.EXACTLY)); 36976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() - 36986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 80 : 90; 36996d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar left = 0; 37006d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vDesiredDist.set(top); 37016d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar break; 37026d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37036d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 37046d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar view.layout(left, top, left + view.getMeasuredWidth(), 37056d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar top + view.getMeasuredHeight()); 37066d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar layoutLatch.countDown(); 37076d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37086d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 37096d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 37106d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollVertically() { 37116d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return true; 37126d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37136d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 37146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 37156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public boolean canScrollHorizontally() { 37166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return super.canScrollHorizontally(); 37176d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37186d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 37196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 37206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 37216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 37226d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar vScrollDist.addAndGet(dy); 37236d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetTopAndBottom(-dy); 37246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dy; 37256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 37276d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar @Override 37286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 37296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar RecyclerView.State state) { 37306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar hScrollDist.addAndGet(dx); 37316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar getChildAt(0).offsetLeftAndRight(-dx); 37326d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar return dx; 37336d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar }; 37356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar TestAdapter adapter = new TestAdapter(10); 37366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setAdapter(adapter); 37376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar rv.setLayoutManager(tlm); 37386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.expectLayouts(1); 37396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar setRecyclerView(rv); 37406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar tlm.waitForLayout(2); 37416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar View view = rv.getChildAt(0); 3742959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", requestFocus(view, true)); 3743959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar assertTrue("test sanity", view.hasFocus()); 37446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(vDesiredDist.get(), vScrollDist.get()); 37456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(hDesiredDist.get(), hScrollDist.get()); 37466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingTop(), view.getTop()); 37476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar if (rtl) { 3748be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(), 3749be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar view.getRight()); 37506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } else { 37516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft()); 37526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar } 37546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar 3755be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 37560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void firstLayoutWithAdapterChanges() throws Throwable { 37574bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final TestAdapter adapter = new TestAdapter(0); 37584bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 37594bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setVisibility(rv, View.GONE); 37604bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 37614bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 37624bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 37634bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 37644bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar super.onLayoutChildren(recycler, state); 37654bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutRange(recycler, 0, state.getItemCount()); 37664bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable t) { 37674bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar postExceptionToInstrumentation(t); 37684bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } finally { 37694bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar layoutLatch.countDown(); 37704bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37714bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37724bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 37734bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 37744bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public boolean supportsPredictiveItemAnimations() { 37754bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar return true; 37764bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37774bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }; 37784bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setLayoutManager(tlm); 37794bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setAdapter(adapter); 37804bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setHasFixedSize(true); 37814bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar setRecyclerView(rv); 37824bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.expectLayouts(1); 37834bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.assertNoLayout("test sanity, layout should not run", 1); 37844bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar getInstrumentation().waitForIdleSync(); 37854bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar runTestOnUiThread(new Runnable() { 37864bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Override 37874bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar public void run() { 37884bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar try { 37894bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar adapter.addAndNotify(2); 37904bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } catch (Throwable throwable) { 37914bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar throwable.printStackTrace(); 37924bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37934bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar rv.setVisibility(View.VISIBLE); 37944bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 37954bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar }); 37964bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 37974bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar tlm.waitForLayout(2); 37984bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar assertEquals(2, rv.getChildCount()); 37994bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar checkForMainThreadException(); 38004bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar } 38014bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar 38024bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar @Test 380314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutLayoutManager() throws Throwable { 380414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 380514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setAdapter(new TestAdapter(10)); 380614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 380714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 380814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 380914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 381014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 381114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 381214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 381314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 381414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 381514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 381614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 381714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar public void computeScrollOfsetWithoutAdapter() throws Throwable { 381814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 381914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar rv.setLayoutManager(new TestLayoutManager()); 382014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar setRecyclerView(rv); 382114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollExtent()); 382214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollOffset()); 382314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeHorizontalScrollRange()); 382414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 382514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollExtent()); 382614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollOffset()); 382714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar assertEquals(0, rv.computeVerticalScrollRange()); 382814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar } 382914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar 383014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar @Test 38310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithDecorOffsets() throws Throwable { 3832f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(true); 3833f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3834f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3835be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar @Test 38360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusRectOnScreenWithout() throws Throwable { 3837f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar focusRectOnScreenTest(false); 3838f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3839f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3840f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable { 3841f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3842f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final AtomicInteger scrollDist = new AtomicInteger(0); 3843f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3844f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3845f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3846f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar detachAndScrapAttachedViews(recycler); 3847f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar final View view = recycler.getViewForPosition(0); 3848f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar addView(view); 3849f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar measureChildWithMargins(view, 0, 0); 3850f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar view.layout(0, -20, view.getWidth(), 3851f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar -20 + view.getHeight());// ignore decors on purpose 3852f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar layoutLatch.countDown(); 3853f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3854f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3855f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3856f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public boolean canScrollVertically() { 3857f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return true; 3858f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3859f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3860f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3861f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 3862f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3863f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar scrollDist.addAndGet(dy); 3864f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar return dy; 3865f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3866f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }; 3867f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar TestAdapter adapter = new TestAdapter(10); 3868f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar if (addItemDecors) { 3869f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.addItemDecoration(new RecyclerView.ItemDecoration() { 3870f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar @Override 3871f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 3872f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar RecyclerView.State state) { 3873f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar outRect.set(0, 10, 0, 10); 3874f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3875f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar }); 3876f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3877f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setAdapter(adapter); 3878f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar rv.setLayoutManager(tlm); 3879f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.expectLayouts(1); 3880f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar setRecyclerView(rv); 3881f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar tlm.waitForLayout(2); 3882f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3883f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar View view = rv.getChildAt(0); 3884959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar requestFocus(view, true); 3885f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar assertEquals(addItemDecors ? -30 : -20, scrollDist.get()); 3886f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar } 3887f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar 3888e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 38890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void unimplementedSmoothScroll() throws Throwable { 3890e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1); 3891e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1); 3892e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final CountDownLatch cbLatch = new CountDownLatch(2); 3893e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 3894e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3895e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 3896e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 3897e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, 0, 10); 3898e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 3899e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3900e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3901e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3902e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 3903e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int position) { 3904e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedSmoothScrollToPosition.get()); 3905e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedSmoothScrollToPosition.set(position); 3906e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 3907e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 3908e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3909e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 3910e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return null; 3911e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3912e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3913e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 3914e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 3915e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3916e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3917e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3918e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 3919e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 3920e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(-1, receivedScrollToPosition.get()); 3921e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPosition.set(position); 3922e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar cbLatch.countDown(); 3923e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3924e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 3925e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView rv = new RecyclerView(getActivity()); 3926e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(new TestAdapter(100)); 3927e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 3928e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 3929e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 3930e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 3931ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 3932959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar smoothScrollToPosition(35, false); 3933ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("smoothScrollToPosition should be ignored when frozen", 3934ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu -1, receivedSmoothScrollToPosition.get()); 3935ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 3936959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar smoothScrollToPosition(35, false); 3937e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS)); 3938e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 3939e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedSmoothScrollToPosition.get()); 3940e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(35, receivedScrollToPosition.get()); 3941e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3942e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3943e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 39440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScroller() throws Throwable { 3945e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(true); 3946e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3947e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 3948e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Test 39490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void jumpingJackSmoothScrollerGoesIdle() throws Throwable { 3950e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar jumpingJackSmoothScrollerTest(false); 3951e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 3952e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 39537f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Test 39547f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void testScrollByBeforeFirstLayout() throws Throwable { 39557f5e94985f795f81884334ca2752a0469a998762Yigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()); 39567f5e94985f795f81884334ca2752a0469a998762Yigit Boyar TestAdapter adapter = new TestAdapter(10); 39577f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.setLayoutManager(new TestLayoutManager() { 39587f5e94985f795f81884334ca2752a0469a998762Yigit Boyar AtomicBoolean didLayout = new AtomicBoolean(false); 39597f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 39607f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 39617f5e94985f795f81884334ca2752a0469a998762Yigit Boyar super.onLayoutChildren(recycler, state); 39627f5e94985f795f81884334ca2752a0469a998762Yigit Boyar didLayout.set(true); 39637f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39647f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39657f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 39667f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 39677f5e94985f795f81884334ca2752a0469a998762Yigit Boyar RecyclerView.State state) { 39687f5e94985f795f81884334ca2752a0469a998762Yigit Boyar assertThat("should run layout before scroll", 39697f5e94985f795f81884334ca2752a0469a998762Yigit Boyar didLayout.get(), CoreMatchers.is(true)); 39707f5e94985f795f81884334ca2752a0469a998762Yigit Boyar return super.scrollVerticallyBy(dy, recycler, state); 39717f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39727f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39737f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 39747f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public boolean canScrollVertically() { 39757f5e94985f795f81884334ca2752a0469a998762Yigit Boyar return true; 39767f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39777f5e94985f795f81884334ca2752a0469a998762Yigit Boyar }); 39787f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.setAdapter(adapter); 39797f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39807f5e94985f795f81884334ca2752a0469a998762Yigit Boyar runTestOnUiThread(new Runnable() { 39817f5e94985f795f81884334ca2752a0469a998762Yigit Boyar @Override 39827f5e94985f795f81884334ca2752a0469a998762Yigit Boyar public void run() { 39837f5e94985f795f81884334ca2752a0469a998762Yigit Boyar try { 39847f5e94985f795f81884334ca2752a0469a998762Yigit Boyar setRecyclerView(recyclerView); 39857f5e94985f795f81884334ca2752a0469a998762Yigit Boyar recyclerView.scrollBy(10, 19); 39867f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } catch (Throwable throwable) { 39877f5e94985f795f81884334ca2752a0469a998762Yigit Boyar postExceptionToInstrumentation(throwable); 39887f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39897f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39907f5e94985f795f81884334ca2752a0469a998762Yigit Boyar }); 39917f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 39927f5e94985f795f81884334ca2752a0469a998762Yigit Boyar checkForMainThreadException(); 39937f5e94985f795f81884334ca2752a0469a998762Yigit Boyar } 39947f5e94985f795f81884334ca2752a0469a998762Yigit Boyar 3995e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable { 3996e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final List<Integer> receivedScrollToPositions = new ArrayList<>(); 3997e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final TestAdapter testAdapter = new TestAdapter(200); 3998e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final AtomicBoolean mTargetFound = new AtomicBoolean(false); 3999e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar TestLayoutManager tlm = new TestLayoutManager() { 4000e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int pendingScrollPosition = -1; 4001e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4002e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 4003e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar detachAndScrapAttachedViews(recycler); 4004e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition; 4005e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutRange(recycler, pos, pos + 10); 4006e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (layoutLatch != null) { 4007e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar layoutLatch.countDown(); 4008e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4009e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4010e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4011e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4012e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 4013e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final int position) { 4014e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar RecyclerView.SmoothScroller ss = 4015e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar new LinearSmoothScroller(recyclerView.getContext()) { 4016e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4017e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 4018e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar return new PointF(0, 1); 4019e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4020e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4021e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4022e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void onTargetFound(View targetView, RecyclerView.State state, 4023e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Action action) { 4024e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar super.onTargetFound(targetView, state, action); 4025e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar mTargetFound.set(true); 4026e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4027e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4028e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4029e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar protected void updateActionForInterimTarget(Action action) { 4030e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = succeed ? getTargetPosition() : 100; 4031e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition + 2 < limit) { 4032e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar if (pendingScrollPosition != NO_POSITION) { 4033e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(pendingScrollPosition, 4034e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar getChildViewHolderInt(getChildAt(0)) 4035e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar .getAdapterPosition()); 4036e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4037e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar action.jumpTo(pendingScrollPosition + 2); 4038e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4039e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4040e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 4041e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar ss.setTargetPosition(position); 4042e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar startSmoothScroll(ss); 4043e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4044e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4045e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4046e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void scrollToPosition(int position) { 4047e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar receivedScrollToPositions.add(position); 4048e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar pendingScrollPosition = position; 4049e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar requestLayout(); 4050e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4051e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }; 4052e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar final RecyclerView rv = new RecyclerView(getActivity()); 4053e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setAdapter(testAdapter); 4054e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.setLayoutManager(tlm); 4055e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4056e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.expectLayouts(1); 4057e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar setRecyclerView(rv); 4058e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar tlm.waitForLayout(2); 4059e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4060e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar runTestOnUiThread(new Runnable() { 4061e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar @Override 4062e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar public void run() { 4063e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar rv.smoothScrollToPosition(150); 4064e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4065e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar }); 4066e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar int limit = 100; 4067e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) { 4068e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar Thread.sleep(200); 4069e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 4070e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4071e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar checkForMainThreadException(); 4072e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue(limit > 0); 4073e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar for (int i = 1; i < 100; i+=2) { 4074e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i)); 4075e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4076e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4077e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar assertEquals(succeed, mTargetFound.get()); 4078e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 4079e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar } 4080e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar 40810b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestViewHolder2 extends RecyclerView.ViewHolder { 4082824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 4083824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar Object mData; 4084824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 40850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2(View itemView) { 40860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar super(itemView); 40870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 4089d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 40900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> { 4091824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar 40920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar List<Item> mItems; 40930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 40940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar private TestAdapter2(int count) { 40950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems = new ArrayList<Item>(count); 40960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar for (int i = 0; i < count; i++) { 40970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar mItems.add(new Item(i, "Item " + i)); 40980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 40990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 41000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 41010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 41020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public TestViewHolder2 onCreateViewHolder(ViewGroup parent, 41030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar int viewType) { 41040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return new TestViewHolder2(new TextView(parent.getContext())); 41050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 41060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 41070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 41080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public void onBindViewHolder(TestViewHolder2 holder, int position) { 41090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar final Item item = mItems.get(position); 41100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")"); 41110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 41120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar 41130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar @Override 41140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar public int getItemCount() { 41150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar return mItems.size(); 41160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar } 4117d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 4118d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 4119e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public interface AdapterRunnable { 41201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar 41213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar void run(TestAdapter adapter) throws Throwable; 4122115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar } 4123115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar 41243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public class LayoutAllLayoutManager extends TestLayoutManager { 41253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar @Override 41263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 41273e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar detachAndScrapAttachedViews(recycler); 41283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutRange(recycler, 0, state.getItemCount()); 41293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar layoutLatch.countDown(); 41303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 41313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar } 4132bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4133bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar /** 4134bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar * Proxy class to make protected methods public 4135bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar */ 4136bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public static class TestRecyclerView extends RecyclerView { 4137bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4138bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context) { 4139bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context); 4140bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4141bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4142bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context, @Nullable AttributeSet attrs) { 4143bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context, attrs); 4144bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4145bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4146bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public TestRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 4147bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super(context, attrs, defStyle); 4148bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4149bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4150bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 4151bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void detachViewFromParent(int index) { 4152bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super.detachViewFromParent(index); 4153bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4154bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar 4155bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar @Override 4156bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar public void attachViewToParent(View child, int index, ViewGroup.LayoutParams params) { 4157bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar super.attachViewToParent(child, index, params); 4158bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 4159bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar } 41604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar 41614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar private static interface ViewRunnable { 41624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar void run(View view) throws RuntimeException; 41634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar } 41647a59e4b36500bcfddd842376d6c3abe0d9f23d84Yigit Boyar} 4165