LinearLayoutManagerTest.java revision 999c3976674d20b0de5425490bdfe7415b9c6af2
1d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar/* 2d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 4d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * you may not use this file except in compliance with the License. 6d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * You may obtain a copy of the License at 7d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 8d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * 10d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * See the License for the specific language governing permissions and 14d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * limitations under the License. 15d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar */ 16d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 17d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarpackage android.support.v7.widget; 18d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 19d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.content.Context; 208edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport android.graphics.Rect; 218edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport android.os.Parcel; 228edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport android.os.Parcelable; 23a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.AccessibilityDelegateCompat; 24a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityEventCompat; 25a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityRecordCompat; 26f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest; 278edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport android.util.Log; 28d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.view.View; 29504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup; 30a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent; 31310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyarimport android.widget.FrameLayout; 32d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 33c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END; 34c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START; 35310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL; 36310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyarimport static android.support.v7.widget.LinearLayoutManager.VERTICAL; 378edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport java.lang.reflect.Field; 38d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.ArrayList; 398edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport java.util.LinkedHashMap; 40d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.List; 418edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport java.util.Map; 428edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyarimport java.util.UUID; 43d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.CountDownLatch; 44d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.TimeUnit; 45504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 46d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 478edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar/** 488edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar * Includes tests for {@link LinearLayoutManager}. 498edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar * <p> 508edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar * Since most UI tests are not practical, these tests are focused on internal data representation 518edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar * and stability of LinearLayoutManager in response to different events (state change, scrolling 528edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar * etc) where it is very hard to do manual testing. 538edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar */ 54f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 55999c3976674d20b0de5425490bdfe7415b9c6af2Yigit Boyarpublic class LinearLayoutManagerTest extends BaseLinearLayoutManagerTest { 568edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar 571f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItem() throws Throwable { 581f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 591f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout( 601f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar false), 100, 0); 611f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 621f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 631f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverse() throws Throwable { 641f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 651f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(true), 100, 661f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 0); 671f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 681f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 691f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemStackFromEnd() throws Throwable { 701f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 711f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(false), 100, 721f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 99); 731f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 741f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 751f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemStackFromEndAndReverse() throws Throwable { 761f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 771f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(true), 100, 781f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 99); 791f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 801f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 811f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemHorizontal() throws Throwable { 821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 831f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout( 841f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar false), 100, 0); 851f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 861f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 871f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemReverseHorizontal() throws Throwable { 881f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout(true), 901f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 100, 0); 911f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 921f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemStackFromEndHorizontal() throws Throwable { 941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 951f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(false), 961f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 100, 99); 971f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 981f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 991f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void testRemoveAnchorItemStackFromEndAndReverseHorizontal() throws Throwable { 1001f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar removeAnchorItemTest( 1011f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(true), 100, 1021f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 99); 1031f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1041f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 1051f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar /** 1061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * This tests a regression where predictive animations were not working as expected when the 1071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * first item is removed and there aren't any more items to add from that direction. 1081f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar * First item refers to the default anchor item. 1091f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar */ 1101f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void removeAnchorItemTest(final Config config, int adapterSize, 1111f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int removePos) throws Throwable { 1121f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar config.adapter(new TestAdapter(adapterSize) { 1131f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 1141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 1151f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar int position) { 1161f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar super.onBindViewHolder(holder, position); 1171f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 1181f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (!(lp instanceof ViewGroup.MarginLayoutParams)) { 1191f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar lp = new ViewGroup.MarginLayoutParams(0, 0); 1201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar holder.itemView.setLayoutParams(lp); 1211f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1221f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp; 1231f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int maxSize; 1241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 1251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getWidth(); 1261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = ViewGroup.MarginLayoutParams.FILL_PARENT; 1271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 1281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar maxSize = mRecyclerView.getHeight(); 1291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = ViewGroup.MarginLayoutParams.FILL_PARENT; 1301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 1321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int desiredSize; 1331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (position == removePos) { 1341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it large 1351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 4; 1361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 1371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar // make it small 1381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar desiredSize = maxSize / 8; 1391f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1401f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (config.mOrientation == HORIZONTAL) { 1411f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.width = desiredSize; 1421f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 1431f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mlp.height = desiredSize; 1441f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1451f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1461f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar }); 1471f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar setupByConfig(config, true); 1481f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int childCount = mLayoutManager.getChildCount(); 1491f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder toBeRemoved = null; 1501f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>(); 1511f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < childCount; i++) { 1521f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mLayoutManager.getChildAt(i); 1531f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 1541f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (holder.getAdapterPosition() == removePos) { 1551f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeRemoved = holder; 1561f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 1571f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar toBeMoved.add(holder); 1581f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1591f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1601f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertNotNull("test sanity", toBeRemoved); 1611f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("test sanity", childCount - 1, toBeMoved.size()); 1621f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator(); 1631f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.setItemAnimator(loggingItemAnimator); 1641f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.reset(); 1651f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.expectRunPendingAnimationsCall(1); 1661f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mLayoutManager.expectLayouts(2); 1671f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mTestAdapter.deleteAndNotify(removePos, 1); 1681f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mLayoutManager.waitForLayout(1); 1691f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.waitForPendingAnimationsCall(2); 1701f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("removed child should receive remove animation", 1711f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mRemoveVHs.contains(toBeRemoved)); 1721f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder vh : toBeMoved) { 1731f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("view holder should be in moved list", 1741f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(vh)); 1751f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1761f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>(); 1771f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = 0; i < mLayoutManager.getChildCount(); i++) { 1781f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View child = mLayoutManager.getChildAt(i); 1791f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); 1801f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (toBeRemoved != holder && !toBeMoved.contains(holder)) { 1811f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar newHolders.add(holder); 1821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1831f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1841f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("some new children should show up for the new space", newHolders.size() > 0); 1851f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertEquals("no items should receive animate add since they are not new", 0, 1861f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mAddVHs.size()); 1871f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (RecyclerView.ViewHolder holder : newHolders) { 1881f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("new holder should receive a move animation", 1891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar loggingItemAnimator.mMoveVHs.contains(holder)); 1901f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1911f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar assertTrue("control against adding too many children due to bad layout state preparation." 1921f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(), 1931f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mRecyclerView.getChildCount() <= childCount + 3 /*1 for removed view, 2 for its size*/); 1941f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 1951f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 196310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar public void testKeepFocusOnRelayout() throws Throwable { 197310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar setupByConfig(new Config(VERTICAL, false, false).itemCount(500), true); 198310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar int center = (mLayoutManager.findLastVisibleItemPosition() 199310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar - mLayoutManager.findFirstVisibleItemPosition()) / 2; 200115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(center); 201310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar final int top = mLayoutManager.mOrientationHelper.getDecoratedStart(vh.itemView); 202310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar runTestOnUiThread(new Runnable() { 203310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar @Override 204310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar public void run() { 205310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar vh.itemView.requestFocus(); 206310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar } 207310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar }); 208310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar assertTrue("view should have the focus", vh.itemView.hasFocus()); 209310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar // add a bunch of items right before that view, make sure it keeps its position 210310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar mLayoutManager.expectLayouts(2); 211310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar final int childCountToAdd = mRecyclerView.getChildCount() * 2; 212310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar mTestAdapter.addAndNotify(center, childCountToAdd); 213310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar center += childCountToAdd; // offset item 214310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar mLayoutManager.waitForLayout(2); 215310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar mLayoutManager.waitForAnimationsToEnd(20); 216115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final RecyclerView.ViewHolder postVH = mRecyclerView.findViewHolderForLayoutPosition(center); 217310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar assertNotNull("focused child should stay in layout", postVH); 218310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar assertSame("same view holder should be kept for unchanged child", vh, postVH); 219310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar assertEquals("focused child's screen position should stay unchanged", top, 220310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar mLayoutManager.mOrientationHelper.getDecoratedStart(postVH.itemView)); 221310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar } 222310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar 223542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepFullFocusOnResize() throws Throwable { 224542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), true); 225542f1260934df280985294eaef1ec8469863281fYigit Boyar } 226542f1260934df280985294eaef1ec8469863281fYigit Boyar 227542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepPartialFocusOnResize() throws Throwable { 228542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), false); 229542f1260934df280985294eaef1ec8469863281fYigit Boyar } 230542f1260934df280985294eaef1ec8469863281fYigit Boyar 231542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepReverseFullFocusOnResize() throws Throwable { 232542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), true); 233542f1260934df280985294eaef1ec8469863281fYigit Boyar } 234542f1260934df280985294eaef1ec8469863281fYigit Boyar 235542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepReversePartialFocusOnResize() throws Throwable { 236542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), false); 237542f1260934df280985294eaef1ec8469863281fYigit Boyar } 238542f1260934df280985294eaef1ec8469863281fYigit Boyar 239542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepStackFromEndFullFocusOnResize() throws Throwable { 240542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), true); 241542f1260934df280985294eaef1ec8469863281fYigit Boyar } 242542f1260934df280985294eaef1ec8469863281fYigit Boyar 243542f1260934df280985294eaef1ec8469863281fYigit Boyar public void testKeepStackFromEndPartialFocusOnResize() throws Throwable { 244542f1260934df280985294eaef1ec8469863281fYigit Boyar keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), false); 245542f1260934df280985294eaef1ec8469863281fYigit Boyar } 246542f1260934df280985294eaef1ec8469863281fYigit Boyar 247542f1260934df280985294eaef1ec8469863281fYigit Boyar public void keepFocusOnResizeTest(final Config config, boolean fullyVisible) throws Throwable { 248542f1260934df280985294eaef1ec8469863281fYigit Boyar setupByConfig(config, true); 249542f1260934df280985294eaef1ec8469863281fYigit Boyar final int targetPosition; 250542f1260934df280985294eaef1ec8469863281fYigit Boyar if (config.mStackFromEnd) { 251542f1260934df280985294eaef1ec8469863281fYigit Boyar targetPosition = mLayoutManager.findFirstVisibleItemPosition(); 252542f1260934df280985294eaef1ec8469863281fYigit Boyar } else { 253542f1260934df280985294eaef1ec8469863281fYigit Boyar targetPosition = mLayoutManager.findLastVisibleItemPosition(); 254542f1260934df280985294eaef1ec8469863281fYigit Boyar } 255542f1260934df280985294eaef1ec8469863281fYigit Boyar final OrientationHelper helper = mLayoutManager.mOrientationHelper; 256542f1260934df280985294eaef1ec8469863281fYigit Boyar final RecyclerView.ViewHolder vh = mRecyclerView 257542f1260934df280985294eaef1ec8469863281fYigit Boyar .findViewHolderForLayoutPosition(targetPosition); 258542f1260934df280985294eaef1ec8469863281fYigit Boyar 259542f1260934df280985294eaef1ec8469863281fYigit Boyar // scroll enough to offset the child 260542f1260934df280985294eaef1ec8469863281fYigit Boyar int startMargin = helper.getDecoratedStart(vh.itemView) - 261542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getStartAfterPadding(); 262542f1260934df280985294eaef1ec8469863281fYigit Boyar int endMargin = helper.getEndAfterPadding() - 263542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getDecoratedEnd(vh.itemView); 264542f1260934df280985294eaef1ec8469863281fYigit Boyar Log.d(TAG, "initial start margin " + startMargin + " , end margin:" + endMargin); 265542f1260934df280985294eaef1ec8469863281fYigit Boyar requestFocus(vh.itemView); 266542f1260934df280985294eaef1ec8469863281fYigit Boyar runTestOnUiThread(new Runnable() { 267542f1260934df280985294eaef1ec8469863281fYigit Boyar @Override 268542f1260934df280985294eaef1ec8469863281fYigit Boyar public void run() { 269542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("view should gain the focus", vh.itemView.hasFocus()); 270542f1260934df280985294eaef1ec8469863281fYigit Boyar } 271542f1260934df280985294eaef1ec8469863281fYigit Boyar }); 272542f1260934df280985294eaef1ec8469863281fYigit Boyar do { 273542f1260934df280985294eaef1ec8469863281fYigit Boyar Thread.sleep(100); 274542f1260934df280985294eaef1ec8469863281fYigit Boyar } while (mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); 275542f1260934df280985294eaef1ec8469863281fYigit Boyar // scroll enough to offset the child 276542f1260934df280985294eaef1ec8469863281fYigit Boyar startMargin = helper.getDecoratedStart(vh.itemView) - 277542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getStartAfterPadding(); 278542f1260934df280985294eaef1ec8469863281fYigit Boyar endMargin = helper.getEndAfterPadding() - 279542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getDecoratedEnd(vh.itemView); 280542f1260934df280985294eaef1ec8469863281fYigit Boyar 281542f1260934df280985294eaef1ec8469863281fYigit Boyar Log.d(TAG, "start margin " + startMargin + " , end margin:" + endMargin); 282542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("View should become fully visible", startMargin >= 0 && endMargin >= 0); 283542f1260934df280985294eaef1ec8469863281fYigit Boyar 284542f1260934df280985294eaef1ec8469863281fYigit Boyar int expectedOffset = 0; 285542f1260934df280985294eaef1ec8469863281fYigit Boyar boolean offsetAtStart = false; 286542f1260934df280985294eaef1ec8469863281fYigit Boyar if (!fullyVisible) { 287542f1260934df280985294eaef1ec8469863281fYigit Boyar // move it a bit such that it is no more fully visible 288542f1260934df280985294eaef1ec8469863281fYigit Boyar final int childSize = helper 289542f1260934df280985294eaef1ec8469863281fYigit Boyar .getDecoratedMeasurement(vh.itemView); 290542f1260934df280985294eaef1ec8469863281fYigit Boyar expectedOffset = childSize / 3; 291542f1260934df280985294eaef1ec8469863281fYigit Boyar if (startMargin < endMargin) { 292542f1260934df280985294eaef1ec8469863281fYigit Boyar scrollBy(expectedOffset); 293542f1260934df280985294eaef1ec8469863281fYigit Boyar offsetAtStart = true; 294542f1260934df280985294eaef1ec8469863281fYigit Boyar } else { 295542f1260934df280985294eaef1ec8469863281fYigit Boyar scrollBy(-expectedOffset); 296542f1260934df280985294eaef1ec8469863281fYigit Boyar offsetAtStart = false; 297542f1260934df280985294eaef1ec8469863281fYigit Boyar } 298542f1260934df280985294eaef1ec8469863281fYigit Boyar startMargin = helper.getDecoratedStart(vh.itemView) - 299542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getStartAfterPadding(); 300542f1260934df280985294eaef1ec8469863281fYigit Boyar endMargin = helper.getEndAfterPadding() - 301542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getDecoratedEnd(vh.itemView); 302542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("test sanity, view should not be fully visible", startMargin < 0 303542f1260934df280985294eaef1ec8469863281fYigit Boyar || endMargin < 0); 304542f1260934df280985294eaef1ec8469863281fYigit Boyar } 305542f1260934df280985294eaef1ec8469863281fYigit Boyar 306542f1260934df280985294eaef1ec8469863281fYigit Boyar mLayoutManager.expectLayouts(1); 307542f1260934df280985294eaef1ec8469863281fYigit Boyar runTestOnUiThread(new Runnable() { 308542f1260934df280985294eaef1ec8469863281fYigit Boyar @Override 309542f1260934df280985294eaef1ec8469863281fYigit Boyar public void run() { 310542f1260934df280985294eaef1ec8469863281fYigit Boyar final ViewGroup.LayoutParams layoutParams = mRecyclerView.getLayoutParams(); 311542f1260934df280985294eaef1ec8469863281fYigit Boyar if (config.mOrientation == HORIZONTAL) { 312542f1260934df280985294eaef1ec8469863281fYigit Boyar layoutParams.width = mRecyclerView.getWidth() / 2; 313542f1260934df280985294eaef1ec8469863281fYigit Boyar } else { 314542f1260934df280985294eaef1ec8469863281fYigit Boyar layoutParams.height = mRecyclerView.getHeight() / 2; 315542f1260934df280985294eaef1ec8469863281fYigit Boyar } 316542f1260934df280985294eaef1ec8469863281fYigit Boyar mRecyclerView.setLayoutParams(layoutParams); 317542f1260934df280985294eaef1ec8469863281fYigit Boyar } 318542f1260934df280985294eaef1ec8469863281fYigit Boyar }); 319542f1260934df280985294eaef1ec8469863281fYigit Boyar Thread.sleep(100); 320542f1260934df280985294eaef1ec8469863281fYigit Boyar // add a bunch of items right before that view, make sure it keeps its position 321542f1260934df280985294eaef1ec8469863281fYigit Boyar mLayoutManager.waitForLayout(2); 322542f1260934df280985294eaef1ec8469863281fYigit Boyar mLayoutManager.waitForAnimationsToEnd(20); 323542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("view should preserve the focus", vh.itemView.hasFocus()); 324542f1260934df280985294eaef1ec8469863281fYigit Boyar final RecyclerView.ViewHolder postVH = mRecyclerView 325542f1260934df280985294eaef1ec8469863281fYigit Boyar .findViewHolderForLayoutPosition(targetPosition); 326542f1260934df280985294eaef1ec8469863281fYigit Boyar assertNotNull("focused child should stay in layout", postVH); 327542f1260934df280985294eaef1ec8469863281fYigit Boyar assertSame("same view holder should be kept for unchanged child", vh, postVH); 328542f1260934df280985294eaef1ec8469863281fYigit Boyar View focused = postVH.itemView; 329542f1260934df280985294eaef1ec8469863281fYigit Boyar 330542f1260934df280985294eaef1ec8469863281fYigit Boyar startMargin = helper.getDecoratedStart(focused) - helper.getStartAfterPadding(); 331542f1260934df280985294eaef1ec8469863281fYigit Boyar endMargin = helper.getEndAfterPadding() - helper.getDecoratedEnd(focused); 332542f1260934df280985294eaef1ec8469863281fYigit Boyar 333542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("focused child should be somewhat visible", 334542f1260934df280985294eaef1ec8469863281fYigit Boyar helper.getDecoratedStart(focused) < helper.getEndAfterPadding() 335542f1260934df280985294eaef1ec8469863281fYigit Boyar && helper.getDecoratedEnd(focused) > helper.getStartAfterPadding()); 336542f1260934df280985294eaef1ec8469863281fYigit Boyar if (fullyVisible) { 337542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("focused child end should stay fully visible", 338542f1260934df280985294eaef1ec8469863281fYigit Boyar endMargin >= 0); 339542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("focused child start should stay fully visible", 340542f1260934df280985294eaef1ec8469863281fYigit Boyar startMargin >= 0); 341542f1260934df280985294eaef1ec8469863281fYigit Boyar } else { 342542f1260934df280985294eaef1ec8469863281fYigit Boyar if (offsetAtStart) { 343542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("start should preserve its offset", startMargin < 0); 344542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("end should be visible", endMargin >= 0); 345542f1260934df280985294eaef1ec8469863281fYigit Boyar } else { 346542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("end should preserve its offset", endMargin < 0); 347542f1260934df280985294eaef1ec8469863281fYigit Boyar assertTrue("start should be visible", startMargin >= 0); 348542f1260934df280985294eaef1ec8469863281fYigit Boyar } 349542f1260934df280985294eaef1ec8469863281fYigit Boyar } 350542f1260934df280985294eaef1ec8469863281fYigit Boyar } 351542f1260934df280985294eaef1ec8469863281fYigit Boyar 3526e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar public void testScrollToPositionWithPredictive() throws Throwable { 3536e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar scrollToPositionWithPredictive(0, LinearLayoutManager.INVALID_OFFSET); 3546e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar removeRecyclerView(); 3556e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar scrollToPositionWithPredictive(3, 20); 3566e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar removeRecyclerView(); 3576e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 3586e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar LinearLayoutManager.INVALID_OFFSET); 3596e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar removeRecyclerView(); 3606e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 10); 3616e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar } 3626e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar 363504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void testRecycleDuringAnimations() throws Throwable { 364504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 365504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(300) { 366504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 367504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 368504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 369504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final int cnt = childCount.incrementAndGet(); 370504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType); 371504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (DEBUG) { 372504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Log.d(TAG, "CHILD_CNT(create):" + cnt + ", " + testViewHolder); 373504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 374504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return testViewHolder; 375504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 376504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 377310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar setupByConfig(new Config(VERTICAL, false, false).itemCount(300) 378504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar .adapter(adapter), true); 379504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 380504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool() { 381504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 382504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 383504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 384504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int cnt = childCount.decrementAndGet(); 385504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (DEBUG) { 386504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Log.d(TAG, "CHILD_CNT(put):" + cnt + ", " + scrap); 387504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 388504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 389504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 390504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 391504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 392504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 393504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 394504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final int cnt = childCount.incrementAndGet(); 395504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (DEBUG) { 396504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Log.d(TAG, "CHILD_CNT(get):" + cnt + ", " + recycledView); 397504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 398504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 399504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 400504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 401504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 402504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar pool.setMaxRecycledViews(mTestAdapter.getItemViewType(0), 500); 403504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(pool); 404504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 405504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 406504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 407504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar for (int i = 0; i < 100; i ++) { 408504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 409504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(15); 410504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 411504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 412504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 413504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 414504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 415504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 416504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now trigger lots of add again, followed by a scroll to position 417504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar for (int i = 0; i < 100; i ++) { 418504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(5 + (i % 3) * 3, 1); 419504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(25); 420504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 421504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar smoothScrollToPosition(mLayoutManager.findLastVisibleItemPosition() + 20); 422504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 423504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 424504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 425504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 426504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 427504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 428d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar 42949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void testDontRecycleChildrenOnDetach() throws Throwable { 43049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar setupByConfig(new Config().recycleChildrenOnDetach(false), true); 43149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar runTestOnUiThread(new Runnable() { 43249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 43349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void run() { 43449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size(); 43549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mRecyclerView.setLayoutManager(new TestLayoutManager()); 43649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertEquals("No views are recycled", recyclerSize, 43749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mRecyclerView.mRecycler.getRecycledViewPool().size()); 43849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 43949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar }); 44049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 44149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 44249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void testRecycleChildrenOnDetach() throws Throwable { 44349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar setupByConfig(new Config().recycleChildrenOnDetach(true), true); 44449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar final int childCount = mLayoutManager.getChildCount(); 44549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar runTestOnUiThread(new Runnable() { 44649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar @Override 44749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar public void run() { 44849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size(); 44949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mRecyclerView.mRecycler.getRecycledViewPool().setMaxRecycledViews( 45049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mTestAdapter.getItemViewType(0), recyclerSize + childCount); 45149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mRecyclerView.setLayoutManager(new TestLayoutManager()); 45249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar assertEquals("All children should be recycled", childCount + recyclerSize, 45349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar mRecyclerView.mRecycler.getRecycledViewPool().size()); 45449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 45549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar }); 45649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar } 45749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar 4583d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev public void testScrollAndClear() throws Throwable { 4593d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev setupByConfig(new Config(), true); 4603d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev 4613d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev assertTrue("Children not laid out", mLayoutManager.collectChildCoordinates().size() > 0); 4623d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev 4633d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev mLayoutManager.expectLayouts(1); 4643d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev runTestOnUiThread(new Runnable() { 4653d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev @Override 4663d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev public void run() { 4673d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev mLayoutManager.scrollToPositionWithOffset(1, 0); 4683d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev mTestAdapter.clearOnUIThread(); 4693d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev } 4703d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev }); 4713d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev mLayoutManager.waitForLayout(2); 4723d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev 4733d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev assertEquals("Remaining children", 0, mLayoutManager.collectChildCoordinates().size()); 4743d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev } 4753d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev 4763d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev 477a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void testAccessibilityPositions() throws Throwable { 478a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar setupByConfig(new Config(VERTICAL, false, false), true); 479a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityDelegateCompat delegateCompat = mRecyclerView 480a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCompatAccessibilityDelegate(); 481a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityEvent event = AccessibilityEvent.obtain(); 482a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar runTestOnUiThread(new Runnable() { 483a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 484a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 485a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityEvent(mRecyclerView, event); 486a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 487a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 488a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityRecordCompat record = AccessibilityEventCompat 489a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .asRecord(event); 490a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have first position", 491a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.getFromIndex(), 492a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar mLayoutManager.findFirstVisibleItemPosition()); 493a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals("result should have last position", 494a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.getToIndex(), 495a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar mLayoutManager.findLastVisibleItemPosition()); 496a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 497d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar} 498