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
1913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyarimport org.hamcrest.CoreMatchers;
2013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyarimport org.hamcrest.MatcherAssert;
210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Test;
220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runner.RunWith;
230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
245a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyarimport android.graphics.Rect;
254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.annotation.NonNull;
260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
27f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyarimport android.support.v4.view.ViewCompat;
28f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest;
29b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log;
30b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View;
31504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup;
32b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
3311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList;
348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap;
3511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet;
3611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List;
3711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map;
3811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set;
39b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean;
40d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger;
410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*;
42d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
43121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/**
44121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Tests for {@link SimpleItemAnimator} API.
45121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */
46f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest
470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class)
48121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
49b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    final List<TestViewHolder> recycledVHs = new ArrayList<>();
519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
53e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar    public void keepFocusAfterChangeAnimation() throws Throwable {
54e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        setupBasic(10, 0, 5, new TestAdapter(10) {
55e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            @Override
56e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
57e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar                    int position) {
58e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar                super.onBindViewHolder(holder, position);
59e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar                holder.itemView.setFocusableInTouchMode(true);
60e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            }
61e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        });
62e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        ((SimpleItemAnimator)(mRecyclerView.getItemAnimator())).setSupportsChangeAnimations(true);
63e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar
64e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(3);
65e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertNotNull("test sanity", oldVh);
66e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        runTestOnUiThread(new Runnable() {
67e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            @Override
68e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            public void run() {
69e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar                oldVh.itemView.requestFocus();
70e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar            }
71e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        });
72e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertTrue("test sanity", oldVh.itemView.hasFocus());
73e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        mLayoutManager.expectLayouts(2);
74e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        mTestAdapter.changeAndNotify(3, 1);
75e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        mLayoutManager.waitForLayout(2);
76e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar
77e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
78e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertNotNull("test sanity", newVh);
79e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertNotSame(oldVh, newVh);
80e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertFalse(oldVh.itemView.hasFocus());
81e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar        assertTrue(newVh.itemView.hasFocus());
82e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar    }
83e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar
84e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar    @Test
8513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    public void changeAndDisappearDontReUseViewHolder() throws Throwable {
8613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        changeAndDisappearTest(false, false);
8713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
8813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
8913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    @Test
9013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    public void changeAndDisappearReUseViewHolder() throws Throwable {
9113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        changeAndDisappearTest(true, false);
9213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
9313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
9413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    @Test
9513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    public void changeAndDisappearReUseWithScrapViewHolder() throws Throwable {
9613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        changeAndDisappearTest(true, true);
9713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
9813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
9913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    public void changeAndDisappearTest(final boolean reUse, final boolean useScrap)
10013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            throws Throwable {
10113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        final List<RecyclerView.ViewHolder> mRecycled = new ArrayList<>();
10213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        final TestAdapter adapter = new TestAdapter(1) {
10313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            @Override
10413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            public void onViewRecycled(TestViewHolder holder) {
10513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                super.onViewRecycled(holder);
10613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                mRecycled.add(holder);
10713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            }
10813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        };
10913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        setupBasic(1, 0, 1, adapter);
11013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0));
11113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        LoggingItemAnimator animator = new LoggingItemAnimator() {
11213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            @Override
11313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
11413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                                                     @NonNull List<Object> payloads) {
11513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                return reUse;
11613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            }
11713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        };
11813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        mRecyclerView.setItemAnimator(animator);
11913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        mLayoutManager.expectLayouts(2);
12013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        final RecyclerView.ViewHolder[] updatedVH = new RecyclerView.ViewHolder[1];
12113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        runTestOnUiThread(new Runnable() {
12213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            @Override
12313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            public void run() {
12413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                adapter.notifyItemChanged(0);
12513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
12613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                    @Override
12713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                    void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
12813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                                  RecyclerView.State state) {
12913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                        if (state.isPreLayout()) {
13013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            super.doLayout(recycler, lm, state);
13113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                        } else {
13213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            lm.detachAndScrapAttachedViews(recycler);
13313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            final View view;
13413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            if (reUse && useScrap) {
13513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                                view = recycler.getScrapViewAt(0);
13613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            } else {
13713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                                view = recycler.getViewForPosition(0);
13813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            }
13913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            updatedVH[0] = RecyclerView.getChildViewHolderInt(view);
14013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                            lm.addDisappearingView(view);
14113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                        }
14213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                    }
14313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                };
14413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            }
14513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        });
14613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        mLayoutManager.waitForLayout(2);
14713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
14813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateDisappearanceList),
149dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar                CoreMatchers.is(reUse));
15013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateChangeList),
151dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar                CoreMatchers.is(!reUse));
15213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        MatcherAssert.assertThat(animator.contains(updatedVH[0], animator.mAnimateChangeList),
153dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar                CoreMatchers.is(!reUse));
15413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        MatcherAssert.assertThat(animator.contains(updatedVH[0],
155dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar                animator.mAnimateDisappearanceList), CoreMatchers.is(reUse));
15613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        waitForAnimations(10);
15713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        MatcherAssert.assertThat(mRecyclerView.getChildCount(), CoreMatchers.is(0));
15813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        if (useScrap || !reUse) {
15913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            MatcherAssert.assertThat(mRecycled.contains(vh), CoreMatchers.is(true));
16013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        } else {
16113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(vh),
16213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                    CoreMatchers.is(true));
16313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        }
16413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
16513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        if (!reUse) {
16613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            MatcherAssert.assertThat(mRecycled.contains(updatedVH[0]), CoreMatchers.is(false));
16713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(updatedVH[0]),
16813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar                    CoreMatchers.is(true));
16913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar        }
17013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    }
17113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar
17213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar    @Test
1730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detectStableIdError() throws Throwable {
17466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        setIgnoreMainThreadException(true);
175b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        final AtomicBoolean useBadIds = new AtomicBoolean(false);
176b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        TestAdapter adapter = new TestAdapter(10) {
177b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            @Override
178b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            public long getItemId(int position) {
179b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                if (useBadIds.get() && position == 5) {
180b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                    return super.getItemId(position) - 1;
181b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                }
182b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                return super.getItemId(position);
183b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            }
184b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
185b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            @Override
186b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
187b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                // ignore validation
188b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            }
189b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        };
190b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        adapter.setHasStableIds(true);
191b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        setupBasic(10, 0, 10, adapter);
192b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        mLayoutManager.expectLayouts(2);
193b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        useBadIds.set(true);
194b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        adapter.changeAndNotify(4, 2);
195b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        mLayoutManager.waitForLayout(2);
19666826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        assertTrue(getMainThreadException() instanceof IllegalStateException);
19766826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        assertTrue(getMainThreadException().getMessage()
198b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar                .contains("Two different ViewHolders have the same stable ID."));
199b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        // TODO don't use this after moving this class to Junit 4
200b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        try {
201b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar            removeRecyclerView();
202b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar        } catch (Throwable t){}
203b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar    }
204b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
205b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar
2060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
2070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontLayoutReusedViewWithoutPredictive() throws Throwable {
2089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
2099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
2109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
2119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    final TestViewHolder target) throws Throwable {
2129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
2139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
2149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
2159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
2169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
2189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
2199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        fail("pre layout is not expected");
2209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePostLayout(RecyclerView.Recycler recycler,
2249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
2259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
2269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 7;
2279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        View targetView = recycler
2289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                .getViewForPosition(target.getAdapterPosition());
2299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertSame(targetView, target.itemView);
2309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePostLayout(recycler, layoutManager, state);
2319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPostLayout(RecyclerView.Recycler recycler,
2359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
2369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
2379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPostLayout(recycler, layoutManager, state);
2389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertNull("test sanity. this view should not be re-laid out in post "
2399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + "layout", target.itemView.getParent());
2409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
2429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
2439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.requestSimpleAnimationsInNextLayout();
2449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
2459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                checkForMainThreadException();
2479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
2509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This is a LayoutManager problem if it asked for the view but didn't properly
2519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // lay it out. It will move to disappearance
2529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
2539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
2549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
2559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
2569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
2579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
2589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
2600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontLayoutReusedViewWithPredictive() throws Throwable {
2619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
2629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
2639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
2649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    final TestViewHolder target) throws Throwable {
2659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
2669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
2679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
2689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
2699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
2719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
2729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 9;
2739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePreLayout(recycler, lm, state);
2749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePostLayout(RecyclerView.Recycler recycler,
2789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
2799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
2809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 7;
2819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePostLayout(recycler, layoutManager, state);
2829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
2849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
2859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPostLayout(RecyclerView.Recycler recycler,
2869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
2879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
2889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPostLayout(recycler, layoutManager, state);
2899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        assertNull("test sanity. this view should not be re-laid out in post "
2909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + "layout", target.itemView.getParent());
2919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
2929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
2939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
2949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(1, 1);
2959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
2969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                checkForMainThreadException();
2979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
2989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
2999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This is a LayoutManager problem if it asked for the view but didn't properly
3019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // lay it out. It will move to disappearance.
3029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
3059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithoutPredictive() throws Throwable {
3119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
3199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.requestSimpleAnimationsInNextLayout();
3209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
3219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
3229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
3239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
3259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
3269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
3299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithoutAnimations() throws Throwable {
3359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
3439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
3449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithPredictive() throws Throwable {
3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
3639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
3679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(2, 1);
3689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
3699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
3709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This LM does not layout the additional item so it does predictive wrong.
3719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // We should still handle it and animate persistence for this item
3729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
3739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
3749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
3759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
3769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mMoveVHs.contains(target));
3779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
3789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
3799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
3809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
3819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
3820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
3830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void reuseHiddenViewWithProperPredictive() throws Throwable {
3849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
3859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
3869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
3879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
3889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
3899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
3909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
3919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
3929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
3939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
3949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void beforePreLayout(RecyclerView.Recycler recycler,
3959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager lm, RecyclerView.State state) {
3969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 9;
3979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.beforePreLayout(recycler, lm, state);
3989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
3999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
4019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void afterPreLayout(RecyclerView.Recycler recycler,
4029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            AnimationLayoutManager layoutManager,
4039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
4049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutItemCount = 8;
4059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        super.afterPreLayout(recycler, layoutManager, state);
4069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
4079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                };
4089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(2);
4109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.deleteAndNotify(2, 1);
4119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
4129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
4139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // This LM implements predictive animations properly by requesting target view
4149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // in pre-layout.
4159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
4169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
4179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
4189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
4199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mMoveVHs.contains(target));
4209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
4219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
4229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
4239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
4249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
4260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontReuseHiddenViewOnInvalidate() throws Throwable {
4279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
4289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
4299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
4309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
4319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
4329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
4339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
4349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
4359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
4369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.dispatchDataSetChanged();
4379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
4389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
4399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(mRecyclerView.getItemAnimator().isRunning());
4409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
4419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
4429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
4439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
4449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
4459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
4469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
4479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
4489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
4500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dontReuseOnTypeChange() throws Throwable {
4519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        reuseHiddenViewTest(new ReuseTestCallback() {
4529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
4539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void postSetup(List<TestViewHolder> recycledList,
4549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    TestViewHolder target) throws Throwable {
4559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                // it should move to change scrap and then show up from there
4569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
4579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        .getItemAnimator();
4589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                itemAnimator.reset();
4599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.expectLayouts(1);
4609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                target.mBoundItem.mType += 2;
4619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
4629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
4639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                requestLayoutOnUIThread(mRecyclerView);
4649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                mLayoutManager.waitForLayout(2);
4659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(itemAnimator.mChangeOldVHs.contains(target));
4679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
4689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
4699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
4709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
4719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertFalse(recycledVHs.contains(target));
4729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                waitForAnimations(5);
4739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                assertTrue(recycledVHs.contains(target));
4749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
4759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        });
4769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
4779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    interface ReuseTestCallback {
4799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
4819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
4829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    @Override
4849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    protected RecyclerView.ItemAnimator createItemAnimator() {
4859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        return new LoggingItemAnimator();
4869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
4879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
4889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
4899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        TestAdapter adapter = new TestAdapter(10) {
4909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            @Override
4919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            public void onViewRecycled(TestViewHolder holder) {
4929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                super.onViewRecycled(holder);
4939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                recycledVHs.add(holder);
4949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            }
4959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        };
4969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        setupBasic(10, 0, 10, adapter);
4979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.setItemViewCacheSize(0);
4989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
4999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setAddDuration(1000);
5009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setRemoveDuration(1000);
5019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setChangeDuration(1000);
5029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mRecyclerView.getItemAnimator().setMoveDuration(1000);
5039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
5049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.expectLayouts(2);
5059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        adapter.deleteAndNotify(2, 1);
5069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        mLayoutManager.waitForLayout(2);
5079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // test sanity, make sure target is hidden now
5089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
5099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        callback.postSetup(recycledVHs, target);
5109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
5119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
5129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
5139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
5149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar    }
5159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
5160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detachBeforeAnimations() throws Throwable {
5180ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        setupBasic(10, 0, 5);
5190ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        final RecyclerView rv = mRecyclerView;
5200ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        waitForAnimations(2);
5210ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        final DefaultItemAnimator animator = new DefaultItemAnimator() {
5220ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            @Override
5230ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            public void runPendingAnimations() {
5240ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar                super.runPendingAnimations();
5250ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar            }
5260ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        };
5270ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        rv.setItemAnimator(animator);
5280ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mLayoutManager.expectLayouts(2);
5290ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mTestAdapter.deleteAndNotify(3, 4);
5300ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        mLayoutManager.waitForLayout(2);
5310ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        removeRecyclerView();
5320ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertNull("test sanity check RV should be removed", rv.getParent());
5330ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size());
5340ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar        assertFalse("there should not be any animations running", animator.isRunning());
5350ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar    }
5360ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar
5370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
5380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void moveDeleted() throws Throwable {
5395a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        setupBasic(4, 0, 3);
5405a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        waitForAnimations(2);
5415a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        final View[] targetChild = new View[1];
5425a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        final LoggingItemAnimator animator = new LoggingItemAnimator();
5435a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        runTestOnUiThread(new Runnable() {
5445a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            @Override
5455a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            public void run() {
5465a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                mRecyclerView.setItemAnimator(animator);
5475a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                targetChild[0] = mRecyclerView.getChildAt(1);
5485a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            }
5495a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        });
5505a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
5515a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertNotNull("test sanity", targetChild);
5525a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.expectLayouts(1);
5535a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        runTestOnUiThread(new Runnable() {
5545a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            @Override
5555a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            public void run() {
5565a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
5575a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    @Override
5585a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
5599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            RecyclerView.State state) {
5605a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        if (view == targetChild[0]) {
5615a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                            outRect.set(10, 20, 30, 40);
5625a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        } else {
5635a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                            outRect.set(0, 0, 0, 0);
5645a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                        }
5655a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                    }
5665a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                });
5675a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar            }
5685a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        });
5695a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.waitForLayout(1);
5705a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
5715a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        // now delete that item.
5725a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.expectLayouts(2);
5735a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]);
5745a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        targetChild[0] = null;
5755a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mTestAdapter.deleteAndNotify(1, 1);
5765a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        mLayoutManager.waitForLayout(2);
5775a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertFalse("if deleted view moves, it should not be in move animations",
5785a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar                animator.mMoveVHs.contains(targetVH));
5795a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size());
5805a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH
5815a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar        ));
5825a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar    }
5835a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar
584344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    private void runTestImportantForAccessibilityWhileDeteling(
585344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            final int boundImportantForAccessibility,
586344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            final int expectedImportantForAccessibility) throws Throwable {
587344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Adapter binding the item to the initial accessibility option.
588344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // RecyclerView is expected to change it to 'expectedImportantForAccessibility'.
589344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        TestAdapter adapter = new TestAdapter(1) {
590344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
591344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void onBindViewHolder(TestViewHolder holder, int position) {
592344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                super.onBindViewHolder(holder, position);
593344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.setImportantForAccessibility(
594344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        holder.itemView, boundImportantForAccessibility);
595344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
596344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        };
597344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
598344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Set up with 1 item.
599344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        setupBasic(1, 0, 1, adapter);
600344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        waitForAnimations(2);
601344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        final View[] targetChild = new View[1];
602344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        final LoggingItemAnimator animator = new LoggingItemAnimator();
603344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        animator.setRemoveDuration(500);
604344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
605344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
606344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
607344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                mRecyclerView.setItemAnimator(animator);
608344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                targetChild[0] = mRecyclerView.getChildAt(0);
609344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
610344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
611344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
612344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
613344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
614344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
615344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        assertNotNull("test sanity", targetChild[0]);
616344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
617344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // now delete that item.
618344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.expectLayouts(2);
619344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mTestAdapter.deleteAndNotify(0, 1);
620344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
621344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.waitForLayout(2);
622344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
623344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
624344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
625344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
626344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view is still a child of mRecyclerView, and is invisible for accessibility.
627344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(targetChild[0].getParent() == mRecyclerView);
628344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
629344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
630344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
631344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
632344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
633344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
634344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        waitForAnimations(2);
635344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
636344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Delete animation is now complete.
637344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
638344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
639344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
640344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view is in recycled state, and back to the expected accessibility.
641344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(targetChild[0].getParent() == null);
642344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
643344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
644344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
645344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
646344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
647344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
648344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        // Add 1 element, which should use same view.
649344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.expectLayouts(2);
650344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mTestAdapter.addAndNotify(1);
651344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        mLayoutManager.waitForLayout(2);
652344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
653344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestOnUiThread(new Runnable() {
654344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            @Override
655344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            public void run() {
656344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                // The view should be reused, and have the expected accessibility.
657344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertTrue(
658344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0));
659344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                assertEquals(
660344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        expectedImportantForAccessibility,
661344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                        ViewCompat.getImportantForAccessibility(targetChild[0]));
662344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev            }
663344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        });
664344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
665344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
6660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingAuto() throws Throwable {
668344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
669344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO,
670344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
671344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
672344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
6730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingNo() throws Throwable {
675344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
676344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO,
677344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
678344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
679344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
6800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable {
682344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
683344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
684344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
685344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
686344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
6870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void importantForAccessibilityWhileDetelingYes() throws Throwable {
689344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev        runTestImportantForAccessibilityWhileDeteling(
690344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
691344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
692344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev    }
693344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev
6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
6950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void preLayoutPositionCleanup() throws Throwable {
69642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        setupBasic(4, 0, 4);
69742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.expectLayouts(2);
69842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
69942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            @Override
70042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler,
70142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
70242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutMin = 0;
70342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutItemCount = 3;
70442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            }
70542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
70642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            @Override
70742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            void beforePostLayout(RecyclerView.Recycler recycler,
70842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    AnimationLayoutManager layoutManager,
70942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                    RecyclerView.State state) {
71042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutMin = 0;
71142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar                mLayoutItemCount = 4;
71242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar            }
71342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        };
71442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mTestAdapter.addAndNotify(0, 1);
71542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar        mLayoutManager.waitForLayout(2);
71642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
71742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
71842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar    }
71942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar
7200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
7210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addRemoveSamePass() throws Throwable {
72293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final List<RecyclerView.ViewHolder> mRecycledViews
72393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
72493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        TestAdapter adapter = new TestAdapter(50) {
72593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
72693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public void onViewRecycled(TestViewHolder holder) {
72793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.onViewRecycled(holder);
72893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                mRecycledViews.add(holder);
72993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
73093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        };
73193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        adapter.setHasStableIds(true);
73293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        setupBasic(50, 3, 5, adapter);
73393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecyclerView.setItemViewCacheSize(0);
73493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> addVH
73593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
73693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> removeVH
73793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
73893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
73993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final ArrayList<RecyclerView.ViewHolder> moveVH
74093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
74193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
74293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        final View[] testView = new View[1];
74393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
74493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
74593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateAdd(RecyclerView.ViewHolder holder) {
74693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                addVH.add(holder);
74793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
74893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
74993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
75093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
75193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateRemove(RecyclerView.ViewHolder holder) {
75293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                removeVH.add(holder);
75393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
75493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
75593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
75693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
75793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY,
75893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    int toX, int toY) {
75993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                moveVH.add(holder);
76093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                return true;
76193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
76293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        });
76393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
76493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
76593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            void afterPreLayout(RecyclerView.Recycler recycler,
76693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    AnimationLayoutManager layoutManager,
76793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    RecyclerView.State state) {
76893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.afterPreLayout(recycler, layoutManager, state);
76993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0] = recycler.getViewForPosition(45);
77093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST),
77193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST));
77293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(),
77393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        10 + testView[0].getMeasuredHeight());
77493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                layoutManager.addView(testView[0], 4);
77593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
77693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
77793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            @Override
77893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            void afterPostLayout(RecyclerView.Recycler recycler,
77993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    AnimationLayoutManager layoutManager,
78093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                    RecyclerView.State state) {
78193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                super.afterPostLayout(recycler, layoutManager, state);
78293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(),
78393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                        50 + testView[0].getMeasuredHeight());
78493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar                layoutManager.addDisappearingView(testView[0], 4);
78593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            }
78693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        };
78793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3;
78893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5;
78993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mRecycledViews.clear();
79093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.expectLayouts(2);
79193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mTestAdapter.deleteAndNotify(3, 1);
79293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        mLayoutManager.waitForLayout(2);
79393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
79493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : addVH) {
79593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate add", testView[0], vh.itemView);
79693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
79793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : moveVH) {
79893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate move", testView[0], vh.itemView);
79993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
80093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : removeVH) {
80193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView);
80293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
80393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        boolean found = false;
80493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        for (RecyclerView.ViewHolder vh : mRecycledViews) {
80593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar            found |= vh.itemView == testView[0];
80693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        }
80793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar        assertTrue("added-removed view should be recycled", found);
80893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar    }
80993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar
8100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
8110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void tmpRemoveMe() throws Throwable {
812121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        changeAnimTest(false, false, true, false);
813121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar    }
814121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
8150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
8160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void changeAnimations() throws Throwable {
8177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final boolean[] booleans = {true, false};
8187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        for (boolean supportsChange : booleans) {
8197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            for (boolean changeType : booleans) {
8207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                for (boolean hasStableIds : booleans) {
8217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    for (boolean deleteSomeItems : booleans) {
8227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems);
8237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    }
8247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    removeRecyclerView();
8257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
8267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
8287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    }
829121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar
8307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
8319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
8327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final int changedIndex = 3;
8337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final int defaultType = 1;
8347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
8357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
8367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                ", change view type:" + changeType +
8377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                ", has stable ids:" + hasStableIds +
838121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                ", delete some items:" + deleteSomeItems;
8397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        TestAdapter testAdapter = new TestAdapter(10) {
8407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
8417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public int getItemViewType(int position) {
8427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                return position == changedIndex ? changedIndexNewType.get() : defaultType;
8437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
8457c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
8467c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public TestViewHolder onCreateViewHolder(ViewGroup parent,
8477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    int viewType) {
8487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
8497c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (DEBUG) {
8507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    Log.d(TAG, logPrefix + " onCreateVH" + vh.toString());
8517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
8527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                return vh;
8537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
8557c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
8567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            public void onBindViewHolder(TestViewHolder holder,
8577c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    int position) {
8587c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                super.onBindViewHolder(holder, position);
8597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (DEBUG) {
8607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString());
8617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
8627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        };
8647c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        testAdapter.setHasStableIds(hasStableIds);
8657c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
8669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
867121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                supportsChangeAnim);
8687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
8697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        final RecyclerView.ViewHolder toBeChangedVH =
870115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
8717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
8727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
8737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            void afterPreLayout(RecyclerView.Recycler recycler,
8747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    AnimationLayoutManager layoutManager,
8757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    RecyclerView.State state) {
876115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
877115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        changedIndex);
878121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                assertTrue(logPrefix + " changed view holder should have correct flag"
879121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                        , vh.isUpdated());
8807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
8827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            @Override
8837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            void afterPostLayout(RecyclerView.Recycler recycler,
8847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    AnimationLayoutManager layoutManager, RecyclerView.State state) {
885115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
886115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        changedIndex);
8877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                if (supportsChangeAnim) {
8887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    assertNotSame(logPrefix + "a new VH should be given if change is supported",
8897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                            toBeChangedVH, vh);
8907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                } else if (!changeType && hasStableIds) {
8917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    assertSame(logPrefix + "if change animations are not supported but we have "
8927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                            + "stable ids, same view holder should be returned", toBeChangedVH, vh);
8937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
8947c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                super.beforePostLayout(recycler, layoutManager, state);
8957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            }
8967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        };
8977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.expectLayouts(1);
8987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        if (changeType) {
8997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            changedIndexNewType.set(defaultType + 1);
9007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
9017c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        if (deleteSomeItems) {
9027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            runTestOnUiThread(new Runnable() {
9037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                @Override
9047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                public void run() {
9057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    try {
9067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        mTestAdapter.deleteAndNotify(changedIndex + 2, 1);
9077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        mTestAdapter.notifyItemChanged(3);
9087c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    } catch (Throwable throwable) {
9097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                        throwable.printStackTrace();
9107c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                    }
9117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
9127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen                }
9137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            });
9147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        } else {
915121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            mTestAdapter.changeAndNotify(3, 1);
9167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        }
9177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
9187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen        mLayoutManager.waitForLayout(2);
9197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen    }
9207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen
9214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    private void testChangeWithPayload(final boolean supportsChangeAnim,
9224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final boolean canReUse, Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
9239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            throws Throwable {
92421b345f101abc385496f42d250e580d21f1287b6Dake Gu        final List<Object> expectedPayloads = new ArrayList<Object>();
92521b345f101abc385496f42d250e580d21f1287b6Dake Gu        final int changedIndex = 3;
92621b345f101abc385496f42d250e580d21f1287b6Dake Gu        TestAdapter testAdapter = new TestAdapter(10) {
92721b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
92821b345f101abc385496f42d250e580d21f1287b6Dake Gu            public int getItemViewType(int position) {
92921b345f101abc385496f42d250e580d21f1287b6Dake Gu                return 1;
93021b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
93121b345f101abc385496f42d250e580d21f1287b6Dake Gu
93221b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
93321b345f101abc385496f42d250e580d21f1287b6Dake Gu            public TestViewHolder onCreateViewHolder(ViewGroup parent,
93421b345f101abc385496f42d250e580d21f1287b6Dake Gu                    int viewType) {
93521b345f101abc385496f42d250e580d21f1287b6Dake Gu                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
93621b345f101abc385496f42d250e580d21f1287b6Dake Gu                if (DEBUG) {
93721b345f101abc385496f42d250e580d21f1287b6Dake Gu                    Log.d(TAG, " onCreateVH" + vh.toString());
93821b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
93921b345f101abc385496f42d250e580d21f1287b6Dake Gu                return vh;
94021b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
94121b345f101abc385496f42d250e580d21f1287b6Dake Gu
94221b345f101abc385496f42d250e580d21f1287b6Dake Gu            @Override
94321b345f101abc385496f42d250e580d21f1287b6Dake Gu            public void onBindViewHolder(TestViewHolder holder,
94421b345f101abc385496f42d250e580d21f1287b6Dake Gu                    int position, List<Object> payloads) {
94521b345f101abc385496f42d250e580d21f1287b6Dake Gu                super.onBindViewHolder(holder, position);
94621b345f101abc385496f42d250e580d21f1287b6Dake Gu                if (DEBUG) {
94721b345f101abc385496f42d250e580d21f1287b6Dake Gu                    Log.d(TAG, " onBind to " + position + "" + holder.toString());
94821b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
949f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                assertEquals(expectedPayloads, payloads);
95021b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
95121b345f101abc385496f42d250e580d21f1287b6Dake Gu        };
95221b345f101abc385496f42d250e580d21f1287b6Dake Gu        testAdapter.setHasStableIds(false);
95321b345f101abc385496f42d250e580d21f1287b6Dake Gu        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
954f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
955f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            @Override
956f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
957f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                    @NonNull List<Object> payloads) {
958f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads);
959f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar            }
960f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        });
9619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
962121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                supportsChangeAnim);
96321b345f101abc385496f42d250e580d21f1287b6Dake Gu
96421b345f101abc385496f42d250e580d21f1287b6Dake Gu        int numTests = notifyPayloads.length;
9659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        for (int i = 0; i < numTests; i++) {
96621b345f101abc385496f42d250e580d21f1287b6Dake Gu            mLayoutManager.expectLayouts(1);
96721b345f101abc385496f42d250e580d21f1287b6Dake Gu            expectedPayloads.clear();
96821b345f101abc385496f42d250e580d21f1287b6Dake Gu            for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
96921b345f101abc385496f42d250e580d21f1287b6Dake Gu                expectedPayloads.add(expectedPayloadsInOnBind[i][j]);
97021b345f101abc385496f42d250e580d21f1287b6Dake Gu            }
97121b345f101abc385496f42d250e580d21f1287b6Dake Gu            final Object[] payloadsToSend = notifyPayloads[i];
97221b345f101abc385496f42d250e580d21f1287b6Dake Gu            runTestOnUiThread(new Runnable() {
97321b345f101abc385496f42d250e580d21f1287b6Dake Gu                @Override
97421b345f101abc385496f42d250e580d21f1287b6Dake Gu                public void run() {
97521b345f101abc385496f42d250e580d21f1287b6Dake Gu                    for (int j = 0; j < payloadsToSend.length; j++) {
97621b345f101abc385496f42d250e580d21f1287b6Dake Gu                        mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]);
97721b345f101abc385496f42d250e580d21f1287b6Dake Gu                    }
97821b345f101abc385496f42d250e580d21f1287b6Dake Gu                }
97921b345f101abc385496f42d250e580d21f1287b6Dake Gu            });
98021b345f101abc385496f42d250e580d21f1287b6Dake Gu            mLayoutManager.waitForLayout(2);
9819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            checkForMainThreadException();
98221b345f101abc385496f42d250e580d21f1287b6Dake Gu        }
98321b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
98421b345f101abc385496f42d250e580d21f1287b6Dake Gu
9850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
9860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void crossFadingChangeAnimationWithPayload() throws Throwable {
98721b345f101abc385496f42d250e580d21f1287b6Dake Gu        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
988f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(true, true,
989f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                new Object[][]{
990f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc"},
991f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", null, "cdf"},
992f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", null},
993f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{null, "abc"},
994f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", "cdf"}
995f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                },
996f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                new Object[][]{
997f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc"},
998f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
999f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
1000f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[0],
1001f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                        new Object[]{"abc", "cdf"}
1002f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar                });
1003f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar    }
1004f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar
10050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable {
1007f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
1008f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(true, false,
100921b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
10109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
10119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null, "cdf"},
10129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null},
10139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{null, "abc"},
10149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
101521b345f101abc385496f42d250e580d21f1287b6Dake Gu                },
101621b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
10179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0]
102221b345f101abc385496f42d250e580d21f1287b6Dake Gu                });
102321b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
102421b345f101abc385496f42d250e580d21f1287b6Dake Gu
10250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void noChangeAnimationWithPayload() throws Throwable {
102721b345f101abc385496f42d250e580d21f1287b6Dake Gu        // for Change Animation disabled, payload should match the payloads unless
102821b345f101abc385496f42d250e580d21f1287b6Dake Gu        // null payload is fired.
1029f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar        testChangeWithPayload(false, true,
103021b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
10319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
10329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null, "cdf"},
10339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", null},
10349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{null, "abc"},
10359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
103621b345f101abc385496f42d250e580d21f1287b6Dake Gu                },
103721b345f101abc385496f42d250e580d21f1287b6Dake Gu                new Object[][]{
10389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc"},
10399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[0],
10429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        new Object[]{"abc", "cdf"}
104321b345f101abc385496f42d250e580d21f1287b6Dake Gu                });
104421b345f101abc385496f42d250e580d21f1287b6Dake Gu    }
104521b345f101abc385496f42d250e580d21f1287b6Dake Gu
10460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleDuringAnimations() throws Throwable {
1048504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        final AtomicInteger childCount = new AtomicInteger(0);
1049504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        final TestAdapter adapter = new TestAdapter(1000) {
1050504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
1051504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public TestViewHolder onCreateViewHolder(ViewGroup parent,
1052504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                    int viewType) {
1053504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                childCount.incrementAndGet();
1054504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                return super.onCreateViewHolder(parent, viewType);
1055504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
1056504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        };
1057504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        setupBasic(1000, 10, 20, adapter);
1058504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10;
1059504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20;
1060504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
1061504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
1062504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
1063504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public void putRecycledView(RecyclerView.ViewHolder scrap) {
1064504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                super.putRecycledView(scrap);
1065504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                childCount.decrementAndGet();
1066504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
1067504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
1068504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            @Override
1069504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            public RecyclerView.ViewHolder getRecycledView(int viewType) {
1070504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
1071504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                if (recycledView != null) {
1072504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                    childCount.incrementAndGet();
1073504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                }
1074504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                return recycledView;
1075504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            }
1076504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        });
1077504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
1078504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        // now keep adding children to trigger more children being created etc.
10799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        for (int i = 0; i < 100; i++) {
1080504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            adapter.addAndNotify(15, 1);
1081504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            Thread.sleep(50);
1082504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        }
1083504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        getInstrumentation().waitForIdleSync();
1084504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        waitForAnimations(2);
1085504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        assertEquals("Children count should add up", childCount.get(),
1086504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
1087504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar    }
1088504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar
10890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
10900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChanged() throws Throwable {
1091b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        setupBasic(10, 3, 4);
1092b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        int layoutCount = mLayoutManager.mTotalLayoutCount;
1093b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(1);
1094b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        runTestOnUiThread(new Runnable() {
1095b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            @Override
1096b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            public void run() {
1097b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                try {
1098b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    mTestAdapter.deleteAndNotify(4, 1);
1099cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    mTestAdapter.dispatchDataSetChanged();
1100b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                } catch (Throwable throwable) {
1101b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                    throwable.printStackTrace();
1102b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                }
1103b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
1104b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar            }
1105b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        });
1106b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
1107b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        getInstrumentation().waitForIdleSync();
1108b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        assertEquals("on notify data set changed, predictive animations should not run",
1109b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar                layoutCount + 1, mLayoutManager.mTotalLayoutCount);
1110b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.expectLayouts(2);
1111b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mTestAdapter.addAndNotify(4, 2);
1112b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        // make sure animations recover
1113b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar        mLayoutManager.waitForLayout(2);
1114b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar    }
1115b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar
11160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void stableIdNotifyDataSetChanged() throws Throwable {
1118e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int itemCount = 20;
1119e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        List<Item> initialSet = new ArrayList<Item>();
1120e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestAdapter adapter = new TestAdapter(itemCount) {
1121e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
1122e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public long getItemId(int position) {
1123e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return mItems.get(position).mId;
1124e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
1125e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
1126e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        adapter.setHasStableIds(true);
1127e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        initialSet.addAll(adapter.mItems);
1128e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
11299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
11309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter testAdapter) throws Throwable {
11319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        Item item5 = adapter.mItems.get(5);
11329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        Item item6 = adapter.mItems.get(6);
11339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        item5.mAdapterIndex = 6;
11349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        item6.mAdapterIndex = 5;
11359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.mItems.remove(5);
11369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.mItems.add(6, item5);
11379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.dispatchDataSetChanged();
11389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        //hacky, we support only 1 layout pass
11399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        mLayoutManager.layoutLatch.countDown();
11409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
11419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
1142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
1143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                PositionConstraint.scrap(9, -1, 9));
1144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        // now mix items.
1145e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
1146e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
1147d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
11480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
11490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void getItemForDeletedView() throws Throwable {
11508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(false);
11518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        getItemForDeletedViewTest(true);
115211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
115311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
11548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void getItemForDeletedViewTest(boolean stableIds) throws Throwable {
115511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemViewTypeQueries = new HashSet<Integer>();
115611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final Set<Integer> itemIdQueries = new HashSet<Integer>();
115711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        TestAdapter adapter = new TestAdapter(10) {
115811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
115911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public int getItemViewType(int position) {
116011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.add(position);
116111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return super.getItemViewType(position);
116211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
116311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
116411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            @Override
116511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            public long getItemId(int position) {
116611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemIdQueries.add(position);
116711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                return mItems.get(position).mId;
116811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
116911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        };
117011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.setHasStableIds(stableIds);
117111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        setupBasic(10, 0, 10, adapter);
117211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        assertEquals("getItemViewType for all items should be called", 10,
117311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                itemViewTypeQueries.size());
117411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        if (adapter.hasStableIds()) {
117511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should be called when adapter has stable ids", 10,
117611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
117711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        } else {
117811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertEquals("getItemId should not be called when adapter does not have stable ids", 0,
117911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemIdQueries.size());
118011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
118111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemViewTypeQueries.clear();
118211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        itemIdQueries.clear();
118311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.expectLayouts(2);
118411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        // delete last two
118511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteStart = 8;
118611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        final int deleteCount = adapter.getItemCount() - deleteStart;
118711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        adapter.deleteAndNotify(deleteStart, deleteCount);
118811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        mLayoutManager.waitForLayout(2);
118911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = 0; i < deleteStart; i++) {
119011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertTrue("getItemViewType for existing item " + i + " should be called",
119111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
119211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
119311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                assertTrue("getItemId for existing item " + i
11949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                + " should be called when adapter has stable ids",
119511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
119611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
119711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
119811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        for (int i = deleteStart; i < deleteStart + deleteCount; i++) {
119911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called",
120011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                    itemViewTypeQueries.contains(i));
120111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            if (adapter.hasStableIds()) {
12028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called",
120311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar                        itemIdQueries.contains(i));
120411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar            }
120511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar        }
120611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar    }
120711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar
12080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteInvisibleMultiStep() throws Throwable {
12108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(1000, 1, 7);
12118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
12128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
12138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
12148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
12158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
12168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
12178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});
121890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            checkForMainThreadException();
12198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount -= 2;
12208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
12218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
12228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
12238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
12248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
12258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
12268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
12278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addManyMultiStep() throws Throwable {
12308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10, 1, 7);
12318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
12328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
12338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(1);
12348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // try to trigger race conditions
12358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        int targetItemCount = mTestAdapter.getItemCount();
12368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int i = 0; i < 100; i++) {
1237e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
12388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(0, 1);
1239e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
12408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            mTestAdapter.addAndNotify(7, 1);
12418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            targetItemCount += 2;
12428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1243e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar        checkForMainThreadException();
12448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        // wait until main thread runnables are consumed
12458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        while (targetItemCount != mTestAdapter.getItemCount()) {
12468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            Thread.sleep(100);
1247e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar            checkForMainThreadException();
12488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
12498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
12508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
12518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void basicDelete() throws Throwable {
12548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
12558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() {
12568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
12578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void postDispatchLayout() {
12588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                // verify this only in first layout
12598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                assertEquals("deleted views should still be children of RV",
12608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        mLayoutManager.getChildCount() + mDeletedViewCount
12618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        , mRecyclerView.getChildCount());
12628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
12638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
12658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void afterPreLayout(RecyclerView.Recycler recycler,
12668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    AnimationLayoutManager layoutManager,
12678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
12688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.afterPreLayout(recycler, layoutManager, state);
12698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutItemCount = 3;
12708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                mLayoutMin = 0;
12718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
12728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
12738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.mLayoutItemCount = 10;
12748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.setExpectedItemCounts(10, 3);
12758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(callbacks);
12768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.expectLayouts(2);
12788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(0, 7);
12798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.waitForLayout(2);
12808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        callbacks.reset();// when animations end another layout will happen
12818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
12828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
12840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
12850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringScrolling() throws Throwable {
1286d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        setupBasic(10);
1287d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
1288d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
1289d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1290d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
1291d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1292d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            void onLayoutChildren(RecyclerView.Recycler recycler,
1293d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
1294d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onLayoutItemCount.set(state.getItemCount());
1295d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onLayoutChildren(recycler, lm, state);
1296d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1297d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1298d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1299d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
1300d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                onScrollItemCount.set(state.getItemCount());
1301d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                super.onScroll(dx, recycler, state);
1302d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1303d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
1304d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        runTestOnUiThread(new Runnable() {
1305d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            @Override
1306d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            public void run() {
1307d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.mItems.remove(5);
1308d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mTestAdapter.notifyItemRangeRemoved(5, 1);
1309d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                mRecyclerView.scrollBy(0, 100);
1310d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertTrue("scrolling while there are pending adapter updates should "
1311d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
1312d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                assertEquals("scroll by should be called w/ updated adapter count",
1313d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar                        mTestAdapter.mItems.size(), onScrollItemCount.get());
1314d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
1315d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar            }
1316d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar        });
1317d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar    }
1318d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar
13190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChangedDuringScroll() throws Throwable {
132117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        setupBasic(10);
132217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
132317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
132417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
132517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
132617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
132717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            void onLayoutChildren(RecyclerView.Recycler recycler,
132817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
132917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                onLayoutItemCount.set(state.getItemCount());
133017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                super.onLayoutChildren(recycler, lm, state);
133117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
133217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
133317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
133417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
133517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                onScrollItemCount.set(state.getItemCount());
133617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                super.onScroll(dx, recycler, state);
133717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
133817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        });
133917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        runTestOnUiThread(new Runnable() {
134017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            @Override
134117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            public void run() {
134217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mTestAdapter.mItems.remove(5);
134317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mTestAdapter.notifyDataSetChanged();
134417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                mRecyclerView.scrollBy(0, 100);
134517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                assertTrue("scrolling while there are pending adapter updates should "
134617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
134717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                assertEquals("scroll by should be called w/ updated adapter count",
134817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar                        mTestAdapter.mItems.size(), onScrollItemCount.get());
134917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
135017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar            }
135117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar        });
135217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar    }
135317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar
13540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addInvisibleAndVisible() throws Throwable {
1356b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
1357b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
1358b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible
1360b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1361b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1362b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
13630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addInvisible() throws Throwable {
1365b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
1366b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
1367b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
13682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0
1369b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1370b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1371b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
13720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void basicAdd() throws Throwable {
1374b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10);
1375b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
1376b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(10, 13);
1377b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.addAndNotify(2, 3);
1378b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1379b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1380b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
13810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
13820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void appCancelAnimationInDetach() throws Throwable {
1383a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        final View[] addedView = new View[2];
1384a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        TestAdapter adapter = new TestAdapter(1) {
1385a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            @Override
1386a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            public void onViewDetachedFromWindow(TestViewHolder holder) {
1387a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView)
1388f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        && ViewCompat.hasTransientState(holder.itemView)) {
1389f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                    ViewCompat.animate(holder.itemView).cancel();
1390a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                }
1391a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                super.onViewDetachedFromWindow(holder);
1392a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            }
1393a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        };
1394a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // original 1 item
1395a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        setupBasic(1, 0, 1, adapter);
1396cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        mRecyclerView.getItemAnimator().setAddDuration(10000);
1397a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.expectLayouts(2);
1398a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // add 2 items
1399a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        setExpectedItemCounts(1, 3);
1400a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mTestAdapter.addAndNotify(0, 2);
140166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        mLayoutManager.waitForLayout(2);
1402629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar        checkForMainThreadException();
1403a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // wait till "add animation" starts
1404e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        int limit = 200;
1405a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        while (addedView[0] == null || addedView[1] == null) {
1406629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar            Thread.sleep(100);
1407a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            runTestOnUiThread(new Runnable() {
1408a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                @Override
1409a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                public void run() {
1410a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    if (mRecyclerView.getChildCount() == 3) {
1411a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        View view = mRecyclerView.getChildAt(0);
1412f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        if (ViewCompat.hasTransientState(view)) {
1413a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                            addedView[0] = view;
1414a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        }
1415a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        view = mRecyclerView.getChildAt(1);
1416f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar                        if (ViewCompat.hasTransientState(view)) {
1417a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                            addedView[1] = view;
1418a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                        }
1419a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    }
1420a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                }
1421a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            });
1422e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            assertTrue("add should start on time", --limit > 0);
1423a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        }
1424a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu
1425a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        // Layout from item2, exclude the current adding items
1426a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.expectLayouts(1);
1427a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
1428a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            @Override
1429a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            void beforePostLayout(RecyclerView.Recycler recycler,
1430a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    AnimationLayoutManager layoutManager,
1431a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                    RecyclerView.State state) {
1432a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                mLayoutMin = 2;
1433a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu                mLayoutItemCount = 1;
1434a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu            }
1435a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        };
1436a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        requestLayoutOnUIThread(mRecyclerView);
1437a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu        mLayoutManager.waitForLayout(2);
1438a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu    }
1439a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu
14400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeFrozen() throws Throwable {
1442ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setupBasic(10, 1, 7);
1443ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertTrue(mRecyclerView.getChildCount() == 7);
1444ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1445ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.expectLayouts(2);
1446ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
1447ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
1448ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
1449ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mTestAdapter.addAndNotify(0, 1);
1450ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1451ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2);
1452ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals(7, mRecyclerView.getChildCount());
1453ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
1454ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
1455ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        mLayoutManager.waitForLayout(2);
1456ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("RV should get updated after waken from frozen",
1457ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                8, mRecyclerView.getChildCount());
1458ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
1459ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
14600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void removeScrapInvalidate() throws Throwable {
1462888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        setupBasic(10);
1463888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        TestRecyclerView testRecyclerView = getTestRecyclerView();
1464888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.expectLayouts(1);
1465888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.expectDraw(1);
1466888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        runTestOnUiThread(new Runnable() {
1467888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            @Override
1468888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            public void run() {
1469888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.mItems.clear();
1470888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar                mTestAdapter.notifyDataSetChanged();
1471888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar            }
1472888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        });
1473888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        mLayoutManager.waitForLayout(2);
1474888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar        testRecyclerView.waitForDraw(2);
1475888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar    }
1476888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar
14770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteVisibleAndInvisible() throws Throwable {
1479b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(11, 3, 5); //layout items  3 4 5 6 7
1480b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
14818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list
1482b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setExpectedItemCounts(9, 8);
1483b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9
1484b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1485b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1486b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
14870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
14880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findPositionOffset() throws Throwable {
14898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        setupBasic(10);
149090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
149190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            @Override
149290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler,
149390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
149490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                super.beforePreLayout(recycler, lm, state);
149590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                // [0,2,4]
149690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0));
149790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2));
149890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4));
149990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            }
150090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        };
15018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        runTestOnUiThread(new Runnable() {
15028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
15038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            public void run() {
1504121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                try {
1505121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    // delete 1
1506121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    mTestAdapter.deleteAndNotify(1, 1);
1507121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    // delete 3
1508121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    mTestAdapter.deleteAndNotify(2, 1);
1509121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                } catch (Throwable throwable) {
1510121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    throwable.printStackTrace();
1511121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
15128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
15138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        });
151490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        mLayoutManager.waitForLayout(2);
15158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
15168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1517b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setLayoutRange(int start, int count) {
1518b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start;
1519b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count;
1520b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1521b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
1522b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private void setExpectedItemCounts(int preLayout, int postLayout) {
1523b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout);
1524b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1525b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
15260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
15270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteInvisible() throws Throwable {
1528b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        setupBasic(10, 1, 7);
15298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
15308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
1531b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(1);
1532b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8);
15338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8
1534b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1535b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1536b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
1537e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    private CollectPositionResult findByPos(RecyclerView recyclerView,
1538e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int position) {
1539e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        View view = recycler.getViewForPosition(position, true);
1540e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
1541e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        if (vh.wasReturnedFromScrap()) {
1542e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            vh.clearReturnedFromScrapFlag(); //keep data consistent.
1543e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromScrap(vh);
1544e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        } else {
1545e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            return CollectPositionResult.fromAdapter(vh);
15468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
15478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
15488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1549e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView,
1550e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) {
15518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        Map<Integer, CollectPositionResult> positionToAdapterMapping
15528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                = new HashMap<Integer, CollectPositionResult>();
15538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (int position : positions) {
15548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            if (position < 0) {
15558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                continue;
15568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
1557e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            positionToAdapterMapping.put(position,
1558e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    findByPos(recyclerView, recycler, state, position));
15598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
15608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        return positionToAdapterMapping;
15618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
15628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
15630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
15640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addDelete2() throws Throwable {
15658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
15669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 3 4
15679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 a b 3 4
15689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 b 3 4
15699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre: 0 1 2 3 4
15709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre w/ adap: 0 1 2 b 3 4
15719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
15729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
15739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
15749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
15759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
15768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(3, 3, 3)
15778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
15788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
1579d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
15800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
15810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addDelete1() throws Throwable {
15828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(5, 0, 5, new AdapterOps() {
15839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 3 4
15849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 1 2 a b 3 4
15859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 2 a b 3 4
15869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 c d 2 a b 3 4
15879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // 0 c d 2 a 4
15889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // c d 2 a 4
15899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    // pre: 0 1 2 3 4
15909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
15919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
15929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
15939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
15949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
15959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
15968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
15978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
15988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapter(1), PositionConstraint.adapter(3)
15998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
16008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
16018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
16020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
16030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addSameIndexTwice() throws Throwable {
16048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
16059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
16069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
16079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
16089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{11, 1});
16099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
16109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
16118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
16128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
16138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(8, 8, 13)
16148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
16158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
16168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
16170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
16180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void deleteTwice() throws Throwable {
16198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        positionStatesTest(12, 2, 7, new AdapterOps() {
16209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    @Override
16219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    void onRun(TestAdapter adapter) throws Throwable {
16229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                        adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
16239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                                new int[]{0, 1});// delete item ids 0,2,9,1
16249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    }
16259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
16268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
16278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
16288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
16298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        );
16308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    }
16318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
1632b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
16338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
1634e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            int firstLayoutItemCount, AdapterOps adapterChanges,
1635e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
1636e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
16379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                adapterChanges, constraints);
1638e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
16399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar
1640e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
16419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar            int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
1642e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            final PositionConstraint... constraints) throws Throwable {
1643e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
1644b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.expectLayouts(2);
16458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
16468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
16478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
16488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
16498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePreLayout(recycler, lm, state);
16508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                //harmless
16518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
16528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
16538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
16548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPreLayoutPos;
16558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
16568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
1657e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
1658121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
1659121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
16609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                    positionLog.append(entry.getKey()).append(":").append(entry.getValue())
16619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                            .append("\n");
1662121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
16638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
16648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPreLayoutPos != -1) {
16658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPreLayoutPos),
1666121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                lm.getLog() + positionLog);
16678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
16688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
16698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
16708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar
16718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            @Override
16728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
16738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    RecyclerView.State state) {
16748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                super.beforePostLayout(recycler, lm, state);
16758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                lm.detachAndScrapAttachedViews(recycler);
16768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                final int[] ids = new int[constraints.length];
16778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (int i = 0; i < constraints.length; i++) {
16788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    ids[i] = constraints[i].mPostLayoutPos;
16798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
16808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                Map<Integer, CollectPositionResult> positions
1681e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
1682121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
1683121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
1684121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    positionLog.append(entry.getKey()).append(":")
1685121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                            .append(entry.getValue()).append("\n");
1686121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                }
16878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                for (PositionConstraint constraint : constraints) {
16888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    if (constraint.mPostLayoutPos >= 0) {
16898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                        constraint.validate(state, positions.get(constraint.mPostLayoutPos),
1690121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                                lm.getLog() + positionLog);
16918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                    }
16928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                }
16938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            }
16948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        };
16958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        adapterChanges.run(mTestAdapter);
1696b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        mLayoutManager.waitForLayout(2);
1697e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
16988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        for (PositionConstraint constraint : constraints) {
16998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar            constraint.assertValidate();
17008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        }
1701b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    }
1702b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
17030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
17040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void addThenRecycleRemovedView() throws Throwable {
17056a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        setupBasic(10);
17066a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final AtomicInteger step = new AtomicInteger(0);
17079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar        final List<RecyclerView.ViewHolder> animateRemoveList
17089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar                = new ArrayList<RecyclerView.ViewHolder>();
17096a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        DefaultItemAnimator animator = new DefaultItemAnimator() {
17106a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
17116a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            public boolean animateRemove(RecyclerView.ViewHolder holder) {
17126a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                animateRemoveList.add(holder);
17136a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                return super.animateRemove(holder);
17146a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
17156a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        };
17166a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mRecyclerView.setItemAnimator(animator);
17176a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>();
17186a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
17196a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
17206a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            public void putRecycledView(RecyclerView.ViewHolder scrap) {
17216a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                pooledViews.add(scrap);
17226a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                super.putRecycledView(scrap);
17236a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
17246a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        });
17256a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1];
17266a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
17276a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            @Override
17286a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            void doLayout(RecyclerView.Recycler recycler,
17296a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                    AnimationLayoutManager lm, RecyclerView.State state) {
17306a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                switch (step.get()) {
17316a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                    case 1:
17326a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        super.doLayout(recycler, lm, state);
17336a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        if (state.isPreLayout()) {
17346a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            View view = mLayoutManager.getChildAt(1);
17356a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            RecyclerView.ViewHolder holder =
17366a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                                    mRecyclerView.getChildViewHolderInt(view);
17376a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            targetVh[0] = holder;
17386a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            assertTrue("test sanity", holder.isRemoved());
17396a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                            mLayoutManager.removeAndRecycleView(view, recycler);
17406a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        }
17416a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                        break;
17426a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                }
17436a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar            }
17446a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        };
17456a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        step.set(1);
17466a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        animateRemoveList.clear();
17476a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.expectLayouts(2);
17486a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mTestAdapter.deleteAndNotify(1, 1);
17496a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        mLayoutManager.waitForLayout(2);
17506a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0]));
17516a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar        assertTrue("since LM force recycled a view, animate disappearance should not be called",
17526a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar                animateRemoveList.isEmpty());
17536a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar    }
1754d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
1755