RecyclerViewAnimationsTest.java revision e0c347f627f8a78d3e5e3e5eaac9c3ae26208689
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
19b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.content.Context;
20888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyarimport android.graphics.Canvas;
21b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.AttributeSet;
22b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log;
23b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View;
24b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
2511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList;
268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap;
2711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet;
2811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List;
2911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map;
3011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set;
31888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyarimport java.util.concurrent.CountDownLatch;
32d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit;
33d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger;
34d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
35d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
36d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
37668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar    private static final boolean DEBUG = false;
38b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
39b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private static final String TAG = "RecyclerViewAnimationsTest";
40b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
41b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    AnimationLayoutManager mLayoutManager;
42b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
43b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    TestAdapter mTestAdapter;
44b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
45b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public RecyclerViewAnimationsTest() {
46b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        super(DEBUG);
47b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
48b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
49b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    @Override
50b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    protected void setUp() throws Exception {
51b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        super.setUp();
52b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
53b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
54b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    RecyclerView setupBasic(int itemCount) throws Throwable {
55b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        return setupBasic(itemCount, 0, itemCount);
56b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
57b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
58b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
59b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            throws Throwable {
6011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
6111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
6211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
6311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
6411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            TestAdapter testAdapter)
6511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            throws Throwable {
66888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
67b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        recyclerView.setHasFixedSize(true);
6811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        if (testAdapter == null) {
6911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            mTestAdapter = new TestAdapter(itemCount);
7011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        } else {
7111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            mTestAdapter = testAdapter;
7211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
73b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        recyclerView.setAdapter(mTestAdapter);
74b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager = new AnimationLayoutManager();
75b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        recyclerView.setLayoutManager(mLayoutManager);
76b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
77b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
78b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
79b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
80888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        recyclerView.expectDraw(1);
81b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setRecyclerView(recyclerView);
82b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
83888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        recyclerView.waitForDraw(1);
84888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.reset();
858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getInstrumentation().waitForIdleSync();
86b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        assertEquals("all expected children should be laid out", firstLayoutItemCount,
888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutManager.getChildCount());
89b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        return recyclerView;
90b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
91b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
92b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar    public void testNotifyDataSetChanged() throws Throwable {
93b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        setupBasic(10, 3, 4);
94b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        int layoutCount = mLayoutManager.mTotalLayoutCount;
95b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(1);
96b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        runTestOnUiThread(new Runnable() {
97b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            @Override
98b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            public void run() {
99b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                try {
100b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    mTestAdapter.deleteAndNotify(4, 1);
101b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    mTestAdapter.notifyChange();
102b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                } catch (Throwable throwable) {
103b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    throwable.printStackTrace();
104b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                }
105b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
106b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            }
107b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        });
108b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
109b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        getInstrumentation().waitForIdleSync();
110b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        assertEquals("on notify data set changed, predictive animations should not run",
111b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                layoutCount + 1, mLayoutManager.mTotalLayoutCount);
112b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(2);
113b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mTestAdapter.addAndNotify(4, 2);
114b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        // make sure animations recover
115b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
116b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar    }
117b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
118e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public void testStableIdNotifyDataSetChanged() throws Throwable {
119e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int itemCount = 20;
120e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        List<Item> initialSet = new ArrayList<Item>();
121e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestAdapter adapter = new TestAdapter(itemCount) {
122e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
123e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public long getItemId(int position) {
124e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return mItems.get(position).mId;
125e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
126e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
127e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        adapter.setHasStableIds(true);
128e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        initialSet.addAll(adapter.mItems);
129e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
130e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
131e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            void onRun(TestAdapter testAdapter) throws Throwable {
132e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                Item item5 = adapter.mItems.get(5);
133e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                Item item6 = adapter.mItems.get(6);
134e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                item5.mAdapterIndex = 6;
135e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                item6.mAdapterIndex = 5;
136e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                adapter.mItems.remove(5);
137e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                adapter.mItems.add(6, item5);
138e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                adapter.notifyChange();
139e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                //hacky, we support only 1 layout pass
140e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                mLayoutManager.layoutLatch.countDown();
141e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(9, -1, 9));
145e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        // now mix items.
146e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
147e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
148d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testGetItemForDeletedView() throws Throwable {
1508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(false);
1518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(true);
15211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
15311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
1548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void getItemForDeletedViewTest(boolean stableIds) throws Throwable {
15511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemViewTypeQueries = new HashSet<Integer>();
15611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemIdQueries = new HashSet<Integer>();
15711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        TestAdapter adapter = new TestAdapter(10) {
15811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
15911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public int getItemViewType(int position) {
16011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.add(position);
16111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return super.getItemViewType(position);
16211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
16311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
16411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
16511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public long getItemId(int position) {
16611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemIdQueries.add(position);
16711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return mItems.get(position).mId;
16811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
16911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        };
17011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.setHasStableIds(stableIds);
17111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        setupBasic(10, 0, 10, adapter);
17211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        assertEquals("getItemViewType for all items should be called", 10,
17311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.size());
17411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        if (adapter.hasStableIds()) {
17511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should be called when adapter has stable ids", 10,
17611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
17711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        } else {
17811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should not be called when adapter does not have stable ids", 0,
17911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
18011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
18111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemViewTypeQueries.clear();
18211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemIdQueries.clear();
18311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.expectLayouts(2);
18411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        // delete last two
18511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteStart = 8;
18611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteCount = adapter.getItemCount() - deleteStart;
18711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.deleteAndNotify(deleteStart, deleteCount);
18811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.waitForLayout(2);
18911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = 0; i < deleteStart; i++) {
19011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertTrue("getItemViewType for existing item " + i + " should be called",
19111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
19211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
19311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                assertTrue("getItemId for existing item " + i
19411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        + " should be called when adapter has stable ids",
19511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
19611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
19711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
19811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = deleteStart; i < deleteStart + deleteCount; i++) {
19911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called",
20011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
20111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
2028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called",
20311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
20411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
20511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
20611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
20711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
2088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testDeleteInvisibleMultiStep() throws Throwable {
2098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(1000, 1, 7);
2108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
2118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
2128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
2138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
2148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
2158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
2168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});
2178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount -= 2;
2188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
2208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
2218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
2228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
2248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
2258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testAddManyMultiStep() throws Throwable {
2278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10, 1, 7);
2288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
2298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
2308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
2318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
2328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
2338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
2348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(0, 1);
2358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(7, 1);
2368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount += 2;
2378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
2398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
2408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
2418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
2428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
2438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
2448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testBasicDelete() throws Throwable {
2468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
2478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() {
2488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
2498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void postDispatchLayout() {
2508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // verify this only in first layout
2518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("deleted views should still be children of RV",
2528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        mLayoutManager.getChildCount() + mDeletedViewCount
2538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        , mRecyclerView.getChildCount());
2548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
2558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
2578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void afterPreLayout(RecyclerView.Recycler recycler,
2588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    AnimationLayoutManager layoutManager,
2598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
2608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.afterPreLayout(recycler, layoutManager, state);
2618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutItemCount = 3;
2628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutMin = 0;
2638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
2648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
2658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.mLayoutItemCount = 10;
2668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.setExpectedItemCounts(10, 3);
2678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(callbacks);
2688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(2);
2708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(0, 7);
2718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
2728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.reset();// when animations end another layout will happen
2738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
2748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
2758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
276d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar    public void testAdapterChangeDuringScrolling() throws Throwable {
277d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        setupBasic(10);
278d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
279d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
280d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
281d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
282d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
283d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            void onLayoutChildren(RecyclerView.Recycler recycler,
284d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
285d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onLayoutItemCount.set(state.getItemCount());
286d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onLayoutChildren(recycler, lm, state);
287d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
288d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
289d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
290d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
291d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onScrollItemCount.set(state.getItemCount());
292d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onScroll(dx, recycler, state);
293d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
294d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
295d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        runTestOnUiThread(new Runnable() {
296d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
297d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void run() {
298d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.mItems.remove(5);
299d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.notifyItemRangeRemoved(5, 1);
300d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mRecyclerView.scrollBy(0, 100);
301d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertTrue("scrolling while there are pending adapter updates should "
302d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
303d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertEquals("scroll by should be called w/ updated adapter count",
304d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        mTestAdapter.mItems.size(), onScrollItemCount.get());
305d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
306d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
307d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
308d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar    }
309d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
310b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public void testAddInvisibleAndVisible() throws Throwable {
311b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
312b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
313b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
3142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible
315b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
316b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
317b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
318b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public void testAddInvisible() throws Throwable {
319b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
320b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
321b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
3222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0
323b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
324b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
325b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
326b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public void testBasicAdd() throws Throwable {
327b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10);
328b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
329b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(10, 13);
330b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.addAndNotify(2, 3);
331b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
332b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
333b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
334888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    public TestRecyclerView getTestRecyclerView() {
335888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        return (TestRecyclerView) mRecyclerView;
336888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    }
337888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
338888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    public void testRemoveScrapInvalidate() throws Throwable {
339888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        setupBasic(10);
340888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        TestRecyclerView testRecyclerView = getTestRecyclerView();
341888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.expectLayouts(1);
342888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.expectDraw(1);
343888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        runTestOnUiThread(new Runnable() {
344888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            @Override
345888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            public void run() {
346888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.mItems.clear();
347888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.notifyDataSetChanged();
348888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            }
349888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        });
350888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.waitForLayout(2);
351888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.waitForDraw(2);
352888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    }
353888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
354b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public void testDeleteVisibleAndInvisible() throws Throwable {
355b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(11, 3, 5); //layout items  3 4 5 6 7
356b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
3578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list
358b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(9, 8);
359b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9
360b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
361b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
362b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
3638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testFindPositionOffset() throws Throwable {
3648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
3658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        runTestOnUiThread(new Runnable() {
3668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
3678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void run() {
3688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // [0,1,2,3,4]
3698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // delete 1
3708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mTestAdapter.notifyItemRangeRemoved(1, 1);
3718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // delete 3
3728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mTestAdapter.notifyItemRangeRemoved(2, 1);
3738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mAdapterHelper.preProcess();
3748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // [0,2,4]
3758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0));
3768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2));
3778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4));
3788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
3798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
3808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        });
3818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
3828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
383b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setLayoutRange(int start, int count) {
384b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start;
385b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count;
386b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
387b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
388b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setExpectedItemCounts(int preLayout, int postLayout) {
389b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout);
390b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
391b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
392b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    public void testDeleteInvisible() throws Throwable {
393b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
3948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
3958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
396b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
397b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8);
3988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8
399b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
400b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
401b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
402e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    private CollectPositionResult findByPos(RecyclerView recyclerView,
403e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int position) {
404e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        View view = recycler.getViewForPosition(position, true);
405e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
406e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        if (vh.wasReturnedFromScrap()) {
407e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            vh.clearReturnedFromScrapFlag(); //keep data consistent.
408e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromScrap(vh);
409e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        } else {
410e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromAdapter(vh);
4118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
4128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
414e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView,
415e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) {
4168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        Map<Integer, CollectPositionResult> positionToAdapterMapping
4178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                = new HashMap<Integer, CollectPositionResult>();
4188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int position : positions) {
4198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (position < 0) {
4208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                continue;
4218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
422e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            positionToAdapterMapping.put(position,
423e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    findByPos(recyclerView, recycler, state, position));
4248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
4258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return positionToAdapterMapping;
4268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testAddDelete2() throws Throwable {
4298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
4308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 1 2 3 4
4318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 1 2 a b 3 4
4328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 1 b 3 4
4338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // pre: 0 1 2 3 4
4348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // pre w/ adap: 0 1 2 b 3 4
435d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
4368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void onRun(TestAdapter adapter) throws Throwable {
4378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
438b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
4398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
4408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(3, 3, 3)
4418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
4428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
443d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
4448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testAddDelete1() throws Throwable {
4458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
4468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 1 2 3 4
4478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 1 2 a b 3 4
4488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 2 a b 3 4
4498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 c d 2 a b 3 4
4508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // 0 c d 2 a 4
4518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // c d 2 a 4
4528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            // pre: 0 1 2 3 4
453b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            @Override
4548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void onRun(TestAdapter adapter) throws Throwable {
4558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
4568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
457d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
4588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
4598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
4608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
4618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapter(1), PositionConstraint.adapter(3)
4628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
4638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testAddSameIndexTwice() throws Throwable {
4668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
4678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
4688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void onRun(TestAdapter adapter) throws Throwable {
4698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
4708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        new int[]{11, 1});
4718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
4728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
4738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
4748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
4758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(8, 8, 13)
4768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
4778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
4798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void testDeleteTwice() throws Throwable {
4808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
4818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
4828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void onRun(TestAdapter adapter) throws Throwable {
4838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
4848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        new int[]{0, 1});// delete item ids 0,2,9,1
4858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
4868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
4878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
4888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
4898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
4908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
4918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
4928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
493b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
4948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
495e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            int firstLayoutItemCount, AdapterOps adapterChanges,
496e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
497e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
498e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                adapterChanges,  constraints);
499e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
500e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
501e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            int firstLayoutItemCount,TestAdapter adapter, AdapterOps adapterChanges,
502e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
503e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
504b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
5058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
5068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
5078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
5088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
5098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePreLayout(recycler, lm, state);
5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                //harmless
5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPreLayoutPos;
5158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
5168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
517e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
5188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
5198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPreLayoutPos != -1) {
5208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPreLayoutPos),
5218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                                lm.getLog());
5228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
5238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
5248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
5278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
5288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
5298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePostLayout(recycler, lm, state);
5308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
5318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
5328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
5338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPostLayoutPos;
5348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
5358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
536e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
5378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
5388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPostLayoutPos >= 0) {
5398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPostLayoutPos),
5408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                                lm.getLog());
5418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
5428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
5438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
5458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        adapterChanges.run(mTestAdapter);
546b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
547e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
5488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (PositionConstraint constraint : constraints) {
5498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.assertValidate();
5508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
551b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
552b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
553b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    class AnimationLayoutManager extends TestLayoutManager {
554b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
5558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        private int mTotalLayoutCount = 0;
5568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        private String log;
5578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
558b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
559b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        };
560b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
5618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
5628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
563b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        @Override
564c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase        public boolean supportsPredictiveItemAnimations() {
565b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            return true;
566b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
567b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
5688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public String getLog() {
5698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return log;
5708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
5718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
572668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
5738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            StringBuilder builder = new StringBuilder();
574668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
575668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            builder.append("\nViewHolders:\n");
5768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
5778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                builder.append(vh).append("\n");
5788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            builder.append("scrap:\n");
5808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
5818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                builder.append(vh).append("\n");
5828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
583668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar
584668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            if (state.isPreLayout() && !done) {
5858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                log = "\n" + builder.toString();
5868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
5878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                log += "\n" + builder.toString();
5888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
5898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return log;
5908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
5918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
592b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        @Override
593b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public void expectLayouts(int count) {
594b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            super.expectLayouts(count);
595b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mOnLayoutCallbacks.mLayoutCount = 0;
596b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
597b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
598b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
599b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mOnLayoutCallbacks = onLayoutCallbacks;
600b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
601b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
602b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        @Override
603b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public final void onLayoutChildren(RecyclerView.Recycler recycler,
604b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
605b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            try {
6068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mTotalLayoutCount++;
607668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                prepareLog(recycler, state, false);
608668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                if (state.isPreLayout()) {
609668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    validateOldPositions(recycler, state);
610668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                } else {
611668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    validateClearedOldPositions(recycler, state);
612668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                }
613b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
614668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                prepareLog(recycler, state, true);
615b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            } finally {
616b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                layoutLatch.countDown();
617d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
618b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
619b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
620668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        private void validateClearedOldPositions(RecyclerView.Recycler recycler,
621668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                RecyclerView.State state) {
622668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            if (getTestRecyclerView() == null) {
623668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                return;
624668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            }
625668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
626668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                assertEquals("there should NOT be an old position in post layout",
627668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        RecyclerView.NO_POSITION, viewHolder.mOldPosition);
628668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                assertEquals("there should NOT be a pre layout position in post layout",
629668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
630668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            }
631668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        }
632668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar
633668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        private void validateOldPositions(RecyclerView.Recycler recycler,
634668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                RecyclerView.State state) {
635668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            if (getTestRecyclerView() == null) {
636668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                return;
637668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            }
638668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
639668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
640668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    assertTrue("there should be an old position in pre-layout",
641668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                            viewHolder.mOldPosition != RecyclerView.NO_POSITION);
642668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                }
643668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            }
644668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        }
645668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar
6468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public int getTotalLayoutCount() {
6478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return mTotalLayoutCount;
6488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
6498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
650d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        @Override
651d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        public boolean canScrollVertically() {
652d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            return true;
653d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        }
654d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
655d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        @Override
656d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
657d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                RecyclerView.State state) {
658d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            mOnLayoutCallbacks.onScroll(dy, recycler, state);
659d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            return super.scrollVerticallyBy(dy, recycler, state);
660d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        }
661b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
662b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public void onPostDispatchLayout() {
663b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mOnLayoutCallbacks.postDispatchLayout();
664b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
665b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
666b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        @Override
667b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable {
668b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            super.waitForLayout(timeout, timeUnit);
669b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            checkForMainThreadException();
670b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
671d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
672d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
673b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    abstract class OnLayoutCallbacks {
674b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
675b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int mLayoutMin = Integer.MIN_VALUE;
676b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
677b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int mLayoutItemCount = Integer.MAX_VALUE;
678b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
679b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int expectedPreLayoutItemCount = -1;
680b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
681b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int expectedPostLayoutItemCount = -1;
682b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
683b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int mDeletedViewCount;
684b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
6858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int mLayoutCount = 0;
6868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
687b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void setExpectedItemCounts(int preLayout, int postLayout) {
688b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            expectedPreLayoutItemCount = preLayout;
689b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            expectedPostLayoutItemCount = postLayout;
690b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
691b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
692b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void reset() {
693b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mLayoutMin = Integer.MIN_VALUE;
694b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mLayoutItemCount = Integer.MAX_VALUE;
695b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            expectedPreLayoutItemCount = -1;
696b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            expectedPostLayoutItemCount = -1;
6978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mLayoutCount = 0;
698b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
699b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
700b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void beforePreLayout(RecyclerView.Recycler recycler,
701b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                AnimationLayoutManager lm, RecyclerView.State state) {
702b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mDeletedViewCount = 0;
703b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            for (int i = 0; i < lm.getChildCount(); i++) {
704b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                View v = lm.getChildAt(i);
705b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (lm.getLp(v).isItemRemoved()) {
706b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    mDeletedViewCount++;
707b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
708b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
709b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
710b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
711b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
712b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
713b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            if (DEBUG) {
714b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                Log.d(TAG, "item count " + state.getItemCount());
715b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
716b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            lm.detachAndScrapAttachedViews(recycler);
717b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
718b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            final int count = mLayoutItemCount
719b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
7208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            int skippedAdd = lm.layoutRange(recycler, start, start + count);
721b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            assertEquals("correct # of children should be laid out",
7228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    count - skippedAdd, lm.getChildCount());
7238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            lm.assertVisibleItemPositions();
724b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
725b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
726b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
727b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
728b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
7298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (state.isPreLayout()) {
730b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (expectedPreLayoutItemCount != -1) {
731b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    assertEquals("on pre layout, state should return abstracted adapter size",
732b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                            expectedPreLayoutItemCount, state.getItemCount());
733b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
734b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                beforePreLayout(recycler, lm, state);
7358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
736b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (expectedPostLayoutItemCount != -1) {
737b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    assertEquals("on post layout, state should return real adapter size",
738b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                            expectedPostLayoutItemCount, state.getItemCount());
739b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
740b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                beforePostLayout(recycler, lm, state);
741b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
742b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            doLayout(recycler, lm, state);
7438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (state.isPreLayout()) {
744b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                afterPreLayout(recycler, lm, state);
7458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
746b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                afterPostLayout(recycler, lm, state);
747b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
748b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            mLayoutCount++;
749b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
750b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
751b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
752b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
753b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
754b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
755b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
756b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
757b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
758b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
759b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
760b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                RecyclerView.State state) {
761b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
762b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
763b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void postDispatchLayout() {
764b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
765b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
766d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
767d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
768d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        }
769b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
770b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
771b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    class TestRecyclerView extends RecyclerView {
77211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
773888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        CountDownLatch drawLatch;
774b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
775b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public TestRecyclerView(Context context) {
776b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            super(context);
777b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
778b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
779b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public TestRecyclerView(Context context, AttributeSet attrs) {
780b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            super(context, attrs);
781b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
782b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
783b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
784b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            super(context, attrs, defStyle);
785b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
786b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
7878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        @Override
7888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void initAdapterManager() {
7898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            super.initAdapterManager();
7908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
7918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                @Override
7928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                public void run() {
7938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    validatePostUpdateOp();
7948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
7958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            };
7968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
7978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
798888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        public void expectDraw(int count) {
799888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            drawLatch = new CountDownLatch(count);
800888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        }
801888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
802888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        public void waitForDraw(long timeout) throws Throwable {
803888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
804888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            assertEquals("all expected draws should happen at the expected time frame",
805888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                    0, drawLatch.getCount());
806888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        }
807888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
8088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        List<ViewHolder> collectViewHolders() {
8098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            List<ViewHolder> holders = new ArrayList<ViewHolder>();
8108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            final int childCount = getChildCount();
8118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (int i = 0; i < childCount; i++) {
8128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                ViewHolder holder = getChildViewHolderInt(getChildAt(i));
8138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (holder != null) {
8148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    holders.add(holder);
8158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
8168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return holders;
8188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
8198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        private void validateViewHolderPositions() {
8228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            final Set<Integer> existingOffsets = new HashSet<Integer>();
823668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            int childCount = getChildCount();
824668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            StringBuilder log = new StringBuilder();
8258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (int i = 0; i < childCount; i++) {
8268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
827668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                TestViewHolder tvh = (TestViewHolder) vh;
828668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                log.append(tvh.mBindedItem).append(vh)
829668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        .append(" hidden:")
830668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        .append(mChildHelper.mHiddenViews.contains(vh.itemView))
831668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        .append("\n");
832668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            }
833668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            for (int i = 0; i < childCount; i++) {
834668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
835668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                if (vh.isInvalid()) {
836668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    continue;
837668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                }
838668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                if (vh.getPosition() < 0) {
839668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    LayoutManager lm = getLayoutManager();
840668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                    for (int j = 0; j < lm.getChildCount(); j ++) {
841668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        assertNotSame("removed view holder should not be in LM's child list",
842668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                                vh.itemView, lm.getChildAt(j));
8438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
844668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
8458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (!existingOffsets.add(vh.getPosition())) {
846668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                        throw new IllegalStateException("view holder position conflict for "
847668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                                + "existing views " + vh + "\n" + log);
8488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
8498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
8508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
8528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        void validatePostUpdateOp() {
8548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            try {
8558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                validateViewHolderPositions();
8568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (super.mState.isPreLayout()) {
8578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
8588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
8598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
8608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } catch (Throwable t) {
8618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                postExceptionToInstrumentation(t);
8628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
8648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        private void validateAdapterPosition(AnimationLayoutManager lm) {
8688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (ViewHolder vh : collectViewHolders()) {
8698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
8708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    assertEquals("adapter position calculations should match view holder "
871668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                            + "pre layout:" + mState.isPreLayout()
872668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                            + " positions\n" + vh + "\n" + lm.getLog(),
8738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                            mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
8748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
8758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
8778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
8788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // ensures pre layout positions are continuous block. This is not necessarily a case
8798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // but valid in test RV
8808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        private void validatePreLayoutSequence(AnimationLayoutManager lm) {
8818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Set<Integer> preLayoutPositions = new HashSet<Integer>();
8828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (ViewHolder vh : collectViewHolders()) {
8838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertTrue("pre layout positions should be distinct " + lm.getLog(),
8848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        preLayoutPositions.add(vh.mPreLayoutPosition));
8858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            int minPos = Integer.MAX_VALUE;
8878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (Integer pos : preLayoutPositions) {
8888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (pos < minPos) {
8898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    minPos = pos;
8908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
8918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            for (int i = 1; i < preLayoutPositions.size(); i++) {
8938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertNotNull("next position should exist " + lm.getLog(),
8948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        preLayoutPositions.contains(minPos + i));
8958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
8968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
8978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
898888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        @Override
899888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        protected void dispatchDraw(Canvas canvas) {
900888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            super.dispatchDraw(canvas);
901888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            if (drawLatch != null) {
902888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                drawLatch.countDown();
903888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            }
904888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        }
905888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
906b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        @Override
907b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        void dispatchLayout() {
908b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            try {
909b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                super.dispatchLayout();
910b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (getLayoutManager() instanceof AnimationLayoutManager) {
911b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
912b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
913b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            } catch (Throwable t) {
914b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                postExceptionToInstrumentation(t);
915b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
916b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
917b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
918b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
9198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
9218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    abstract class AdapterOps {
9238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final public void run(TestAdapter adapter) throws Throwable {
9258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            onRun(adapter);
9268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        abstract void onRun(TestAdapter testAdapter) throws Throwable;
9298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
9308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    static class CollectPositionResult {
9328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // true if found in scrap
9348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public RecyclerView.ViewHolder scrapResult;
9358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public RecyclerView.ViewHolder adapterResult;
9378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
9398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            CollectPositionResult cpr = new CollectPositionResult();
9408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            cpr.scrapResult = viewHolder;
9418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return cpr;
9428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
9458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            CollectPositionResult cpr = new CollectPositionResult();
9468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            cpr.adapterResult = viewHolder;
9478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return cpr;
9488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
9508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    static class PositionConstraint {
9528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public static enum Type {
9548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            scrap,
9558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            adapter,
9568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            adapterScrap /*first pass adapter, second pass scrap*/
9578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        Type mType;
9608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int mOldPos; // if VH
9628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int mPreLayoutPos;
9648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int mPostLayoutPos;
9668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int mValidateCount = 0;
9688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
9708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
9718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mType = Type.scrap;
9728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mOldPos = oldPos;
9738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPreLayoutPos = preLayoutPos;
9748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPostLayoutPos = postLayoutPos;
9758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return constraint;
9768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
9798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
9808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mType = Type.adapterScrap;
9818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mOldPos = RecyclerView.NO_POSITION;
9828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPreLayoutPos = preLayoutPos;
9838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPostLayoutPos = position;// adapter pos does not change
9848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return constraint;
9858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public static PositionConstraint adapter(int position) {
9888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
9898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mType = Type.adapter;
9908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
9918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mOldPos = RecyclerView.NO_POSITION;
9928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.mPostLayoutPos = position;// adapter pos does not change
9938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return constraint;
9948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
9958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
9968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public void assertValidate() {
9978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            int expectedValidate = 0;
9988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (mPreLayoutPos >= 0) {
9998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                expectedValidate ++;
10008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
10018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (mPostLayoutPos >= 0) {
10028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                expectedValidate ++;
10038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
10048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            assertEquals("should run all validates", expectedValidate, mValidateCount);
10058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
10068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
10078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        @Override
10088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public String toString() {
10098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            return "Cons{" +
10108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    "t=" + mType.name() +
10118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ", old=" + mOldPos +
10128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ", pre=" + mPreLayoutPos +
10138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ", post=" + mPostLayoutPos +
10148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    '}';
10158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
10168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
10178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
10188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mValidateCount ++;
10198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            assertNotNull(this + ": result should not be null\n" + log, result);
10208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            RecyclerView.ViewHolder viewHolder;
10218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
10228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
10238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                viewHolder = result.scrapResult;
10248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else {
10258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertNotNull(this + ": result should come from adapter\n"  + log,
10268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        result.adapterResult);
10278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals(this + ": old position should be none when it came from adapter\n" + log,
10288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
10298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                viewHolder = result.adapterResult;
10308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
10318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (state.isPreLayout()) {
10328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
1033e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
10348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        viewHolder.mPreLayoutPosition);
10358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
10368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        viewHolder.getPosition());
10378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                if (mType == Type.scrap) {
10388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    assertEquals(this + ": old position should match\n" + log, mOldPos,
10398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                            result.scrapResult.getOldPosition());
1040b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
10418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
10428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    .isRemoved()) {
1043e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
1044e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        + viewHolder, mPostLayoutPos, viewHolder.getPosition());
1045b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
1046b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
1047b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1048d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
1049