1121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
3121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar *
4121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * you may not use this file except in compliance with the License.
6121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * You may obtain a copy of the License at
7121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar *
8121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar *
10121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * See the License for the specific language governing permissions and
14121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * limitations under the License.
15121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */
16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget;
17121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
18121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
1942e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport static org.junit.Assert.assertEquals;
2042e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport static org.junit.Assert.assertNotNull;
2142e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport static org.junit.Assert.assertNotSame;
2242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport static org.junit.Assert.assertTrue;
2342e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas
24121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport android.content.Context;
25121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport android.graphics.Canvas;
26121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport android.util.AttributeSet;
27121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport android.util.Log;
28121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport android.view.View;
29121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
30121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.ArrayList;
31121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.HashSet;
32121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.List;
33121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.Set;
34121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.concurrent.CountDownLatch;
35121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarimport java.util.concurrent.TimeUnit;
36121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
37121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/**
38121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Base class for animation related tests.
39121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */
40121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class BaseRecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
41121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
42959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    protected static final boolean DEBUG = false;
43121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
44121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    protected static final String TAG = "RecyclerViewAnimationsTest";
45121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
46121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    AnimationLayoutManager mLayoutManager;
47121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
48121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    TestAdapter mTestAdapter;
49121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
50121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    public BaseRecyclerViewAnimationsTest() {
51121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        super(DEBUG);
52121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
53121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
54121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    RecyclerView setupBasic(int itemCount) throws Throwable {
55121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return setupBasic(itemCount, 0, itemCount);
56121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
57121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
58121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
59121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            throws Throwable {
60121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
61121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
62121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
63121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
64121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            TestAdapter testAdapter)
65121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            throws Throwable {
66121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
67121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.setHasFixedSize(true);
68121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        if (testAdapter == null) {
69121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mTestAdapter = new TestAdapter(itemCount);
70121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        } else {
71121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mTestAdapter = testAdapter;
72121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
73121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.setAdapter(mTestAdapter);
74121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.setItemAnimator(createItemAnimator());
75121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager = new AnimationLayoutManager();
76121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.setLayoutManager(mLayoutManager);
77121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
78121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
79121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
80121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager.expectLayouts(1);
81121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.expectDraw(1);
82121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        setRecyclerView(recyclerView);
83121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager.waitForLayout(2);
84121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        recyclerView.waitForDraw(1);
85121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.reset();
86121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        getInstrumentation().waitForIdleSync();
87e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        checkForMainThreadException();
88121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
89121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        assertEquals("all expected children should be laid out", firstLayoutItemCount,
90121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                mLayoutManager.getChildCount());
91121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return recyclerView;
92121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
93121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
94121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    protected RecyclerView.ItemAnimator createItemAnimator() {
95121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return new DefaultItemAnimator();
96121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
97121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
98121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    public TestRecyclerView getTestRecyclerView() {
99121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        return (TestRecyclerView) mRecyclerView;
100121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
101121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
102121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    class AnimationLayoutManager extends TestLayoutManager {
103121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
104121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        protected int mTotalLayoutCount = 0;
105121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private String log;
106121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
107121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
108121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        };
109121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
110121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
111121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
112121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
113121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public boolean supportsPredictiveItemAnimations() {
114121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return true;
115121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
116121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
117121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public String getLog() {
118121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return log;
119121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
120121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
121121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
122121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            StringBuilder builder = new StringBuilder();
123121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
124121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            builder.append("\nViewHolders:\n");
125121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
126121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                builder.append(vh).append("\n");
127121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
128121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            builder.append("scrap:\n");
129121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
130121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                builder.append(vh).append("\n");
131121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
132121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
133121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (state.isPreLayout() && !done) {
134121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                log = "\n" + builder.toString();
135121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } else {
136121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                log += "\n" + builder.toString();
137121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
138121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return log;
139121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
140121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
141121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
142121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void expectLayouts(int count) {
143121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super.expectLayouts(count);
144121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mOnLayoutCallbacks.mLayoutCount = 0;
145121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
146121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
147121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
148121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mOnLayoutCallbacks = onLayoutCallbacks;
149121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
150121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
151121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
152121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public final void onLayoutChildren(RecyclerView.Recycler recycler,
153121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
154121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            try {
155121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                mTotalLayoutCount++;
156121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                prepareLog(recycler, state, false);
157121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (state.isPreLayout()) {
158121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    validateOldPositions(recycler, state);
159121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                } else {
160121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    validateClearedOldPositions(recycler, state);
161121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
162121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
163121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                prepareLog(recycler, state, true);
164121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } finally {
165121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                layoutLatch.countDown();
166121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
167121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
168121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
169121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void validateClearedOldPositions(RecyclerView.Recycler recycler,
170121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
171121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (getTestRecyclerView() == null) {
172121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                return;
173121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
174121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
175121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals("there should NOT be an old position in post layout",
176121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        RecyclerView.NO_POSITION, viewHolder.mOldPosition);
177121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals("there should NOT be a pre layout position in post layout",
178121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
179121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
180121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
181121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
182121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void validateOldPositions(RecyclerView.Recycler recycler,
183121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
184121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (getTestRecyclerView() == null) {
185121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                return;
186121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
187121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
188121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
189121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    assertTrue("there should be an old position in pre-layout",
190121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            viewHolder.mOldPosition != RecyclerView.NO_POSITION);
191121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
192121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
193121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
194121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
195121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public int getTotalLayoutCount() {
196121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return mTotalLayoutCount;
197121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
198121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
199121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
200121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public boolean canScrollVertically() {
201121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return true;
202121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
203121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
204121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
205121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
206121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
207121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mOnLayoutCallbacks.onScroll(dy, recycler, state);
208121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return super.scrollVerticallyBy(dy, recycler, state);
209121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
210121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
211121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void onPostDispatchLayout() {
212121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mOnLayoutCallbacks.postDispatchLayout();
213121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
214121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
215121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
216121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    abstract class OnLayoutCallbacks {
217121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
218121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mLayoutMin = Integer.MIN_VALUE;
219121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
220121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mLayoutItemCount = Integer.MAX_VALUE;
221121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
222121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int expectedPreLayoutItemCount = -1;
223121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
224121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int expectedPostLayoutItemCount = -1;
225121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
226121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mDeletedViewCount;
227121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
228121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mLayoutCount = 0;
229121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
230121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void setExpectedItemCounts(int preLayout, int postLayout) {
231121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            expectedPreLayoutItemCount = preLayout;
232121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            expectedPostLayoutItemCount = postLayout;
233121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
234121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
235121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void reset() {
236121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mLayoutMin = Integer.MIN_VALUE;
237121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mLayoutItemCount = Integer.MAX_VALUE;
238121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            expectedPreLayoutItemCount = -1;
239121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            expectedPostLayoutItemCount = -1;
240121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mLayoutCount = 0;
241121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
242121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
243121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void beforePreLayout(RecyclerView.Recycler recycler,
244121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                AnimationLayoutManager lm, RecyclerView.State state) {
245121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mDeletedViewCount = 0;
246121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 0; i < lm.getChildCount(); i++) {
247121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                View v = lm.getChildAt(i);
248121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (lm.getLp(v).isItemRemoved()) {
249121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    mDeletedViewCount++;
250121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
251121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
252121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
253121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
254121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
255121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
256121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (DEBUG) {
257121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                Log.d(TAG, "item count " + state.getItemCount());
258121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
259121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            lm.detachAndScrapAttachedViews(recycler);
260121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
261121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            final int count = mLayoutItemCount
262121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
263121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            lm.layoutRange(recycler, start, start + count);
264121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertEquals("correct # of children should be laid out",
265121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    count, lm.getChildCount());
266121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            lm.assertVisibleItemPositions();
267121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
268121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
269121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) {
270121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) {
271121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertPreLayoutPosition(vh);
272121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
273121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
274121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
275121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) {
276121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 0; i < lm.getChildCount(); i ++) {
277121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                final RecyclerView.ViewHolder vh = mRecyclerView
278121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        .getChildViewHolder(lm.getChildAt(i));
279121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertPreLayoutPosition(vh);
280121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
281121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
282121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
283121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) {
284121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertEquals("in post layout, there should not be a view holder w/ a pre "
285121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition);
286121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertEquals("in post layout, there should not be a view holder w/ an old "
287121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition);
288121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
289121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
290121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
291121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
292121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (state.isPreLayout()) {
293121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (expectedPreLayoutItemCount != -1) {
294121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    assertEquals("on pre layout, state should return abstracted adapter size",
295121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            expectedPreLayoutItemCount, state.getItemCount());
296121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
297121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                beforePreLayout(recycler, lm, state);
298121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } else {
299121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (expectedPostLayoutItemCount != -1) {
300121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    assertEquals("on post layout, state should return real adapter size",
301121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            expectedPostLayoutItemCount, state.getItemCount());
302121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
303121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                beforePostLayout(recycler, lm, state);
304121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
305121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (!state.isPreLayout()) {
306121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertNoPreLayoutPosition(recycler);
307121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
308121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            doLayout(recycler, lm, state);
309121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (state.isPreLayout()) {
310121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                afterPreLayout(recycler, lm, state);
311121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } else {
312121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                afterPostLayout(recycler, lm, state);
313121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertNoPreLayoutPosition(lm);
314121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
315121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mLayoutCount++;
316121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
317121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
318121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
319121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
320121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
321121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
322121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
323121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
324121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
325121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
326121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
327121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                RecyclerView.State state) {
328121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
329121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
330121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void postDispatchLayout() {
331121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
332121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
333121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
334121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
335121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
336121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
337121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
338121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    class TestRecyclerView extends RecyclerView {
339121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
340121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        CountDownLatch drawLatch;
341121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
342121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public TestRecyclerView(Context context) {
343121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super(context);
344121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
345121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
346121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public TestRecyclerView(Context context, AttributeSet attrs) {
347121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super(context, attrs);
348121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
349121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
350121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
351121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super(context, attrs, defStyle);
352121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
353121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
354121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
355121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void initAdapterManager() {
356121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super.initAdapterManager();
357121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
358121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                @Override
359121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                public void run() {
360121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    validatePostUpdateOp();
361121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
362121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            };
363121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
364121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
365121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
366121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        boolean isAccessibilityEnabled() {
367121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return true;
368121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
369121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
370121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void expectDraw(int count) {
371121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            drawLatch = new CountDownLatch(count);
372121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
373121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
374121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void waitForDraw(long timeout) throws Throwable {
375121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
376121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertEquals("all expected draws should happen at the expected time frame",
377121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    0, drawLatch.getCount());
378121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
379121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
380121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        List<ViewHolder> collectViewHolders() {
381121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            List<ViewHolder> holders = new ArrayList<ViewHolder>();
382121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            final int childCount = getChildCount();
383121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 0; i < childCount; i++) {
384121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                ViewHolder holder = getChildViewHolderInt(getChildAt(i));
385121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (holder != null) {
386121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    holders.add(holder);
387121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
388121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
389121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return holders;
390121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
391121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
392121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
393121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void validateViewHolderPositions() {
394121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            final Set<Integer> existingOffsets = new HashSet<Integer>();
395121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            int childCount = getChildCount();
396121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            StringBuilder log = new StringBuilder();
397121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 0; i < childCount; i++) {
398121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
399121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                TestViewHolder tvh = (TestViewHolder) vh;
400121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                log.append(tvh.mBoundItem).append(vh)
401121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        .append(" hidden:")
402121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        .append(mChildHelper.mHiddenViews.contains(vh.itemView))
403121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        .append("\n");
404121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
405121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 0; i < childCount; i++) {
406121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                ViewHolder vh = getChildViewHolderInt(getChildAt(i));
407121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (vh.isInvalid()) {
408121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    continue;
409121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
410121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (vh.getLayoutPosition() < 0) {
411121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    LayoutManager lm = getLayoutManager();
412121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    for (int j = 0; j < lm.getChildCount(); j ++) {
413121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        assertNotSame("removed view holder should not be in LM's child list",
414121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                vh.itemView, lm.getChildAt(j));
415121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    }
416121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
417121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    if (!existingOffsets.add(vh.getLayoutPosition())) {
418121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        throw new IllegalStateException("view holder position conflict for "
419121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                + "existing views " + vh + "\n" + log);
420121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    }
421121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
422121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
423121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
424121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
425121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void validatePostUpdateOp() {
426121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            try {
427121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                validateViewHolderPositions();
428121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (super.mState.isPreLayout()) {
429121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
430121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
431121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
432121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } catch (Throwable t) {
433121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                postExceptionToInstrumentation(t);
434121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
435121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
436121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
437121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
438121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
439121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void validateAdapterPosition(AnimationLayoutManager lm) {
440121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (ViewHolder vh : collectViewHolders()) {
441121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
442121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    assertEquals("adapter position calculations should match view holder "
443121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                    + "pre layout:" + mState.isPreLayout()
444121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                    + " positions\n" + vh + "\n" + lm.getLog(),
445121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
446121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
447121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
448121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
449121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
450121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        // ensures pre layout positions are continuous block. This is not necessarily a case
451121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        // but valid in test RV
452121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        private void validatePreLayoutSequence(AnimationLayoutManager lm) {
453121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            Set<Integer> preLayoutPositions = new HashSet<Integer>();
454121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (ViewHolder vh : collectViewHolders()) {
455121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertTrue("pre layout positions should be distinct " + lm.getLog(),
456121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        preLayoutPositions.add(vh.mPreLayoutPosition));
457121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
458121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            int minPos = Integer.MAX_VALUE;
459121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (Integer pos : preLayoutPositions) {
460121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (pos < minPos) {
461121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    minPos = pos;
462121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
463121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
464121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            for (int i = 1; i < preLayoutPositions.size(); i++) {
465121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertNotNull("next position should exist " + lm.getLog(),
466121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        preLayoutPositions.contains(minPos + i));
467121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
468121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
469121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
470121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
471121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        protected void dispatchDraw(Canvas canvas) {
472121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            super.dispatchDraw(canvas);
473121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (drawLatch != null) {
474121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                drawLatch.countDown();
475121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
476121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
477121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
478121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
479121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        void dispatchLayout() {
480121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            try {
481121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                super.dispatchLayout();
482121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (getLayoutManager() instanceof AnimationLayoutManager) {
483121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
484121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
485121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } catch (Throwable t) {
486121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                postExceptionToInstrumentation(t);
487121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
488121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
489121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
490121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
491121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
492121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
493121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
494121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    abstract class AdapterOps {
495121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
496121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        final public void run(TestAdapter adapter) throws Throwable {
497121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            onRun(adapter);
498121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
499121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
500121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        abstract void onRun(TestAdapter testAdapter) throws Throwable;
501121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
502121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
503121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    static class CollectPositionResult {
504121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
505121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        // true if found in scrap
506121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public RecyclerView.ViewHolder scrapResult;
507121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
508121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public RecyclerView.ViewHolder adapterResult;
509121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
510121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
511121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            CollectPositionResult cpr = new CollectPositionResult();
512121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            cpr.scrapResult = viewHolder;
513121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return cpr;
514121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
515121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
516121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
517121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            CollectPositionResult cpr = new CollectPositionResult();
518121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            cpr.adapterResult = viewHolder;
519121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return cpr;
520121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
521121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
522121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
523121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public String toString() {
524121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return "CollectPositionResult{" +
525121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    "scrapResult=" + scrapResult +
526121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    ", adapterResult=" + adapterResult +
527121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    '}';
528121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
529121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
530121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
531121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    static class PositionConstraint {
532121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
533121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public static enum Type {
534121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            scrap,
535121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            adapter,
536121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            adapterScrap /*first pass adapter, second pass scrap*/
537121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
538121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
539121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        Type mType;
540121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
541121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mOldPos; // if VH
542121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
543121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mPreLayoutPos;
544121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
545121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mPostLayoutPos;
546121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
547121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        int mValidateCount = 0;
548121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
549121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
550121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
551121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mType = Type.scrap;
552121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mOldPos = oldPos;
553121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPreLayoutPos = preLayoutPos;
554121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPostLayoutPos = postLayoutPos;
555121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return constraint;
556121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
557121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
558121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
559121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
560121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mType = Type.adapterScrap;
561121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mOldPos = RecyclerView.NO_POSITION;
562121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPreLayoutPos = preLayoutPos;
563121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPostLayoutPos = position;// adapter pos does not change
564121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return constraint;
565121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
566121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
567121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public static PositionConstraint adapter(int position) {
568121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            PositionConstraint constraint = new PositionConstraint();
569121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mType = Type.adapter;
570121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
571121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mOldPos = RecyclerView.NO_POSITION;
572121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            constraint.mPostLayoutPos = position;// adapter pos does not change
573121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return constraint;
574121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
575121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
576121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void assertValidate() {
577121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            int expectedValidate = 0;
578121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (mPreLayoutPos >= 0) {
579121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                expectedValidate ++;
580121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
581121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (mPostLayoutPos >= 0) {
582121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                expectedValidate ++;
583121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
584121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertEquals("should run all validates", expectedValidate, mValidateCount);
585121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
586121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
587121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        @Override
588121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public String toString() {
589121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            return "Cons{" +
590121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    "t=" + mType.name() +
591121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    ", old=" + mOldPos +
592121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    ", pre=" + mPreLayoutPos +
593121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    ", post=" + mPostLayoutPos +
594121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    '}';
595121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
596121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
597121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
598121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mValidateCount ++;
599121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            assertNotNull(this + ": result should not be null\n" + log, result);
600121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            RecyclerView.ViewHolder viewHolder;
601121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
602121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
603121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                viewHolder = result.scrapResult;
604121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } else {
605121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertNotNull(this + ": result should come from adapter\n"  + log,
606121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        result.adapterResult);
607121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals(this + ": old position should be none when it came from adapter\n" + log,
608121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
609121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                viewHolder = result.adapterResult;
610121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
611121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            if (state.isPreLayout()) {
612121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
613121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
614121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                viewHolder.mPreLayoutPosition);
615121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
616121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        viewHolder.getLayoutPosition());
617121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                if (mType == Type.scrap) {
618121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    assertEquals(this + ": old position should match\n" + log, mOldPos,
619121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            result.scrapResult.getOldPosition());
620121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
621121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
622121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    .isRemoved()) {
623121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
624121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition());
625121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            }
626121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        }
627121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
6289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    static class LoggingInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
6309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final RecyclerView.ViewHolder viewHolder;
6319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        @RecyclerView.ItemAnimator.AdapterChanges
6329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final int changeFlags;
6339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final List<Object> payloads;
6349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        LoggingInfo(RecyclerView.ViewHolder viewHolder, int changeFlags, List<Object> payloads) {
6369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            this.viewHolder = viewHolder;
6379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            this.changeFlags = changeFlags;
6389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            if (payloads != null) {
6399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                this.payloads = new ArrayList<>();
6409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                this.payloads.addAll(payloads);
6419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            } else {
6429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                this.payloads = null;
6439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
6449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            setFrom(viewHolder);
6459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
6464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        @Override
6484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public String toString() {
6494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return "LoggingInfo{" +
6504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    "changeFlags=" + changeFlags +
6514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    ", payloads=" + payloads +
6524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    '}';
6534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
6549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
6559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
656e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    static class AnimateChange extends AnimateLogBase {
6579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final RecyclerView.ViewHolder newHolder;
6599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        public AnimateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
6619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingInfo pre, LoggingInfo post) {
6629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            super(oldHolder, pre, post);
6639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            this.newHolder = newHolder;
6649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
6659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
6669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
667e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    static class AnimatePersistence extends AnimateLogBase {
6689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        public AnimatePersistence(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
6709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingInfo post) {
6719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            super(viewHolder, pre, post);
6729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
6739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
6749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
675e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar    static class AnimateAppearance extends AnimateLogBase {
6769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        public AnimateAppearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
6779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingInfo post) {
678e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            super(viewHolder, pre, post);
6799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
6809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
6819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    static class AnimateDisappearance extends AnimateLogBase {
683e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        public AnimateDisappearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
684e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                LoggingInfo post) {
685e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            super(viewHolder, pre, post);
6869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
6879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
6889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    static class AnimateLogBase {
6899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
6904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public final RecyclerView.ViewHolder viewHolder;
6914143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public final LoggingInfo preInfo;
6924143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public final LoggingInfo postInfo;
6939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
694e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        public AnimateLogBase(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
695e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                LoggingInfo postInfo) {
6969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            this.viewHolder = viewHolder;
6979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            this.preInfo = pre;
698e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            this.postInfo = postInfo;
699e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
700e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
7014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public String log() {
7024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return getClass().getSimpleName() + "[" +  log(preInfo) + " - " + log(postInfo) + "]";
7034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
7054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        public String log(LoggingInfo info) {
7064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return info == null ? "null" : info.toString();
7074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
709e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        @Override
710e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        public boolean equals(Object o) {
711e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if (this == o) {
712e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                return true;
713e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
714e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if (o == null || getClass() != o.getClass()) {
715e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                return false;
716e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
717e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
718e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            AnimateLogBase that = (AnimateLogBase) o;
719e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
720e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if (viewHolder != null ? !viewHolder.equals(that.viewHolder)
721e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                    : that.viewHolder != null) {
722e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                return false;
723e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
724e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            if (preInfo != null ? !preInfo.equals(that.preInfo) : that.preInfo != null) {
725e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                return false;
726e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            }
727e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return !(postInfo != null ? !postInfo.equals(that.postInfo) : that.postInfo != null);
728e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
729e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        }
730e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar
731e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        @Override
732e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        public int hashCode() {
733e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            int result = viewHolder != null ? viewHolder.hashCode() : 0;
734e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            result = 31 * result + (preInfo != null ? preInfo.hashCode() : 0);
735e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            result = 31 * result + (postInfo != null ? postInfo.hashCode() : 0);
736e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            return result;
7379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        }
7389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
739121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar}
740