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