RecyclerViewAnimationsTest.java revision 0a017072206f93474ccd2706e7983c2ff778b904
1d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/*
2d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Copyright (C) 2014 The Android Open Source Project
3d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
4d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * you may not use this file except in compliance with the License.
6d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * You may obtain a copy of the License at
7d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
8d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
10d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Unless required by applicable law or agreed to in writing, software
11d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * See the License for the specific language governing permissions and
14d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * limitations under the License.
15d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
16d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
17d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepackage android.support.v7.widget;
18d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Test;
200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runner.RunWith;
210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
225a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyarimport android.graphics.Rect;
239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyarimport android.os.Debug;
24f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.support.annotation.NonNull;
250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
26f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyarimport android.support.v4.view.ViewCompat;
27f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest;
28b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log;
29b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View;
30504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup;
31b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
3211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList;
338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap;
3411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet;
3511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List;
3611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map;
3711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set;
38b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean;
39d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger;
400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*;
41d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
42121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/**
43121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Tests for {@link SimpleItemAnimator} API.
44121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */
45f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest
460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class)
47121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
48b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    final List<TestViewHolder> recycledVHs = new ArrayList<>();
509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detectStableIdError() throws Throwable {
53b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        final AtomicBoolean useBadIds = new AtomicBoolean(false);
54b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        TestAdapter adapter = new TestAdapter(10) {
55b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            @Override
56b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            public long getItemId(int position) {
57b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                if (useBadIds.get() && position == 5) {
58b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                    return super.getItemId(position) - 1;
59b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                }
60b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                return super.getItemId(position);
61b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            }
62b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
63b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            @Override
64b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
65b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                // ignore validation
66b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            }
67b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        };
68b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        adapter.setHasStableIds(true);
69b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        setupBasic(10, 0, 10, adapter);
70b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        mLayoutManager.expectLayouts(2);
71b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        useBadIds.set(true);
72b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        adapter.changeAndNotify(4, 2);
73b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        mLayoutManager.waitForLayout(2);
74b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        assertTrue(mainThreadException instanceof IllegalStateException);
75b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        assertTrue(mainThreadException.getMessage()
76b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                .contains("Two different ViewHolders have the same stable ID."));
77b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        // TODO don't use this after moving this class to Junit 4
78b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        try {
79b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            removeRecyclerView();
80b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        } catch (Throwable t){}
81b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        mainThreadException = null;
82b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar    }
83b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
84b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontLayoutReusedViewWithoutPredictive() throws Throwable {
879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    final TestViewHolder target) throws Throwable {
919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        fail("pre layout is not expected");
999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
1029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePostLayout(RecyclerView.Recycler recycler,
1039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
1049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
1059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 7;
1069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        View targetView = recycler
1079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                .getViewForPosition(target.getAdapterPosition());
1089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertSame(targetView, target.itemView);
1099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePostLayout(recycler, layoutManager, state);
1109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
1139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPostLayout(RecyclerView.Recycler recycler,
1149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
1159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
1169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPostLayout(recycler, layoutManager, state);
1179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertNull("test sanity. this view should not be re-laid out in post "
1189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + "layout", target.itemView.getParent());
1199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
1219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
1229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.requestSimpleAnimationsInNextLayout();
1239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
1249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
1259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                checkForMainThreadException();
1269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
1279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
1289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
1299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This is a LayoutManager problem if it asked for the view but didn't properly
1309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // lay it out. It will move to disappearance
1319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
1329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
1339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
1349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
1359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
1369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
1379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontLayoutReusedViewWithPredictive() throws Throwable {
1409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
1419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
1429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
1439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    final TestViewHolder target) throws Throwable {
1449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
1459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
1469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
1479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
1489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
1499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
1509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
1519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 9;
1529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePreLayout(recycler, lm, state);
1539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
1569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePostLayout(RecyclerView.Recycler recycler,
1579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
1589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
1599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 7;
1609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePostLayout(recycler, layoutManager, state);
1619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
1649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPostLayout(RecyclerView.Recycler recycler,
1659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
1669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
1679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPostLayout(recycler, layoutManager, state);
1689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertNull("test sanity. this view should not be re-laid out in post "
1699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + "layout", target.itemView.getParent());
1709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
1719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
1729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
1739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(1, 1);
1749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
1759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                checkForMainThreadException();
1769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
1779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
1789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
1799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This is a LayoutManager problem if it asked for the view but didn't properly
1809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // lay it out. It will move to disappearance.
1819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
1829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
1839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
1849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
1859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
1869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
1879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithoutPredictive() throws Throwable {
1909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
1919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
1929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
1939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
1949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
1959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
1969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
1979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
1989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.requestSimpleAnimationsInNextLayout();
1999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
2009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
2019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
2039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
2069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
2079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
2089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
2099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
2109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
2119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
2130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithoutAnimations() throws Throwable {
2149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
2159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
2169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
2179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
2189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
2199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
2209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
2219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
2229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
2239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
2249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
2269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
2299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
2309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
2319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
2329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
2339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
2349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
2360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithPredictive() throws Throwable {
2379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
2389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
2399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
2409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
2419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
2429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
2439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
2449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
2459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
2469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(2, 1);
2479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
2499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This LM does not layout the additional item so it does predictive wrong.
2509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // We should still handle it and animate persistence for this item
2519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
2549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
2559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mMoveVHs.contains(target));
2569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
2579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
2589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
2599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
2609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
2620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithProperPredictive() throws Throwable {
2639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
2649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
2659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
2669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
2679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
2689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
2699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
2709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
2719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
2729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
2749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
2759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 9;
2769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePreLayout(recycler, lm, state);
2779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPreLayout(RecyclerView.Recycler recycler,
2819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
2829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
2839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 8;
2849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPreLayout(recycler, layoutManager, state);
2859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
2879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
2899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(2, 1);
2909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
2929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This LM implements predictive animations properly by requesting target view
2939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // in pre-layout.
2949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
2979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
2989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mMoveVHs.contains(target));
2999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
3009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontReuseHiddenViewOnInvalidate() throws Throwable {
3069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
3119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
3159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.dispatchDataSetChanged();
3169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
3179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(mRecyclerView.getItemAnimator().isRunning());
3199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
3209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
3219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
3249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontReuseOnTypeChange() throws Throwable {
3309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
3359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
3399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                target.mBoundItem.mType += 2;
3409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
3419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
3439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
3449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mChangeOldVHs.contains(target));
3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    interface ReuseTestCallback {
3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    @Override
3639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    protected RecyclerView.ItemAnimator createItemAnimator() {
3649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        return new LoggingItemAnimator();
3659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
3689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        TestAdapter adapter = new TestAdapter(10) {
3699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void onViewRecycled(TestViewHolder holder) {
3719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                super.onViewRecycled(holder);
3729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                recycledVHs.add(holder);
3739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        };
3759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        setupBasic(10, 0, 10, adapter);
3769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.setItemViewCacheSize(0);
3779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
3789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setAddDuration(1000);
3799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setRemoveDuration(1000);
3809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setChangeDuration(1000);
3819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setMoveDuration(1000);
3829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
3839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.expectLayouts(2);
3849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        adapter.deleteAndNotify(2, 1);
3859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.waitForLayout(2);
3869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // test sanity, make sure target is hidden now
3879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
3889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        callback.postSetup(recycledVHs, target);
3899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
3909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
3919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
3929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detachBeforeAnimations() throws Throwable {
3970ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        setupBasic(10, 0, 5);
3980ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        final RecyclerView rv = mRecyclerView;
3990ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        waitForAnimations(2);
4000ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        final DefaultItemAnimator animator = new DefaultItemAnimator() {
4010ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            @Override
4020ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            public void runPendingAnimations() {
4030ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar                super.runPendingAnimations();
4040ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            }
4050ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        };
4060ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        rv.setItemAnimator(animator);
4070ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mLayoutManager.expectLayouts(2);
4080ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mTestAdapter.deleteAndNotify(3, 4);
4090ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mLayoutManager.waitForLayout(2);
4100ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        removeRecyclerView();
4110ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertNull("test sanity check RV should be removed", rv.getParent());
4120ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size());
4130ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertFalse("there should not be any animations running", animator.isRunning());
4140ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar    }
4150ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar
4160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
4170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void moveDeleted() throws Throwable {
4185a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        setupBasic(4, 0, 3);
4195a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        waitForAnimations(2);
4205a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        final View[] targetChild = new View[1];
4215a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        final LoggingItemAnimator animator = new LoggingItemAnimator();
4225a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        runTestOnUiThread(new Runnable() {
4235a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            @Override
4245a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            public void run() {
4255a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                mRecyclerView.setItemAnimator(animator);
4265a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                targetChild[0] = mRecyclerView.getChildAt(1);
4275a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            }
4285a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        });
4295a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
4305a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertNotNull("test sanity", targetChild);
4315a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.expectLayouts(1);
4325a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        runTestOnUiThread(new Runnable() {
4335a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            @Override
4345a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            public void run() {
4355a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
4365a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    @Override
4375a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
4389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
4395a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        if (view == targetChild[0]) {
4405a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                            outRect.set(10, 20, 30, 40);
4415a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        } else {
4425a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                            outRect.set(0, 0, 0, 0);
4435a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        }
4445a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    }
4455a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                });
4465a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            }
4475a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        });
4485a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.waitForLayout(1);
4495a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
4505a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        // now delete that item.
4515a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.expectLayouts(2);
4525a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]);
4535a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        targetChild[0] = null;
4545a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mTestAdapter.deleteAndNotify(1, 1);
4555a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.waitForLayout(2);
4565a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertFalse("if deleted view moves, it should not be in move animations",
4575a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                animator.mMoveVHs.contains(targetVH));
4585a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size());
4595a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH
4605a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        ));
4615a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar    }
4625a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
463344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    private void runTestImportantForAccessibilityWhileDeteling(
464344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            final int boundImportantForAccessibility,
465344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            final int expectedImportantForAccessibility) throws Throwable {
466344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Adapter binding the item to the initial accessibility option.
467344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // RecyclerView is expected to change it to 'expectedImportantForAccessibility'.
468344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        TestAdapter adapter = new TestAdapter(1) {
469344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
470344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void onBindViewHolder(TestViewHolder holder, int position) {
471344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                super.onBindViewHolder(holder, position);
472344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.setImportantForAccessibility(
473344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        holder.itemView, boundImportantForAccessibility);
474344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
475344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        };
476344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
477344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Set up with 1 item.
478344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        setupBasic(1, 0, 1, adapter);
479344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        waitForAnimations(2);
480344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        final View[] targetChild = new View[1];
481344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        final LoggingItemAnimator animator = new LoggingItemAnimator();
482344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        animator.setRemoveDuration(500);
483344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
484344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
485344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
486344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                mRecyclerView.setItemAnimator(animator);
487344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                targetChild[0] = mRecyclerView.getChildAt(0);
488344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
489344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
490344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
491344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
492344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
493344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
494344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        assertNotNull("test sanity", targetChild[0]);
495344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
496344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // now delete that item.
497344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.expectLayouts(2);
498344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mTestAdapter.deleteAndNotify(0, 1);
499344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
500344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.waitForLayout(2);
501344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
502344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
503344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
504344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
505344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view is still a child of mRecyclerView, and is invisible for accessibility.
506344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(targetChild[0].getParent() == mRecyclerView);
507344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
508344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
509344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
510344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
511344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
512344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
513344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        waitForAnimations(2);
514344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
515344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Delete animation is now complete.
516344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
517344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
518344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
519344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view is in recycled state, and back to the expected accessibility.
520344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(targetChild[0].getParent() == null);
521344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
522344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
523344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
524344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
525344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
526344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
527344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Add 1 element, which should use same view.
528344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.expectLayouts(2);
529344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mTestAdapter.addAndNotify(1);
530344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.waitForLayout(2);
531344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
532344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
533344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
534344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
535344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view should be reused, and have the expected accessibility.
536344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(
537344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0));
538344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
539344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
540344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
541344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
542344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
543344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
544344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
5450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingAuto() throws Throwable {
547344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
548344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO,
549344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
550344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
551344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
5520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingNo() throws Throwable {
554344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
555344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO,
556344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
557344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
558344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
5590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable {
561344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
562344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
563344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
564344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
565344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
5660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingYes() throws Throwable {
568344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
569344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
570344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
571344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
572344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
5730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void preLayoutPositionCleanup() throws Throwable {
57542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        setupBasic(4, 0, 4);
57642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.expectLayouts(2);
57742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
57842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            @Override
57942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler,
58042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
58142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutMin = 0;
58242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutItemCount = 3;
58342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            }
58442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
58542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            @Override
58642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            void beforePostLayout(RecyclerView.Recycler recycler,
58742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    AnimationLayoutManager layoutManager,
58842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    RecyclerView.State state) {
58942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutMin = 0;
59042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutItemCount = 4;
59142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            }
59242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        };
59342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mTestAdapter.addAndNotify(0, 1);
59442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.waitForLayout(2);
59542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
59642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
59742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar    }
59842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
5990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addRemoveSamePass() throws Throwable {
60193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final List<RecyclerView.ViewHolder> mRecycledViews
60293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
60393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        TestAdapter adapter = new TestAdapter(50) {
60493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
60593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public void onViewRecycled(TestViewHolder holder) {
60693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.onViewRecycled(holder);
60793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                mRecycledViews.add(holder);
60893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
60993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        };
61093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        adapter.setHasStableIds(true);
61193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        setupBasic(50, 3, 5, adapter);
61293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecyclerView.setItemViewCacheSize(0);
61393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> addVH
61493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
61593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> removeVH
61693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
61793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
61893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> moveVH
61993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
62093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
62193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final View[] testView = new View[1];
62293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
62393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
62493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateAdd(RecyclerView.ViewHolder holder) {
62593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                addVH.add(holder);
62693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
62793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
62893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
62993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
63093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateRemove(RecyclerView.ViewHolder holder) {
63193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                removeVH.add(holder);
63293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
63393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
63493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
63593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
63693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY,
63793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    int toX, int toY) {
63893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                moveVH.add(holder);
63993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
64093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
64193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        });
64293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
64393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
64493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            void afterPreLayout(RecyclerView.Recycler recycler,
64593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    AnimationLayoutManager layoutManager,
64693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    RecyclerView.State state) {
64793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.afterPreLayout(recycler, layoutManager, state);
64893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0] = recycler.getViewForPosition(45);
64993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST),
65093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST));
65193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(),
65293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        10 + testView[0].getMeasuredHeight());
65393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                layoutManager.addView(testView[0], 4);
65493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
65593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
65693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
65793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            void afterPostLayout(RecyclerView.Recycler recycler,
65893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    AnimationLayoutManager layoutManager,
65993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    RecyclerView.State state) {
66093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.afterPostLayout(recycler, layoutManager, state);
66193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(),
66293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        50 + testView[0].getMeasuredHeight());
66393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                layoutManager.addDisappearingView(testView[0], 4);
66493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
66593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        };
66693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3;
66793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5;
66893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecycledViews.clear();
66993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.expectLayouts(2);
67093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mTestAdapter.deleteAndNotify(3, 1);
67193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.waitForLayout(2);
67293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
67393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : addVH) {
67493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate add", testView[0], vh.itemView);
67593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
67693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : moveVH) {
67793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate move", testView[0], vh.itemView);
67893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
67993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : removeVH) {
68093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView);
68193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
68293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        boolean found = false;
68393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : mRecycledViews) {
68493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            found |= vh.itemView == testView[0];
68593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
68693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        assertTrue("added-removed view should be recycled", found);
68793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar    }
68893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
6890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void tmpRemoveMe() throws Throwable {
691121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        changeAnimTest(false, false, true, false);
692121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
693121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void changeAnimations() throws Throwable {
6967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final boolean[] booleans = {true, false};
6977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        for (boolean supportsChange : booleans) {
6987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            for (boolean changeType : booleans) {
6997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                for (boolean hasStableIds : booleans) {
7007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    for (boolean deleteSomeItems : booleans) {
7017c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems);
7027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    }
7037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    removeRecyclerView();
7047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
7057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
7077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    }
708121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
7097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
7109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
7117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final int changedIndex = 3;
7127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final int defaultType = 1;
7137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
7147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
7157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                ", change view type:" + changeType +
7167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                ", has stable ids:" + hasStableIds +
717121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                ", delete some items:" + deleteSomeItems;
7187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        TestAdapter testAdapter = new TestAdapter(10) {
7197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
7207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public int getItemViewType(int position) {
7217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                return position == changedIndex ? changedIndexNewType.get() : defaultType;
7227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
7257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public TestViewHolder onCreateViewHolder(ViewGroup parent,
7267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    int viewType) {
7277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
7287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (DEBUG) {
7297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    Log.d(TAG, logPrefix + " onCreateVH" + vh.toString());
7307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
7317c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                return vh;
7327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
7357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public void onBindViewHolder(TestViewHolder holder,
7367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    int position) {
7377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                super.onBindViewHolder(holder, position);
7387c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (DEBUG) {
7397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString());
7407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
7417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        };
7437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        testAdapter.setHasStableIds(hasStableIds);
7447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
7459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
746121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                supportsChangeAnim);
7477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final RecyclerView.ViewHolder toBeChangedVH =
749115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
7507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
7517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
7527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            void afterPreLayout(RecyclerView.Recycler recycler,
7537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    AnimationLayoutManager layoutManager,
7547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    RecyclerView.State state) {
755115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
756115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        changedIndex);
757121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertTrue(logPrefix + " changed view holder should have correct flag"
758121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        , vh.isUpdated());
7597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
7627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            void afterPostLayout(RecyclerView.Recycler recycler,
7637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    AnimationLayoutManager layoutManager, RecyclerView.State state) {
764115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
765115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        changedIndex);
7667c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (supportsChangeAnim) {
7677c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    assertNotSame(logPrefix + "a new VH should be given if change is supported",
7687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                            toBeChangedVH, vh);
7697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                } else if (!changeType && hasStableIds) {
7707c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    assertSame(logPrefix + "if change animations are not supported but we have "
7717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                            + "stable ids, same view holder should be returned", toBeChangedVH, vh);
7727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
7737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                super.beforePostLayout(recycler, layoutManager, state);
7747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
7757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        };
7767c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.expectLayouts(1);
7777c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        if (changeType) {
7787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            changedIndexNewType.set(defaultType + 1);
7797c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
7807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        if (deleteSomeItems) {
7817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            runTestOnUiThread(new Runnable() {
7827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                @Override
7837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                public void run() {
7847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    try {
7857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        mTestAdapter.deleteAndNotify(changedIndex + 2, 1);
7867c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        mTestAdapter.notifyItemChanged(3);
7877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    } catch (Throwable throwable) {
7887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        throwable.printStackTrace();
7897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    }
7907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
7927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            });
7937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        } else {
794121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mTestAdapter.changeAndNotify(3, 1);
7957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
7967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
7977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.waitForLayout(2);
7987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    }
7997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
800f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar    private void testChangeWithPayload(final boolean supportsChangeAnim, final boolean canReUse,
8019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
8029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            throws Throwable {
80321b345f101abc385496f42d250e580d21f1287b6Dake Gu        final List<Object> expectedPayloads = new ArrayList<Object>();
80421b345f101abc385496f42d250e580d21f1287b6Dake Gu        final int changedIndex = 3;
80521b345f101abc385496f42d250e580d21f1287b6Dake Gu        TestAdapter testAdapter = new TestAdapter(10) {
80621b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
80721b345f101abc385496f42d250e580d21f1287b6Dake Gu            public int getItemViewType(int position) {
80821b345f101abc385496f42d250e580d21f1287b6Dake Gu                return 1;
80921b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
81021b345f101abc385496f42d250e580d21f1287b6Dake Gu
81121b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
81221b345f101abc385496f42d250e580d21f1287b6Dake Gu            public TestViewHolder onCreateViewHolder(ViewGroup parent,
81321b345f101abc385496f42d250e580d21f1287b6Dake Gu                    int viewType) {
81421b345f101abc385496f42d250e580d21f1287b6Dake Gu                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
81521b345f101abc385496f42d250e580d21f1287b6Dake Gu                if (DEBUG) {
81621b345f101abc385496f42d250e580d21f1287b6Dake Gu                    Log.d(TAG, " onCreateVH" + vh.toString());
81721b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
81821b345f101abc385496f42d250e580d21f1287b6Dake Gu                return vh;
81921b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
82021b345f101abc385496f42d250e580d21f1287b6Dake Gu
82121b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
82221b345f101abc385496f42d250e580d21f1287b6Dake Gu            public void onBindViewHolder(TestViewHolder holder,
82321b345f101abc385496f42d250e580d21f1287b6Dake Gu                    int position, List<Object> payloads) {
82421b345f101abc385496f42d250e580d21f1287b6Dake Gu                super.onBindViewHolder(holder, position);
82521b345f101abc385496f42d250e580d21f1287b6Dake Gu                if (DEBUG) {
82621b345f101abc385496f42d250e580d21f1287b6Dake Gu                    Log.d(TAG, " onBind to " + position + "" + holder.toString());
82721b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
828f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                assertEquals(expectedPayloads, payloads);
82921b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
83021b345f101abc385496f42d250e580d21f1287b6Dake Gu        };
83121b345f101abc385496f42d250e580d21f1287b6Dake Gu        testAdapter.setHasStableIds(false);
83221b345f101abc385496f42d250e580d21f1287b6Dake Gu        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
833f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
834f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            @Override
835f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
836f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                    @NonNull List<Object> payloads) {
837f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads);
838f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            }
839f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        });
8409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
841121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                supportsChangeAnim);
84221b345f101abc385496f42d250e580d21f1287b6Dake Gu
84321b345f101abc385496f42d250e580d21f1287b6Dake Gu        int numTests = notifyPayloads.length;
8449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        for (int i = 0; i < numTests; i++) {
84521b345f101abc385496f42d250e580d21f1287b6Dake Gu            mLayoutManager.expectLayouts(1);
84621b345f101abc385496f42d250e580d21f1287b6Dake Gu            expectedPayloads.clear();
84721b345f101abc385496f42d250e580d21f1287b6Dake Gu            for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
84821b345f101abc385496f42d250e580d21f1287b6Dake Gu                expectedPayloads.add(expectedPayloadsInOnBind[i][j]);
84921b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
85021b345f101abc385496f42d250e580d21f1287b6Dake Gu            final Object[] payloadsToSend = notifyPayloads[i];
85121b345f101abc385496f42d250e580d21f1287b6Dake Gu            runTestOnUiThread(new Runnable() {
85221b345f101abc385496f42d250e580d21f1287b6Dake Gu                @Override
85321b345f101abc385496f42d250e580d21f1287b6Dake Gu                public void run() {
85421b345f101abc385496f42d250e580d21f1287b6Dake Gu                    for (int j = 0; j < payloadsToSend.length; j++) {
85521b345f101abc385496f42d250e580d21f1287b6Dake Gu                        mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]);
85621b345f101abc385496f42d250e580d21f1287b6Dake Gu                    }
85721b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
85821b345f101abc385496f42d250e580d21f1287b6Dake Gu            });
85921b345f101abc385496f42d250e580d21f1287b6Dake Gu            mLayoutManager.waitForLayout(2);
8609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            checkForMainThreadException();
86121b345f101abc385496f42d250e580d21f1287b6Dake Gu        }
86221b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
86321b345f101abc385496f42d250e580d21f1287b6Dake Gu
8640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
8650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void crossFadingChangeAnimationWithPayload() throws Throwable {
86621b345f101abc385496f42d250e580d21f1287b6Dake Gu        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
867f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(true, true,
868f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                new Object[][]{
869f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc"},
870f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", null, "cdf"},
871f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", null},
872f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{null, "abc"},
873f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", "cdf"}
874f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                },
875f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                new Object[][]{
876f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc"},
877f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
878f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
879f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
880f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", "cdf"}
881f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                });
882f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar    }
883f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar
8840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
8850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable {
886f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
887f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(true, false,
88821b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
8899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
8909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null, "cdf"},
8919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null},
8929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{null, "abc"},
8939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
89421b345f101abc385496f42d250e580d21f1287b6Dake Gu                },
89521b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
8969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
8979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
8989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
8999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
9009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0]
90121b345f101abc385496f42d250e580d21f1287b6Dake Gu                });
90221b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
90321b345f101abc385496f42d250e580d21f1287b6Dake Gu
9040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
9050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void noChangeAnimationWithPayload() throws Throwable {
90621b345f101abc385496f42d250e580d21f1287b6Dake Gu        // for Change Animation disabled, payload should match the payloads unless
90721b345f101abc385496f42d250e580d21f1287b6Dake Gu        // null payload is fired.
908f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(false, true,
90921b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
9109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
9119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null, "cdf"},
9129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null},
9139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{null, "abc"},
9149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
91521b345f101abc385496f42d250e580d21f1287b6Dake Gu                },
91621b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
9179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
9189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
9199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
9209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
9219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
92221b345f101abc385496f42d250e580d21f1287b6Dake Gu                });
92321b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
92421b345f101abc385496f42d250e580d21f1287b6Dake Gu
9250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
9260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleDuringAnimations() throws Throwable {
927504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        final AtomicInteger childCount = new AtomicInteger(0);
928504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        final TestAdapter adapter = new TestAdapter(1000) {
929504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
930504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public TestViewHolder onCreateViewHolder(ViewGroup parent,
931504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                    int viewType) {
932504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                childCount.incrementAndGet();
933504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                return super.onCreateViewHolder(parent, viewType);
934504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
935504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        };
936504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        setupBasic(1000, 10, 20, adapter);
937504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10;
938504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20;
939504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
940504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
941504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
942504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public void putRecycledView(RecyclerView.ViewHolder scrap) {
943504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                super.putRecycledView(scrap);
944504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                childCount.decrementAndGet();
945504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
946504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
947504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
948504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public RecyclerView.ViewHolder getRecycledView(int viewType) {
949504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
950504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                if (recycledView != null) {
951504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                    childCount.incrementAndGet();
952504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                }
953504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                return recycledView;
954504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
955504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        });
956504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
957504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        // now keep adding children to trigger more children being created etc.
9589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        for (int i = 0; i < 100; i++) {
959504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            adapter.addAndNotify(15, 1);
960504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            Thread.sleep(50);
961504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        }
962504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        getInstrumentation().waitForIdleSync();
963504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        waitForAnimations(2);
964504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        assertEquals("Children count should add up", childCount.get(),
965504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
966504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar    }
967504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
9680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
9690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChanged() throws Throwable {
970b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        setupBasic(10, 3, 4);
971b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        int layoutCount = mLayoutManager.mTotalLayoutCount;
972b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(1);
973b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        runTestOnUiThread(new Runnable() {
974b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            @Override
975b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            public void run() {
976b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                try {
977b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    mTestAdapter.deleteAndNotify(4, 1);
978cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    mTestAdapter.dispatchDataSetChanged();
979b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                } catch (Throwable throwable) {
980b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    throwable.printStackTrace();
981b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                }
982b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
983b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            }
984b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        });
985b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
986b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        getInstrumentation().waitForIdleSync();
987b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        assertEquals("on notify data set changed, predictive animations should not run",
988b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                layoutCount + 1, mLayoutManager.mTotalLayoutCount);
989b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(2);
990b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mTestAdapter.addAndNotify(4, 2);
991b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        // make sure animations recover
992b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
993b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar    }
994b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
9950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
9960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void stableIdNotifyDataSetChanged() throws Throwable {
997e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int itemCount = 20;
998e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        List<Item> initialSet = new ArrayList<Item>();
999e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestAdapter adapter = new TestAdapter(itemCount) {
1000e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
1001e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public long getItemId(int position) {
1002e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return mItems.get(position).mId;
1003e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
1004e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
1005e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        adapter.setHasStableIds(true);
1006e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        initialSet.addAll(adapter.mItems);
1007e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
10089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
10099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter testAdapter) throws Throwable {
10109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        Item item5 = adapter.mItems.get(5);
10119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        Item item6 = adapter.mItems.get(6);
10129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        item5.mAdapterIndex = 6;
10139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        item6.mAdapterIndex = 5;
10149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.mItems.remove(5);
10159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.mItems.add(6, item5);
10169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.dispatchDataSetChanged();
10179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        //hacky, we support only 1 layout pass
10189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutManager.layoutLatch.countDown();
10199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
10209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
1021e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
1022e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(9, -1, 9));
1023e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        // now mix items.
1024e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
1025e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
1026d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
10270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void getItemForDeletedView() throws Throwable {
10298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(false);
10308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(true);
103111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
103211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
10338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void getItemForDeletedViewTest(boolean stableIds) throws Throwable {
103411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemViewTypeQueries = new HashSet<Integer>();
103511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemIdQueries = new HashSet<Integer>();
103611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        TestAdapter adapter = new TestAdapter(10) {
103711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
103811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public int getItemViewType(int position) {
103911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.add(position);
104011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return super.getItemViewType(position);
104111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
104211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
104311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
104411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public long getItemId(int position) {
104511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemIdQueries.add(position);
104611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return mItems.get(position).mId;
104711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
104811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        };
104911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.setHasStableIds(stableIds);
105011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        setupBasic(10, 0, 10, adapter);
105111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        assertEquals("getItemViewType for all items should be called", 10,
105211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.size());
105311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        if (adapter.hasStableIds()) {
105411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should be called when adapter has stable ids", 10,
105511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
105611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        } else {
105711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should not be called when adapter does not have stable ids", 0,
105811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
105911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
106011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemViewTypeQueries.clear();
106111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemIdQueries.clear();
106211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.expectLayouts(2);
106311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        // delete last two
106411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteStart = 8;
106511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteCount = adapter.getItemCount() - deleteStart;
106611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.deleteAndNotify(deleteStart, deleteCount);
106711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.waitForLayout(2);
106811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = 0; i < deleteStart; i++) {
106911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertTrue("getItemViewType for existing item " + i + " should be called",
107011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
107111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
107211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                assertTrue("getItemId for existing item " + i
10739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + " should be called when adapter has stable ids",
107411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
107511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
107611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
107711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = deleteStart; i < deleteStart + deleteCount; i++) {
107811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called",
107911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
108011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
10818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called",
108211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
108311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
108411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
108511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
108611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
10870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteInvisibleMultiStep() throws Throwable {
10898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(1000, 1, 7);
10908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
10918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
10928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
10938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
10948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
10958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
10968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});
109790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            checkForMainThreadException();
10988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount -= 2;
10998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
11008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
11018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
11028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
11038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
11048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
11058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
11068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addManyMultiStep() throws Throwable {
11098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10, 1, 7);
11108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
11118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
11128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
11138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
11148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
11158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
1116e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
11178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(0, 1);
1118e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
11198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(7, 1);
11208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount += 2;
11218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1122e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        checkForMainThreadException();
11238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
11248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
11258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
1126e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
11278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
11288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
11298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
11308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void basicDelete() throws Throwable {
11338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
11348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() {
11358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
11368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void postDispatchLayout() {
11378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // verify this only in first layout
11388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("deleted views should still be children of RV",
11398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        mLayoutManager.getChildCount() + mDeletedViewCount
11408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        , mRecyclerView.getChildCount());
11418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
11428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
11448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void afterPreLayout(RecyclerView.Recycler recycler,
11458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    AnimationLayoutManager layoutManager,
11468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
11478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.afterPreLayout(recycler, layoutManager, state);
11488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutItemCount = 3;
11498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutMin = 0;
11508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
11518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
11528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.mLayoutItemCount = 10;
11538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.setExpectedItemCounts(10, 3);
11548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(callbacks);
11558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(2);
11578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(0, 7);
11588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
11598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.reset();// when animations end another layout will happen
11608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
11618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
11630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringScrolling() throws Throwable {
1165d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        setupBasic(10);
1166d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
1167d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
1168d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1169d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
1170d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1171d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            void onLayoutChildren(RecyclerView.Recycler recycler,
1172d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
1173d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onLayoutItemCount.set(state.getItemCount());
1174d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onLayoutChildren(recycler, lm, state);
1175d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1176d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1177d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1178d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
1179d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onScrollItemCount.set(state.getItemCount());
1180d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onScroll(dx, recycler, state);
1181d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1182d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
1183d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        runTestOnUiThread(new Runnable() {
1184d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1185d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void run() {
1186d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.mItems.remove(5);
1187d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.notifyItemRangeRemoved(5, 1);
1188d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mRecyclerView.scrollBy(0, 100);
1189d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertTrue("scrolling while there are pending adapter updates should "
1190d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
1191d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertEquals("scroll by should be called w/ updated adapter count",
1192d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        mTestAdapter.mItems.size(), onScrollItemCount.get());
1193d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1194d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1195d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
1196d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar    }
1197d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
11980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChangedDuringScroll() throws Throwable {
120017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        setupBasic(10);
120117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
120217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
120317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
120417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
120517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
120617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            void onLayoutChildren(RecyclerView.Recycler recycler,
120717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
120817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                onLayoutItemCount.set(state.getItemCount());
120917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                super.onLayoutChildren(recycler, lm, state);
121017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
121117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
121217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
121317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
121417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                onScrollItemCount.set(state.getItemCount());
121517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                super.onScroll(dx, recycler, state);
121617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
121717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        });
121817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        runTestOnUiThread(new Runnable() {
121917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
122017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            public void run() {
122117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mTestAdapter.mItems.remove(5);
122217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mTestAdapter.notifyDataSetChanged();
122317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mRecyclerView.scrollBy(0, 100);
122417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                assertTrue("scrolling while there are pending adapter updates should "
122517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
122617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                assertEquals("scroll by should be called w/ updated adapter count",
122717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                        mTestAdapter.mItems.size(), onScrollItemCount.get());
122817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
122917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
123017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        });
123117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar    }
123217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
12330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addInvisibleAndVisible() throws Throwable {
1235b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
1236b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
1237b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible
1239b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1240b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1241b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
12420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addInvisible() throws Throwable {
1244b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
1245b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
1246b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0
1248b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1249b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1250b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
12510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void basicAdd() throws Throwable {
1253b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10);
1254b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
1255b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(10, 13);
1256b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.addAndNotify(2, 3);
1257b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1258b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1259b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
12600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void appCancelAnimationInDetach() throws Throwable {
1262a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        final View[] addedView = new View[2];
1263a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        TestAdapter adapter = new TestAdapter(1) {
1264a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            @Override
1265a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            public void onViewDetachedFromWindow(TestViewHolder holder) {
1266a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView)
1267f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        && ViewCompat.hasTransientState(holder.itemView)) {
1268f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                    ViewCompat.animate(holder.itemView).cancel();
1269a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                }
1270a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                super.onViewDetachedFromWindow(holder);
1271a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            }
1272a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        };
1273a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // original 1 item
1274a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        setupBasic(1, 0, 1, adapter);
1275cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        mRecyclerView.getItemAnimator().setAddDuration(10000);
1276a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.expectLayouts(2);
1277a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // add 2 items
1278a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        setExpectedItemCounts(1, 3);
1279a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mTestAdapter.addAndNotify(0, 2);
1280629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar        mLayoutManager.waitForLayout(2, false);
1281629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar        checkForMainThreadException();
1282a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // wait till "add animation" starts
1283e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        int limit = 200;
1284a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        while (addedView[0] == null || addedView[1] == null) {
1285629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar            Thread.sleep(100);
1286a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            runTestOnUiThread(new Runnable() {
1287a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                @Override
1288a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                public void run() {
1289a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    if (mRecyclerView.getChildCount() == 3) {
1290a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        View view = mRecyclerView.getChildAt(0);
1291f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        if (ViewCompat.hasTransientState(view)) {
1292a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                            addedView[0] = view;
1293a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        }
1294a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        view = mRecyclerView.getChildAt(1);
1295f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        if (ViewCompat.hasTransientState(view)) {
1296a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                            addedView[1] = view;
1297a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        }
1298a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    }
1299a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                }
1300a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            });
1301e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            assertTrue("add should start on time", --limit > 0);
1302a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        }
1303a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu
1304a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // Layout from item2, exclude the current adding items
1305a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.expectLayouts(1);
1306a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
1307a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            @Override
1308a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            void beforePostLayout(RecyclerView.Recycler recycler,
1309a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    AnimationLayoutManager layoutManager,
1310a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    RecyclerView.State state) {
1311a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                mLayoutMin = 2;
1312a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                mLayoutItemCount = 1;
1313a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            }
1314a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        };
1315a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        requestLayoutOnUIThread(mRecyclerView);
1316a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.waitForLayout(2);
1317a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu    }
1318a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu
13190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeFrozen() throws Throwable {
1321ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setupBasic(10, 1, 7);
1322ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertTrue(mRecyclerView.getChildCount() == 7);
1323ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1324ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.expectLayouts(2);
1325ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
1326ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
1327ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
1328ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mTestAdapter.addAndNotify(0, 1);
1329ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1330ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2);
1331ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals(7, mRecyclerView.getChildCount());
1332ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1333ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
1334ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.waitForLayout(2);
1335ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("RV should get updated after waken from frozen",
1336ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                8, mRecyclerView.getChildCount());
1337ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
1338ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
13390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void removeScrapInvalidate() throws Throwable {
1341888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        setupBasic(10);
1342888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        TestRecyclerView testRecyclerView = getTestRecyclerView();
1343888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.expectLayouts(1);
1344888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.expectDraw(1);
1345888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        runTestOnUiThread(new Runnable() {
1346888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            @Override
1347888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            public void run() {
1348888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.mItems.clear();
1349888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.notifyDataSetChanged();
1350888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            }
1351888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        });
1352888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.waitForLayout(2);
1353888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.waitForDraw(2);
1354888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    }
1355888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
13560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteVisibleAndInvisible() throws Throwable {
1358b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(11, 3, 5); //layout items  3 4 5 6 7
1359b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
13608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list
1361b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(9, 8);
1362b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9
1363b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1364b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1365b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
13660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findPositionOffset() throws Throwable {
13688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
136990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
137090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            @Override
137190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler,
137290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
137390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                super.beforePreLayout(recycler, lm, state);
137490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                // [0,2,4]
137590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0));
137690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2));
137790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4));
137890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            }
137990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        };
13808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        runTestOnUiThread(new Runnable() {
13818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
13828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void run() {
1383121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                try {
1384121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    // delete 1
1385121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    mTestAdapter.deleteAndNotify(1, 1);
1386121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    // delete 3
1387121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    mTestAdapter.deleteAndNotify(2, 1);
1388121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                } catch (Throwable throwable) {
1389121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    throwable.printStackTrace();
1390121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
13918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
13928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        });
139390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        mLayoutManager.waitForLayout(2);
13948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
13958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1396b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setLayoutRange(int start, int count) {
1397b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start;
1398b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count;
1399b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1400b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
1401b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setExpectedItemCounts(int preLayout, int postLayout) {
1402b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout);
1403b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1404b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
14050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteInvisible() throws Throwable {
1407b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
14088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
14098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
1410b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
1411b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8);
14128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8
1413b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1414b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1415b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
1416e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    private CollectPositionResult findByPos(RecyclerView recyclerView,
1417e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int position) {
1418e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        View view = recycler.getViewForPosition(position, true);
1419e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
1420e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        if (vh.wasReturnedFromScrap()) {
1421e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            vh.clearReturnedFromScrapFlag(); //keep data consistent.
1422e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromScrap(vh);
1423e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        } else {
1424e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromAdapter(vh);
14258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
14268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
14278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1428e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView,
1429e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) {
14308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        Map<Integer, CollectPositionResult> positionToAdapterMapping
14318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                = new HashMap<Integer, CollectPositionResult>();
14328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int position : positions) {
14338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (position < 0) {
14348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                continue;
14358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1436e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            positionToAdapterMapping.put(position,
1437e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    findByPos(recyclerView, recycler, state, position));
14388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
14398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return positionToAdapterMapping;
14408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
14418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
14420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addDelete2() throws Throwable {
14448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
14459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 3 4
14469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 a b 3 4
14479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 b 3 4
14489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre: 0 1 2 3 4
14499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre w/ adap: 0 1 2 b 3 4
14509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
14519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
14529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
14539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
14549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
14558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(3, 3, 3)
14568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
14578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
1458d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
14590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addDelete1() throws Throwable {
14618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
14629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 3 4
14639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 a b 3 4
14649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 2 a b 3 4
14659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 c d 2 a b 3 4
14669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 c d 2 a 4
14679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // c d 2 a 4
14689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre: 0 1 2 3 4
14699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
14709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
14719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
14729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
14739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
14749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
14758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
14768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
14778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapter(1), PositionConstraint.adapter(3)
14788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
14798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
14808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
14810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addSameIndexTwice() throws Throwable {
14838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
14849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
14859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
14869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
14879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{11, 1});
14889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
14899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
14908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
14918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
14928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(8, 8, 13)
14938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
14948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
14958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
14960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteTwice() throws Throwable {
14988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
14999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
15009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
15019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
15029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{0, 1});// delete item ids 0,2,9,1
15039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
15049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
15058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
15068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
15078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
15088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
15098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
15108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1511b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
15128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
1513e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            int firstLayoutItemCount, AdapterOps adapterChanges,
1514e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
1515e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
15169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                adapterChanges, constraints);
1517e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
15189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1519e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
15209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
1521e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
1522e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
1523b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
15248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
15258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
15268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
15278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
15288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePreLayout(recycler, lm, state);
15298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                //harmless
15308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
15318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
15328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
15338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPreLayoutPos;
15348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
15358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
1536e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
1537121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
1538121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
15399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    positionLog.append(entry.getKey()).append(":").append(entry.getValue())
15409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            .append("\n");
1541121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
15428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
15438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPreLayoutPos != -1) {
15448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPreLayoutPos),
1545121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                lm.getLog() + positionLog);
15468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
15478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
15488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
15498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
15508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
15518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
15528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
15538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePostLayout(recycler, lm, state);
15548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
15558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
15568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
15578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPostLayoutPos;
15588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
15598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
1560e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
1561121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
1562121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
1563121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    positionLog.append(entry.getKey()).append(":")
1564121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            .append(entry.getValue()).append("\n");
1565121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
15668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
15678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPostLayoutPos >= 0) {
15688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPostLayoutPos),
1569121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                lm.getLog() + positionLog);
15708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
15718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
15728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
15738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
15748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        adapterChanges.run(mTestAdapter);
1575b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1576e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
15778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (PositionConstraint constraint : constraints) {
15788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.assertValidate();
15798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1580b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1581b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
15820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
15830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addThenRecycleRemovedView() throws Throwable {
15846a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        setupBasic(10);
15856a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final AtomicInteger step = new AtomicInteger(0);
15869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final List<RecyclerView.ViewHolder> animateRemoveList
15879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
15886a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        DefaultItemAnimator animator = new DefaultItemAnimator() {
15896a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
15906a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            public boolean animateRemove(RecyclerView.ViewHolder holder) {
15916a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                animateRemoveList.add(holder);
15926a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                return super.animateRemove(holder);
15936a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
15946a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        };
15956a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mRecyclerView.setItemAnimator(animator);
15966a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>();
15976a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
15986a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
15996a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            public void putRecycledView(RecyclerView.ViewHolder scrap) {
16006a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                pooledViews.add(scrap);
16016a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                super.putRecycledView(scrap);
16026a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
16036a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        });
16046a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1];
16056a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
16066a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
16076a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            void doLayout(RecyclerView.Recycler recycler,
16086a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
16096a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                switch (step.get()) {
16106a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                    case 1:
16116a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        super.doLayout(recycler, lm, state);
16126a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        if (state.isPreLayout()) {
16136a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            View view = mLayoutManager.getChildAt(1);
16146a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            RecyclerView.ViewHolder holder =
16156a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                                    mRecyclerView.getChildViewHolderInt(view);
16166a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            targetVh[0] = holder;
16176a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            assertTrue("test sanity", holder.isRemoved());
16186a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            mLayoutManager.removeAndRecycleView(view, recycler);
16196a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        }
16206a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        break;
16216a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                }
16226a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
16236a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        };
16246a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        step.set(1);
16256a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        animateRemoveList.clear();
16266a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.expectLayouts(2);
16276a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mTestAdapter.deleteAndNotify(1, 1);
16286a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.waitForLayout(2);
16296a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0]));
16306a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        assertTrue("since LM force recycled a view, animate disappearance should not be called",
16316a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                animateRemoveList.isEmpty());
16326a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar    }
1633d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
1634