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 Haase
18d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepackage android.support.v7.widget;
19d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.hamcrest.CoreMatchers;
212e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyarimport org.hamcrest.MatcherAssert;
22be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.After;
23be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Before;
24be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Test;
25be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runner.RunWith;
263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.mockito.Mockito;
27be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
28bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.content.Context;
29bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.support.annotation.Nullable;
30be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport android.support.test.InstrumentationRegistry;
316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyarimport android.graphics.Color;
32ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.graphics.PointF;
33f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyarimport android.graphics.Rect;
34bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.os.SystemClock;
354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.InstrumentationRegistry;
364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
37ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.support.v4.view.ViewCompat;
380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.v7.util.TouchUtils;
39f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest;
40bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyarimport android.util.AttributeSet;
41ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.util.Log;
42670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyarimport android.view.Gravity;
43bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.MotionEvent;
445ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyarimport android.view.View;
45bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.ViewConfiguration;
460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.view.ViewGroup;
474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyarimport android.view.ViewTreeObserver;
48a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyarimport android.widget.LinearLayout;
490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.widget.TextView;
505ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
51e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.ArrayList;
52e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.HashMap;
530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport java.util.List;
54e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.Map;
55ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport java.util.concurrent.CountDownLatch;
56d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit;
57d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicBoolean;
58d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicInteger;
59824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
60e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION;
61bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
63bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
64e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.getChildViewHolderInt;
65d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar
66d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyarimport static org.hamcrest.CoreMatchers.sameInstance;
670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*;
683d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport static org.mockito.Mockito.*;
694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyarimport static org.hamcrest.CoreMatchers.is;
70be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
71be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar@RunWith(AndroidJUnit4.class)
72f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest
73d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest {
74cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_HORIZONTAL = 1;
75cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_VERTICAL = 1 << 1;
76cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_FLING = 1 << 2;
77d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
787bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar    private static final boolean DEBUG = false;
7922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
80ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    private static final String TAG = "RecyclerViewLayoutTest";
81ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
8222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    public RecyclerViewLayoutTest() {
8322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        super(DEBUG);
8422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    }
85bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
86be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
87a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    public void detachAttachGetReadyWithoutChanges() throws Throwable {
88a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        detachAttachGetReady(false, false, false);
89a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    }
90a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
91a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    @Test
92a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    public void detachAttachGetReadyRequireLayout() throws Throwable {
93a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        detachAttachGetReady(true, false, false);
94a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    }
95a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
96a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    @Test
97a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    public void detachAttachGetReadyRemoveAdapter() throws Throwable {
98a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        detachAttachGetReady(false, true, false);
99a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    }
100a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
101a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    @Test
102a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    public void detachAttachGetReadyRemoveLayoutManager() throws Throwable {
103a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        detachAttachGetReady(false, false, true);
104a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    }
105a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
106a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    private void detachAttachGetReady(final boolean requestLayoutOnDetach,
107a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            final boolean removeAdapter, final boolean removeLayoutManager) throws Throwable {
108a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        final LinearLayout ll1 = new LinearLayout(getActivity());
109a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        final LinearLayout ll2 = new LinearLayout(getActivity());
110a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        final LinearLayout ll3 = new LinearLayout(getActivity());
111a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
112a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
113a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        ll1.addView(ll2);
114a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        ll2.addView(ll3);
115a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        ll3.addView(rv);
116a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        TestLayoutManager layoutManager = new TestLayoutManager() {
117a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            @Override
118a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            public void onLayoutCompleted(RecyclerView.State state) {
119a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                super.onLayoutCompleted(state);
120a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                layoutLatch.countDown();
121a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            }
122a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
123a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            @Override
124a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
125a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                super.onDetachedFromWindow(view, recycler);
126a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                if (requestLayoutOnDetach) {
127a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                    view.requestLayout();
128a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                }
129a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            }
130a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        };
131a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        rv.setLayoutManager(layoutManager);
132a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        rv.setAdapter(new TestAdapter(10));
133a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        layoutManager.expectLayouts(1);
134a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        runTestOnUiThread(new Runnable() {
135a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            @Override
136a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            public void run() {
137a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                getActivity().getContainer().addView(ll1);
138a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            }
139a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        });
140a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        layoutManager.waitForLayout(2);
141a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        runTestOnUiThread(new Runnable() {
142a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            @Override
143a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            public void run() {
144a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                ll1.removeView(ll2);
145a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            }
146a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        });
147a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        getInstrumentation().waitForIdleSync();
148a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        if (removeLayoutManager) {
149a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            rv.setLayoutManager(null);
150a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            rv.setLayoutManager(layoutManager);
151a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        }
152a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        if (removeAdapter) {
153a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            rv.setAdapter(null);
154a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            rv.setAdapter(new TestAdapter(10));
155a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        }
156a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        final boolean requireLayout = requestLayoutOnDetach || removeAdapter || removeLayoutManager;
157a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        layoutManager.expectLayouts(1);
158a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        runTestOnUiThread(new Runnable() {
159a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            @Override
160a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            public void run() {
161a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                ll1.addView(ll2);
162a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                if (requireLayout) {
163a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                    assertTrue(rv.hasPendingAdapterUpdates());
164a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                    assertFalse(rv.mFirstLayoutComplete);
165a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                } else {
166a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                    assertFalse(rv.hasPendingAdapterUpdates());
167a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                    assertTrue(rv.mFirstLayoutComplete);
168a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                }
169a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            }
170a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        });
171a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        if (requireLayout) {
172a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            layoutManager.waitForLayout(2);
173a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        } else {
174a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar            layoutManager.assertNoLayout("nothing is invalid, layout should not happen", 2);
175a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        }
176a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    }
177a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar
178a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar    @Test
179d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar    public void focusSearchWithOtherFocusables() throws Throwable {
180d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        final LinearLayout container = new LinearLayout(getActivity());
181d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        container.setOrientation(LinearLayout.VERTICAL);
182d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
183d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        mRecyclerView = rv;
184d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        rv.setAdapter(new TestAdapter(10) {
185d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            @Override
186d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
187d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    int position) {
188d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                super.onBindViewHolder(holder, position);
189d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                holder.itemView.setFocusableInTouchMode(true);
190d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                holder.itemView.setLayoutParams(
191d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
192d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                        ViewGroup.LayoutParams.WRAP_CONTENT));
193d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            }
194d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        });
195d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
196d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            @Override
197d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
198d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                detachAndScrapAttachedViews(recycler);
199d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                layoutRange(recycler, 0, 1);
200d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                layoutLatch.countDown();
201d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            }
202d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar
203d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            @Nullable
204d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            @Override
205d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            public View onFocusSearchFailed(View focused, int direction,
206d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    RecyclerView.Recycler recycler,
207d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    RecyclerView.State state) {
208d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                assertEquals(View.FOCUS_FORWARD, direction);
209d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                assertEquals(1, getChildCount());
210d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                View child0 = getChildAt(0);
211d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                View view = recycler.getViewForPosition(1);
212d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                addView(view);
213d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                measureChild(view, 0, 0);
214d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                layoutDecorated(view, 0, child0.getBottom(), getDecoratedMeasuredWidth(view),
215d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                        child0.getBottom() + getDecoratedMeasuredHeight(view));
216d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                return view;
217d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            }
218d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        };
219d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        tlm.setAutoMeasureEnabled(true);
220d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        rv.setLayoutManager(tlm);
221d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        TextView viewAbove = new TextView(getActivity());
222d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        viewAbove.setText("view above");
223d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        viewAbove.setFocusableInTouchMode(true);
224d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        container.addView(viewAbove);
225d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        container.addView(rv);
226d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        TextView viewBelow = new TextView(getActivity());
227d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        viewBelow.setText("view below");
228d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        viewBelow.setFocusableInTouchMode(true);
229d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        container.addView(viewBelow);
230d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        tlm.expectLayouts(1);
231d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        runTestOnUiThread(new Runnable() {
232d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            @Override
233d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            public void run() {
234d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                getActivity().getContainer().addView(container);
235d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar            }
236d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        });
237d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar
238d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        tlm.waitForLayout(2);
239d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        requestFocus(viewAbove, true);
240d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        assertTrue(viewAbove.hasFocus());
241d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        View newFocused = focusSearch(viewAbove, View.FOCUS_FORWARD);
242d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        assertThat(newFocused, sameInstance(rv.getChildAt(0)));
243d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        newFocused = focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
244d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        assertThat(newFocused, sameInstance(rv.getChildAt(1)));
245d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar    }
246d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar
247d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar    @Test
2484510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxNoTranslation() throws Throwable {
2494510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
2504510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
2514510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
2524510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
2534510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 10, 30, 50)));
2544510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
2554510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
2564510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
2574510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
2584510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
2594510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxTranslateX() throws Throwable {
2604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
2614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
2624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
2634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
2644510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setTranslationX(view, 10);
2654510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(20, 10, 40, 50)));
2664510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
2674510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
2684510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
2694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
2704510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
2714510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxTranslateY() throws Throwable {
2724510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
2734510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
2744510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
2754510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
2764510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setTranslationY(view, 10);
2774510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 20, 30, 60)));
2784510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
2794510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
2804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
2814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
2824510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
2834510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxScaleX() throws Throwable {
2844510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
2854510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
2864510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
2874510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
2884510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setScaleX(view, 2);
2894510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 10, 40, 50)));
2904510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
2914510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
2924510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
2934510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
2944510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
2954510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxScaleY() throws Throwable {
2964510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
2974510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
2984510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
2994510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
3004510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setScaleY(view, 2);
3014510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(10, -10, 30, 70)));
3024510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
3034510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
3044510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
3054510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3064510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
3074510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxRotated() throws Throwable {
3084510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        transformedBoundingBoxTest(new ViewRunnable() {
3094510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
3104510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void run(View view) throws RuntimeException {
3114510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
3124510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setRotation(view, 90);
3134510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 20, 40, 40)));
3144510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
3154510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
3164510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
3174510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3184510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
3194510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void boundingBoxRotatedWithDecorOffsets() throws Throwable {
3204510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3214510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        final TestAdapter adapter = new TestAdapter(1);
3224510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        recyclerView.setAdapter(adapter);
3234510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
3244510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
3254510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
3264510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                    RecyclerView.State state) {
3274510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                outRect.set(1, 2, 3, 4);
3284510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
3294510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        });
3304510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        TestLayoutManager layoutManager = new TestLayoutManager() {
3314510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
3324510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3334510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                detachAndScrapAttachedViews(recycler);
3344510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                View view = recycler.getViewForPosition(0);
3354510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                addView(view);
3364510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.measure(
3374510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
3384510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
3394510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                );
3404510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                // trigger decor offsets calculation
3414510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                calculateItemDecorationsForChild(view, new Rect());
3424510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.layout(10, 10, 30, 50);
3434510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                ViewCompat.setRotation(view, 90);
3444510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                assertThat(RecyclerViewLayoutTest.this.getTransformedBoundingBox(view),
3454510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        is(new Rect(-4, 19, 42, 43)));
3464510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3474510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                layoutLatch.countDown();
3484510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
3494510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        };
3504510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        recyclerView.setLayoutManager(layoutManager);
3514510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        layoutManager.expectLayouts(1);
3524510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        setRecyclerView(recyclerView);
3534510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        layoutManager.waitForLayout(2);
3544510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        checkForMainThreadException();
3554510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
3564510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3574510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    private Rect getTransformedBoundingBox(View child) {
3584510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        Rect rect = new Rect();
3594510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        mRecyclerView.getLayoutManager().getTransformedBoundingBox(child, true, rect);
3604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        return rect;
3614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
3624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    public void transformedBoundingBoxTest(final ViewRunnable layout) throws Throwable {
3644510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3654510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        final TestAdapter adapter = new TestAdapter(1);
3664510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        recyclerView.setAdapter(adapter);
3674510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        TestLayoutManager layoutManager = new TestLayoutManager() {
3684510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            @Override
3694510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3704510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                detachAndScrapAttachedViews(recycler);
3714510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                View view = recycler.getViewForPosition(0);
3724510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                addView(view);
3734510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                view.measure(
3744510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
3754510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
3764510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                );
3774510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                layout.run(view);
3784510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                layoutLatch.countDown();
3794510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar            }
3804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        };
3814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        recyclerView.setLayoutManager(layoutManager);
3824510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        layoutManager.expectLayouts(1);
3834510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        setRecyclerView(recyclerView);
3844510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        layoutManager.waitForLayout(2);
3854510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        checkForMainThreadException();
3864510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
3874510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
3884510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    @Test
3890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingFrozen() throws Throwable {
390ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        testScrollFrozen(true);
391ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
392ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
393ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
3940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragFrozen() throws Throwable {
395ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        testScrollFrozen(false);
396ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
397ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
3983d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    @Test
3993d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    public void requestRectOnScreenWithScrollOffset() throws Throwable {
4003d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
4013d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager());
4023d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final int scrollY = 50;
4033d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
4043d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
4053d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
4063d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                View view = new View(parent.getContext());
4073d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                view.setScrollY(scrollY);
4083d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                return new RecyclerView.ViewHolder(view) {
4093d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                };
4103d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
4113d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
4123d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
4133d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
4143d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public int getItemCount() {
4153d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                return 1;
4163d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
4173d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        };
4183d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        recyclerView.setAdapter(adapter);
4193d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        recyclerView.setLayoutManager(tlm);
4203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        tlm.expectLayouts(1);
4213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        setRecyclerView(recyclerView);
4223d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        tlm.waitForLayout(1);
4233d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final View child = recyclerView.getChildAt(0);
4243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        assertThat(child.getScrollY(), CoreMatchers.is(scrollY));
4253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        runTestOnUiThread(new Runnable() {
4263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
4273d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public void run() {
4283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true);
4293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class),
4303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                        any(RecyclerView.State.class));
4313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
4323d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        });
4333d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    }
4343d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar
4352ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata    @Test
4362ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata    public void reattachAndScrollCrash() throws Throwable {
4372ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        final RecyclerView recyclerView = new RecyclerView(getActivity());
4382ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        final TestLayoutManager tlm = new TestLayoutManager() {
4392ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4402ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            @Override
4412ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            public boolean canScrollVertically() {
4422ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                return true;
4432ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            }
4442ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4452ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            @Override
4462ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
4472ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                layoutRange(recycler, 0, Math.min(state.getItemCount(), 10));
4482ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            }
4492ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4502ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            @Override
4512ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
4522ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                                          RecyclerView.State state) {
4532ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                // Access views in the state (that might have been deleted).
4542ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                for (int  i = 10; i < state.getItemCount(); i++) {
4552ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                    recycler.getViewForPosition(i);
4562ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                }
4572ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                return dy;
4582ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            }
4592ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        };
4602ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4612ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        final TestAdapter adapter = new TestAdapter(12);
4622ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4632ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        recyclerView.setAdapter(adapter);
4642ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        recyclerView.setLayoutManager(tlm);
4652ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4662ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        setRecyclerView(recyclerView);
4672ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
4682ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        runTestOnUiThread(new Runnable() {
4692ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            @Override
4702ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            public void run() {
471a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                getActivity().getContainer().removeView(recyclerView);
472a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                getActivity().getContainer().addView(recyclerView);
4732ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                try {
4742ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                    adapter.deleteAndNotify(1, adapter.getItemCount() - 1);
4752ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                } catch (Throwable throwable) {
4762ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                    postExceptionToInstrumentation(throwable);
4772ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                }
4782ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata                recyclerView.scrollBy(0, 10);
4792ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata            }
4802ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata        });
4812ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata    }
4822ee3e8c2bf8a9f02f0f9d487beb6463f172f1137susnata
483ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    private void testScrollFrozen(boolean fling) throws Throwable {
484ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
485ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
486ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int horizontalScrollCount = 3;
487ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int verticalScrollCount = 3;
488ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int horizontalVelocity = 1000;
489ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int verticalVelocity = 1000;
490ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
491ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
492ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
493ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
494ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
495ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
496ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
497ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
498ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
499ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
500ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
501ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
502ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
503ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
504ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
505ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
506ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
507ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
508ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
509ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
510ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
511ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
512ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                if (verticalCounter.get() > 0) {
513ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    verticalCounter.decrementAndGet();
514ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    return dy;
515ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                }
516ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return 0;
517ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
518ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
519ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
520ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
521ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
522ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                if (horizontalCounter.get() > 0) {
523ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    horizontalCounter.decrementAndGet();
524ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    return dx;
525ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                }
526ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return 0;
527ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
528ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
529ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
530ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
531ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
532ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
533ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
534ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
535ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
536ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
537ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
538ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        if (fling) {
539ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity));
540ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        } else { // drag
5410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
542ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    Gravity.LEFT | Gravity.TOP,
543ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
544ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        }
545ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount,
546ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                horizontalCounter.get());
547ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's vertical scroll cb must not run", verticalScrollCount,
548ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                verticalCounter.get());
549ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
550ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
551ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
552ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        if (fling) {
553ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity));
554ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        } else { // drag
5550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
556ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    Gravity.LEFT | Gravity.TOP,
557ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
558ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        }
559ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get());
560ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get());
561ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
562ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
563ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
5644be551523e8e36b5a1d480af456bfb392416882cYigit Boyar    public void testFocusSearchAfterChangedData() throws Throwable {
5654be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
5664be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
5674be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            @Override
5684be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
5694be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                layoutRange(recycler, 0, 2);
5704be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                layoutLatch.countDown();
5714be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            }
5724be551523e8e36b5a1d480af456bfb392416882cYigit Boyar
5734be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            @Nullable
5744be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            @Override
5754be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            public View onFocusSearchFailed(View focused, int direction,
5764be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                                            RecyclerView.Recycler recycler,
5774be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                                            RecyclerView.State state) {
5784be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                try {
5794be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                    View view = recycler.getViewForPosition(state.getItemCount() - 1);
5804be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                } catch (Throwable t) {
5814be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                    postExceptionToInstrumentation(t);
5824be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                }
5834be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                return null;
5844be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            }
5854be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        };
5864be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        recyclerView.setLayoutManager(tlm);
5874be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        final TestAdapter adapter = new TestAdapter(10) {
5884be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            @Override
5894be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            public void onBindViewHolder(TestViewHolder holder, int position) {
5904be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                super.onBindViewHolder(holder, position);
5914be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                holder.itemView.setFocusable(false);
5924be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                holder.itemView.setFocusableInTouchMode(false);
5934be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            }
5944be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        };
5954be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        recyclerView.setAdapter(adapter);
5964be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        tlm.expectLayouts(1);
5974be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        setRecyclerView(recyclerView);
5984be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        tlm.waitForLayout(1);
5994be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        runTestOnUiThread(new Runnable() {
6004be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            @Override
6014be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            public void run() {
6024be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                adapter.mItems.remove(9);
6034be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                adapter.notifyItemRemoved(9);
6044be551523e8e36b5a1d480af456bfb392416882cYigit Boyar                recyclerView.focusSearch(recyclerView.getChildAt(1), View.FOCUS_DOWN);
6054be551523e8e36b5a1d480af456bfb392416882cYigit Boyar            }
6064be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        });
6074be551523e8e36b5a1d480af456bfb392416882cYigit Boyar        checkForMainThreadException();
6084be551523e8e36b5a1d480af456bfb392416882cYigit Boyar    }
6094be551523e8e36b5a1d480af456bfb392416882cYigit Boyar
6104be551523e8e36b5a1d480af456bfb392416882cYigit Boyar    @Test
6113e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar    public void testFocusSearchWithRemovedFocusedItem() throws Throwable {
6123e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
6133e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        recyclerView.setItemAnimator(null);
6143e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        TestLayoutManager tlm = new LayoutAllLayoutManager();
6153e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        recyclerView.setLayoutManager(tlm);
6163e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        final TestAdapter adapter = new TestAdapter(10) {
6173e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            @Override
6183e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            public void onBindViewHolder(TestViewHolder holder, int position) {
6193e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                super.onBindViewHolder(holder, position);
6203e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                holder.itemView.setFocusable(true);
6213e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                holder.itemView.setFocusableInTouchMode(true);
6223e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            }
6233e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        };
6243e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        recyclerView.setAdapter(adapter);
6253e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        tlm.expectLayouts(1);
6263e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        setRecyclerView(recyclerView);
6273e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        tlm.waitForLayout(1);
6283e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        final RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(9);
6293e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        requestFocus(toFocus.itemView, true);
6303e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        assertThat("test sanity", toFocus.itemView.hasFocus(), is(true));
6313e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        runTestOnUiThread(new Runnable() {
6323e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            @Override
6333e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            public void run() {
6343e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                adapter.mItems.remove(9);
6353e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                adapter.notifyItemRemoved(9);
6363e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar                recyclerView.focusSearch(toFocus.itemView, View.FOCUS_DOWN);
6373e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            }
6383e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        });
6393e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar        checkForMainThreadException();
6403e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar    }
6413e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar
6423e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar
6433e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar    @Test
6447bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar    public void  testFocusSearchFailFrozen() throws Throwable {
645ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
6467bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar        final CountDownLatch focusLatch = new CountDownLatch(1);
647ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
648ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
649ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
650ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
651ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
652ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
653ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
654ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
655ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
656ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
657ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
658ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
659ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
660ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
661ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
662ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
663ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
664ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
665ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
666121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            public View onFocusSearchFailed(View focused, int direction,
667121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    RecyclerView.Recycler recycler, RecyclerView.State state) {
668ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                focusSearchCalled.addAndGet(1);
6697bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar                focusLatch.countDown();
670ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return null;
671ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
672ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
673ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
674ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
675ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
676ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
677ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
678ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
679ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
680959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertTrue("test sanity", requestFocus(c, true));
681959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertTrue("test sanity", c.hasFocus());
682ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
6834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        focusSearch(recyclerView, c, View.FOCUS_DOWN);
684ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("onFocusSearchFailed should not be called when layout is frozen",
685ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                0, focusSearchCalled.get());
686ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
687d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        focusSearch(c, View.FOCUS_DOWN);
6887bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
689ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals(1, focusSearchCalled.get());
690ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
691ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
692d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar    public View focusSearch(final ViewGroup parent, final View focused, final int direction)
6934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            throws Throwable {
694d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        final View[] result = new View[1];
6954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        runTestOnUiThread(new Runnable() {
6964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            @Override
6974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            public void run() {
698d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                result[0] = parent.focusSearch(focused, direction);
6994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
7004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        });
701d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar        return result[0];
7024143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
7034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
704ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
7050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void frozenAndChangeAdapter() throws Throwable {
706ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
707ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
708ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
709ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
710ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
711ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
712ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
713ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
714ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
715ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
716ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
717ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
718ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
719ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
720ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
721ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
722ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
723ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
724ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
725ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
726ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
727ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
728ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
729ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                focusSearchCalled.addAndGet(1);
730ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return null;
731ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
732ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
733ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
734ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
735ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
736ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
737ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
738ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
739ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
740ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
741ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter2 = new TestAdapter(1000);
742ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setAdapter(adapter2);
743ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertFalse(recyclerView.isLayoutFrozen());
744ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertSame(adapter2, recyclerView.getAdapter());
745ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
746ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
747ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter3 = new TestAdapter(1000);
748ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        swapAdapter(adapter3, true);
749ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertFalse(recyclerView.isLayoutFrozen());
750ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertSame(adapter3, recyclerView.getAdapter());
751ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
752ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
753ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
7548fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void noLayoutIf0ItemsAreChanged() throws Throwable {
7558fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        unnecessaryNotifyEvents(new AdapterRunnable() {
7568fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
7578fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run(TestAdapter adapter) throws Throwable {
7588fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                adapter.notifyItemRangeChanged(3, 0);
7598fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
7608fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
7618fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
7628fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
7638fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    @Test
7648fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void noLayoutIf0ItemsAreChangedWithPayload() throws Throwable {
7658fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        unnecessaryNotifyEvents(new AdapterRunnable() {
7668fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
7678fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run(TestAdapter adapter) throws Throwable {
7688fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                adapter.notifyItemRangeChanged(0, 0, new Object());
7698fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
7708fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
7718fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
7728fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
7738fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    @Test
7748fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void noLayoutIf0ItemsAreAdded() throws Throwable {
7758fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        unnecessaryNotifyEvents(new AdapterRunnable() {
7768fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
7778fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run(TestAdapter adapter) throws Throwable {
7788fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                adapter.notifyItemRangeInserted(3, 0);
7798fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
7808fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
7818fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
7828fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
7838fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    @Test
7848fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void noLayoutIf0ItemsAreRemoved() throws Throwable {
7858fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        unnecessaryNotifyEvents(new AdapterRunnable() {
7868fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
7878fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run(TestAdapter adapter) throws Throwable {
7888fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                adapter.notifyItemRangeRemoved(3, 0);
7898fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
7908fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
7918fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
7928fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
7938fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    @Test
7948fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void noLayoutIfItemMovedIntoItsOwnPlace() throws Throwable {
7958fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        unnecessaryNotifyEvents(new AdapterRunnable() {
7968fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
7978fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run(TestAdapter adapter) throws Throwable {
7988fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                adapter.notifyItemMoved(3, 3);
7998fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
8008fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
8018fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
8028fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
8038fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    public void unnecessaryNotifyEvents(final AdapterRunnable action) throws Throwable {
8048fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
8058fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        final TestAdapter adapter = new TestAdapter(5);
8068fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
8078fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
8088fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
8098fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                super.onLayoutChildren(recycler, state);
8108fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                layoutLatch.countDown();
8118fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
8128fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        };
8138fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        recyclerView.setLayoutManager(tlm);
8148fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        recyclerView.setAdapter(adapter);
8158fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        tlm.expectLayouts(1);
8168fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        setRecyclerView(recyclerView);
8178fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        tlm.waitForLayout(1);
8188fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        // ready
8198fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        tlm.expectLayouts(1);
8208fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        runTestOnUiThread(new Runnable() {
8218fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            @Override
8228fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            public void run() {
8238fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                try {
8248fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                    action.run(adapter);
8258fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                } catch (Throwable throwable) {
8268fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                    postExceptionToInstrumentation(throwable);
8278fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar                }
8288fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar            }
8298fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        });
8308fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        tlm.assertNoLayout("dummy event should not trigger a layout", 1);
8318fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar        checkForMainThreadException();
8328fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    }
8338fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar
8348fd6812c1cc120bb2637526ca4c641fbb01f7b0cYigit Boyar    @Test
8350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollToPositionCallback() throws Throwable {
8364965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
8374965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
8384965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            int scrollPos = RecyclerView.NO_POSITION;
8391a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
8404965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
8414965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
8424965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                layoutLatch.countDown();
8434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                if (scrollPos == RecyclerView.NO_POSITION) {
8444965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    layoutRange(recycler, 0, 10);
8454965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                } else {
8464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    layoutRange(recycler, scrollPos, scrollPos + 10);
8474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                }
8484965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
8491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
8504965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
8514965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void scrollToPosition(int position) {
8524965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                scrollPos = position;
8534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                requestLayout();
8544965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
8554965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        };
8564965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setLayoutManager(tlm);
8574965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        TestAdapter adapter = new TestAdapter(100);
8584965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setAdapter(adapter);
8594965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        final AtomicInteger rvCounter = new AtomicInteger(0);
8604965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        final AtomicInteger viewGroupCounter = new AtomicInteger(0);
8614965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.getViewTreeObserver().addOnScrollChangedListener(
8624965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                new ViewTreeObserver.OnScrollChangedListener() {
8634965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    @Override
8644965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    public void onScrollChanged() {
8654965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                        viewGroupCounter.incrementAndGet();
8664965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    }
8674965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                });
8684965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
8694965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
8704965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
8714965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                rvCounter.incrementAndGet();
8724965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                super.onScrolled(recyclerView, dx, dy);
8734965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
8744965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        });
8754965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
8763f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar
8774965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        setRecyclerView(recyclerView);
8784965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
8793f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        // wait for draw :/
8803f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        Thread.sleep(1000);
8813f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar
8823f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get());
8833f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("VTO on scroll should be called for initialization", 1,
8844965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                viewGroupCounter.get());
8854965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
886ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
887ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        scrollToPosition(3);
888ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.assertNoLayout("scrollToPosition should be ignored", 2);
889ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
8904965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        scrollToPosition(3);
8914965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
8923f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("RV on scroll should be called", 2, rvCounter.get());
8933f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get());
8944965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
8954965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        requestLayoutOnUIThread(recyclerView);
8964965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
8973f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        // wait for draw :/
8983f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        Thread.sleep(1000);
8994965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        assertEquals("on scroll should NOT be called", 2, rvCounter.get());
9004965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get());
901e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    }
902e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
903e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    @Test
904e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    public void scrollCalllbackOnVisibleRangeExpand() throws Throwable {
905e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{3, 6});
906e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    }
907e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
908e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    @Test
909e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    public void scrollCalllbackOnVisibleRangeShrink() throws Throwable {
910e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{3, 5});
911e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    }
912e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
913e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    @Test
914e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    public void scrollCalllbackOnVisibleRangeExpand2() throws Throwable {
915e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{2, 5});
916e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    }
917e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
918e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    @Test
919e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    public void scrollCalllbackOnVisibleRangeShrink2() throws Throwable {
920e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{2, 6});
921e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    }
922e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
923e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar    private void scrollCallbackOnVisibleRangeChange(int itemCount, final int[] beforeRange,
924e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar            final int[] afterRange) throws Throwable {
925e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
926e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        final AtomicBoolean beforeState = new AtomicBoolean(true);
927e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
928e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar            @Override
929e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
930e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar                detachAndScrapAttachedViews(recycler);
931e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar                int[] range = beforeState.get() ? beforeRange : afterRange;
932e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar                layoutRange(recycler, range[0], range[1]);
933e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar                layoutLatch.countDown();
934e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar            }
935e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        };
936e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        recyclerView.setLayoutManager(tlm);
937e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        final TestAdapter adapter = new TestAdapter(itemCount);
938e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        recyclerView.setAdapter(adapter);
939e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        tlm.expectLayouts(1);
940e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        setRecyclerView(recyclerView);
941e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        tlm.waitForLayout(1);
942e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar
943e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        RecyclerView.OnScrollListener mockListener = mock(RecyclerView.OnScrollListener.class);
944e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        recyclerView.addOnScrollListener(mockListener);
945e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        verify(mockListener, never()).onScrolled(any(RecyclerView.class), anyInt(), anyInt());
9464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar
947e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        tlm.expectLayouts(1);
948e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        beforeState.set(false);
949e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        requestLayoutOnUIThread(recyclerView);
950e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        tlm.waitForLayout(2);
951e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        checkForMainThreadException();
952e4f37e5de85662368bdc74f71b60bf402e6937dfYigit Boyar        verify(mockListener).onScrolled(recyclerView, 0, 0);
9534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar    }
954670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
955be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
9562e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar    public void addItemOnScroll() throws Throwable {
9572e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
9582e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        final AtomicInteger start = new AtomicInteger(0);
9592e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
9602e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            @Override
9612e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
9622e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                layoutRange(recycler, start.get(), start.get() + 10);
9632e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                layoutLatch.countDown();
9642e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            }
9652e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        };
9662e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        recyclerView.setLayoutManager(tlm);
9672e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        final TestAdapter adapter = new TestAdapter(100);
9682e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        recyclerView.setAdapter(adapter);
9692e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        tlm.expectLayouts(1);
9702e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        setRecyclerView(recyclerView);
9712e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        tlm.waitForLayout(1);
9722e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        final Throwable[] error = new Throwable[1];
9732e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        final AtomicBoolean calledOnScroll = new AtomicBoolean(false);
9742e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
9752e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            @Override
9762e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
9772e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                super.onScrolled(recyclerView, dx, dy);
9782e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                calledOnScroll.set(true);
9792e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                try {
9802e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                    adapter.addAndNotify(5, 20);
9812e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                } catch (Throwable throwable) {
9822e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                    error[0] = throwable;
9832e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar                }
9842e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar            }
9852e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        });
9862e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        start.set(4);
9872e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(false));
9882e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        tlm.expectLayouts(1);
9892e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        requestLayoutOnUIThread(recyclerView);
9902e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        tlm.waitForLayout(2);
9912e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        checkForMainThreadException();
9922e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(true));
9932e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar        MatcherAssert.assertThat(error[0], CoreMatchers.nullValue());
9942e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar    }
9952e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar
9962e77ca33cc242ec5750cfc11824c215f8d7ffc22Yigit Boyar    @Test
9970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionEqual() throws Throwable {
998670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 3, 1000, 1000);
999670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1000670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1001be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreVertical() throws Throwable {
1003670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(2, 3, 1000, 1000);
1004670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1005670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1006be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreHorizontal() throws Throwable {
1008670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 2, 1000, 1000);
1009670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1010670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1011be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollHorizontalOnly() throws Throwable {
1013670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 0, 1000, 0);
1014670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1015670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1016be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollVerticalOnly() throws Throwable {
1018670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(0, 3, 0, 1000);
1019670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1020670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1021be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionEqualReverse() throws Throwable {
1023670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 3, -1000, -1000);
1024670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1025670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1026be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreVerticalReverse() throws Throwable {
1028670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(2, 3, -1000, -1000);
1029670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1030670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1031be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable {
1033670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 2, -1000, -1000);
1034670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1035670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1036be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollHorizontalOnlyReverse() throws Throwable {
1038670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 0, -1000, 0);
1039670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1040670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1041be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollVerticalOnlyReverse() throws Throwable {
1043670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(0, 3, 0, -1000);
1044670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1045670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1046670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount,
1047670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            int horizontalVelocity, int verticalVelocity)
1048670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            throws Throwable {
1049670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1050670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
1051670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
1052670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
1053670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1054670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollHorizontally() {
1055670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return true;
1056670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1057670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1058670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1059670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollVertically() {
1060670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return true;
1061670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1062670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1063670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1064670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1065670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutRange(recycler, 0, 10);
1066670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutLatch.countDown();
1067670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1068670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1069670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1070670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
1071670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
1072670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                if (verticalCounter.get() > 0) {
1073670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    verticalCounter.decrementAndGet();
1074670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    return dy;
1075670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                }
1076670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return 0;
1077670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1078670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1079670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1080670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
1081670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
1082670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                if (horizontalCounter.get() > 0) {
1083670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    horizontalCounter.decrementAndGet();
1084670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    return dx;
1085670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                }
1086670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return 0;
1087670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1088670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        };
1089670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestAdapter adapter = new TestAdapter(100);
1090670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setAdapter(adapter);
1091670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setLayoutManager(tlm);
1092670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.expectLayouts(1);
1093670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        setRecyclerView(recyclerView);
1094670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.waitForLayout(2);
1095670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity));
1096670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0,
1097670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                horizontalCounter.get());
1098670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0,
1099670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                verticalCounter.get());
1100670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1101670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1102be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragHorizontal() throws Throwable {
1104cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL);
1105670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1106670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1107be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragVertical() throws Throwable {
1109cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL);
1110670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1111670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1112be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingHorizontal() throws Throwable {
1114cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING);
1115670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1116670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1117be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingVertical() throws Throwable {
1119cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING);
1120670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1121670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1122f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    @Test
11230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragVertical() throws Throwable {
1124a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        TestedFrameLayout tfl = getActivity().getContainer();
1125f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1126f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1127cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
1128f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
1129f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
1130f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    @Test
11310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragHorizontal() throws Throwable {
1132a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        TestedFrameLayout tfl = getActivity().getContainer();
1133f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1134f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1135cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
1136f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
1137670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1138d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    @Test
11390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragHorizontalCallsStopNestedScroll() throws Throwable {
1140a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        TestedFrameLayout tfl = getActivity().getContainer();
1141d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1142d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1143d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
1144d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled());
1145d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    }
1146d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
1147d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    @Test
11480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragVerticalCallsStopNestedScroll() throws Throwable {
1149a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        TestedFrameLayout tfl = getActivity().getContainer();
1150d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1151d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
1152d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
1153d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled());
1154d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    }
1155d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
1156cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private void scrollInOtherOrientationTest(int flags)
1157f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes            throws Throwable {
1158364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar        scrollInOtherOrientationTest(flags, flags);
1159f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
1160f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
1161cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable {
1162670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1163670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false);
1164670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean scrolledVertical = new AtomicBoolean(false);
1165f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
1166f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        final TestLayoutManager tlm = new TestLayoutManager() {
1167670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1168670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollHorizontally() {
1169cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                return (flags & FLAG_HORIZONTAL) != 0;
1170670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1171670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1172670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1173670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollVertically() {
1174cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                return (flags & FLAG_VERTICAL) != 0;
1175670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1176670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1177670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1178670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1179670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutRange(recycler, 0, 10);
1180670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutLatch.countDown();
1181670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1182670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1183670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1184670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
1185670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
1186670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                scrolledVertical.set(true);
1187f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes                return super.scrollVerticallyBy(dy, recycler, state);
1188670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1189670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1190670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1191670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
1192670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
1193670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                scrolledHorizontal.set(true);
1194f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes                return super.scrollHorizontallyBy(dx, recycler, state);
1195670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1196670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        };
1197670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestAdapter adapter = new TestAdapter(100);
1198670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setAdapter(adapter);
1199670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setLayoutManager(tlm);
1200670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.expectLayouts(1);
1201670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        setRecyclerView(recyclerView);
1202670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.waitForLayout(2);
1203cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        if ( (flags & FLAG_FLING) != 0 ) {
1204cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar            int flingVelocity = (mRecyclerView.getMaxFlingVelocity() +
1205cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    mRecyclerView.getMinFlingVelocity()) / 2;
1206cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar            assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0,
1207cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    fling(flingVelocity, flingVelocity));
1208f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        } else { // drag
12090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP,
1210cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
1211670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        }
1212f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount,
1213cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get());
1214f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount,
1215cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get());
1216670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1217670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1218670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    private boolean fling(final int velocityX, final int velocityY) throws Throwable {
1219670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean didStart = new AtomicBoolean(false);
1220670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        runTestOnUiThread(new Runnable() {
1221670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
1222670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void run() {
1223670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                boolean result = mRecyclerView.fling(velocityX, velocityY);
1224670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                didStart.set(result);
1225670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
1226670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        });
1227670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        if (!didStart.get()) {
1228670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            return false;
1229670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        }
1230959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        waitForIdleScroll(mRecyclerView);
1231670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        return true;
1232670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
1233670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
1234959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    private void assertPendingUpdatesAndLayoutTest(final AdapterRunnable runnable) throws Throwable {
1235959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1236959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
1237959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
1238959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, false);
1239959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        layoutManager.expectLayouts(1);
1240da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        runTestOnUiThread(new Runnable() {
1241da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1242da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
1243959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                try {
1244959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                    runnable.run(testAdapter);
1245959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                } catch (Throwable throwable) {
1246959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                    fail("runnable has thrown an exception");
1247959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                }
1248da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                assertTrue(mRecyclerView.hasPendingAdapterUpdates());
1249da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1250da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1251959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        layoutManager.waitForLayout(1);
1252da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
1253959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        checkForMainThreadException();
1254da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
1255da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
1256da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm,
1257da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            TestAdapter adapter, boolean waitForFirstLayout) throws Throwable {
1258da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        recyclerView.setLayoutManager(tlm);
1259da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        recyclerView.setAdapter(adapter);
1260da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        if (waitForFirstLayout) {
1261da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            tlm.expectLayouts(1);
1262da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            setRecyclerView(recyclerView);
1263da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            tlm.waitForLayout(1);
1264da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        } else {
1265da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            setRecyclerView(recyclerView);
1266da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        }
1267da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
1268da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
1269be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
12700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void hasPendingUpdatesBeforeFirstLayout() throws Throwable {
1271da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1272da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
1273da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1274da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, false);
1275da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertTrue(mRecyclerView.hasPendingAdapterUpdates());
1276da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
1277da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
1278be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
12790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void noPendingUpdatesAfterLayout() throws Throwable {
1280da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1281da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
1282da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1283da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, true);
1284da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
1285da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
1286da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
1287be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
1288959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    public void hasPendingUpdatesAfterItemIsRemoved() throws Throwable {
1289959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
1290da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1291959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            public void run(TestAdapter testAdapter) throws Throwable {
1292959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                testAdapter.deleteAndNotify(1, 1);
1293da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1294da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1295959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    }
1296959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    @Test
1297959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    public void hasPendingUpdatesAfterItemIsInserted() throws Throwable {
1298959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
1299da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1300959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            public void run(TestAdapter testAdapter) throws Throwable {
1301959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                testAdapter.addAndNotify(2, 1);
1302da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1303da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1304959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    }
1305959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    @Test
1306959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    public void hasPendingUpdatesAfterItemIsMoved() throws Throwable {
1307959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
1308da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1309959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            public void run(TestAdapter testAdapter) throws Throwable {
1310959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                testAdapter.moveItem(2, 3, true);
1311da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1312da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1313959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    }
1314959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    @Test
1315959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    public void hasPendingUpdatesAfterItemIsChanged() throws Throwable {
1316959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
1317da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1318959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            public void run(TestAdapter testAdapter) throws Throwable {
1319959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                testAdapter.changeAndNotify(2, 1);
1320da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1321da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1322959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    }
1323959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    @Test
1324959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar    public void hasPendingUpdatesAfterDataSetIsChanged() throws Throwable {
1325959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
1326da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
1327959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar            public void run(TestAdapter testAdapter) {
1328959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                mRecyclerView.getAdapter().notifyDataSetChanged();
1329da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
1330da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
1331da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
1332da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
1333be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
13340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateRecycleViaAdapter() throws Throwable {
1335e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(true, false);
1336e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
1337e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1338be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
13390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateRecycleViaTransientStateCleanup() throws Throwable {
1340e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(false, true);
1341e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
1342e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1343be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
13440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateDontRecycle() throws Throwable {
1345e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(false, false);
1346e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
1347e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1348e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState)
1349e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            throws Throwable {
1350e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        final List<View> failedToRecycle = new ArrayList<View>();
1351e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        final List<View> recycled = new ArrayList<View>();
1352e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10) {
1353e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
1354e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public boolean onFailedToRecycleView(
1355e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    TestViewHolder holder) {
1356e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                failedToRecycle.add(holder.itemView);
1357e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (unsetTransientState) {
1358e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    setHasTransientState(holder.itemView, false);
1359e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
1360e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                return succeed;
1361e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
1362e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1363e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
1364e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public void onViewRecycled(TestViewHolder holder) {
1365e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                recycled.add(holder.itemView);
1366e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                super.onViewRecycled(holder);
1367e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
1368e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        };
1369e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
1370e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
1371e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1372e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (getChildCount() == 0) {
1373e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    detachAndScrapAttachedViews(recycler);
1374e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    layoutRange(recycler, 0, 5);
1375e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                } else {
1376e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    removeAndRecycleAllViews(recycler);
1377e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
1378e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (layoutLatch != null) {
1379e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    layoutLatch.countDown();
1380e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
1381e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
1382e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        };
1383e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1384e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setAdapter(testAdapter);
1385e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setLayoutManager(tlm);
1386e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setItemAnimator(null);
1387e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        setRecyclerView(recyclerView);
1388e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        getInstrumentation().waitForIdleSync();
1389e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        // make sure we have enough views after this position so that we'll receive the on recycled
1390e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        // callback
1391e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        View view = recyclerView.getChildAt(3);//this has to be greater than def cache size.
1392e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        setHasTransientState(view, true);
1393e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        tlm.expectLayouts(1);
1394e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        requestLayoutOnUIThread(recyclerView);
1395e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        tlm.waitForLayout(2);
1396e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1397e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        assertTrue(failedToRecycle.contains(view));
1398e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        assertEquals(succeed || unsetTransientState, recycled.contains(view));
1399e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar    }
1400e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
1401be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionInvalidation() throws Throwable {
1403e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
1404e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final TestAdapter adapter = new TestAdapter(10);
1405e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final TestLayoutManager tlm = new TestLayoutManager() {
1406e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            @Override
1407e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1408e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                layoutRange(recycler, 0, state.getItemCount());
1409e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                layoutLatch.countDown();
1410e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            }
1411e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        };
1412e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        recyclerView.setAdapter(adapter);
1413e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        recyclerView.setLayoutManager(tlm);
1414e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        tlm.expectLayouts(1);
1415e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        setRecyclerView(recyclerView);
1416e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        tlm.waitForLayout(1);
1417e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        runTestOnUiThread(new Runnable() {
1418e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            @Override
1419e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            public void run() {
14201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < tlm.getChildCount(); i++) {
1421e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                    assertNotSame("adapter positions should not be undefined",
1422e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
1423e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            RecyclerView.NO_POSITION);
1424e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                }
1425e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                adapter.notifyDataSetChanged();
14261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < tlm.getChildCount(); i++) {
1427e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                    assertSame("adapter positions should be undefined",
1428e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
1429e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            RecyclerView.NO_POSITION);
1430e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                }
1431e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            }
1432e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        });
1433e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar    }
1434e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
1435be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsBasic() throws Throwable {
1437115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(null);
1438115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1439115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1440be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsRemoveItems() throws Throwable {
1442115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1443115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1444115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1445115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.deleteAndNotify(3, 4);
1446115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1447115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1448115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1449115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1450be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsRemoveItemsBefore() throws Throwable {
1452115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1453115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1454115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1455115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.deleteAndNotify(0, 1);
1456115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1457115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1458115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1459115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1460be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsAddItemsBefore() throws Throwable {
1462115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1463115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1464115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1465115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.addAndNotify(0, 5);
1466115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1467115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1468115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1469115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1470be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsAddItemsInside() throws Throwable {
1472115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1473115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1474115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1475115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.addAndNotify(3, 2);
1476115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1477115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1478115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1479115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1480be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsMoveItems() throws Throwable {
1482115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1483115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1484115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1485115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.moveAndNotify(3, 5);
1486115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1487115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1488115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1489115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1490be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14910a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsNotifyDataSetChanged() throws Throwable {
1492115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
1493115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1494115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
1495115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.mItems.clear();
14961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < 20; i++) {
1497115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    adapter.mItems.add(new Item(i, "added item"));
1498115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
1499115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.notifyDataSetChanged();
1500115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1501115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1502115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
1503115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1504be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
15050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable {
1506619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final AtomicBoolean failedToRecycle = new AtomicBoolean(false);
1507619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
1508619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
1509619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
1510619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1511619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                detachAndScrapAttachedViews(recycler);
1512619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutRange(recycler, 0, state.getItemCount());
1513619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutLatch.countDown();
1514619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
1515619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
1516619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestAdapter adapter = new TestAdapter(10) {
1517619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
1518619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public boolean onFailedToRecycleView(
1519619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    TestViewHolder holder) {
1520619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                failedToRecycle.set(true);
1521619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                return false;
1522619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
1523619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
1524619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setAdapter(adapter);
1525619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setLayoutManager(tlm);
1526619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
1527619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        setRecyclerView(rv);
1528619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(1);
1529619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
1530619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        runTestOnUiThread(new Runnable() {
1531619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
1532619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void run() {
1533619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                ViewCompat.setHasTransientState(vh.itemView, true);
1534619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
1535619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        });
1536619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
1537619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        adapter.deleteAndNotify(0, 10);
1538619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(2);
1539619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final CountDownLatch animationsLatch = new CountDownLatch(1);
1540619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.getItemAnimator().isRunning(
1541619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
1542619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    @Override
1543619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    public void onAnimationsFinished() {
1544619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                        animationsLatch.countDown();
1545619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    }
1546619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                });
1547619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
1548619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(failedToRecycle.get());
1549619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertNull(vh.mOwnerRecyclerView);
1550619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        checkForMainThreadException();
1551619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar    }
1552619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar
1553be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
15540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable {
1555619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
1556619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
1557619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
1558619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1559619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                detachAndScrapAttachedViews(recycler);
1560619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutRange(recycler, 0, state.getItemCount());
1561619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutLatch.countDown();
1562619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
1563619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
1564619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
1565619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setAdapter(adapter);
1566619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setLayoutManager(tlm);
1567619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
1568619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        setRecyclerView(rv);
1569619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(1);
1570619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
1571619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
1572619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        adapter.deleteAndNotify(0, 10);
1573619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(2);
1574619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final CountDownLatch animationsLatch = new CountDownLatch(1);
1575619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.getItemAnimator().isRunning(
1576619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
1577619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    @Override
1578619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    public void onAnimationsFinished() {
1579619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                        animationsLatch.countDown();
1580619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    }
1581619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                });
1582619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
1583619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertNull(vh.mOwnerRecyclerView);
1584619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        checkForMainThreadException();
1585619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar    }
1586619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar
1587bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    @Test
1588bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    public void duplicateAdapterPositionTest() throws Throwable {
1589bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
1590bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final TestLayoutManager tlm = new TestLayoutManager() {
1591bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            @Override
1592bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1593bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                detachAndScrapAttachedViews(recycler);
1594bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                layoutRange(recycler, 0, state.getItemCount());
1595bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                if (!state.isPreLayout()) {
1596bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    while (!recycler.getScrapList().isEmpty()) {
1597bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        RecyclerView.ViewHolder viewHolder = recycler.getScrapList().get(0);
1598bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        addDisappearingView(viewHolder.itemView, 0);
1599bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    }
1600bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                }
1601bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                layoutLatch.countDown();
1602bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            }
1603bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1604bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            @Override
1605bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
1606bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                return true;
1607bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            }
1608bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        };
1609bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final DefaultItemAnimator animator = new DefaultItemAnimator();
1610bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        animator.setSupportsChangeAnimations(true);
1611bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        animator.setChangeDuration(10000);
1612bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        testAdapter.setHasStableIds(true);
1613bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
1614bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.setLayoutManager(tlm);
1615bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.setAdapter(testAdapter);
1616bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.setItemAnimator(animator);
1617bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1618bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        tlm.expectLayouts(1);
1619bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        setRecyclerView(recyclerView);
1620bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        tlm.waitForLayout(2);
1621bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1622bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        tlm.expectLayouts(2);
1623bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        testAdapter.mItems.get(2).mType += 2;
1624bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final int itemId = testAdapter.mItems.get(2).mId;
1625bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        testAdapter.changeAndNotify(2, 1);
1626bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        tlm.waitForLayout(2);
1627bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1628bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        runTestOnUiThread(new Runnable() {
1629bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            @Override
1630bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            public void run() {
1631bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat("test sanity", recyclerView.getChildCount(), CoreMatchers.is(11));
1632bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                // now mangle the order and run the test
1633bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                RecyclerView.ViewHolder hidden = null;
1634bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                RecyclerView.ViewHolder updated = null;
1635bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                for (int i = 0; i < recyclerView.getChildCount(); i ++) {
1636bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    View view = recyclerView.getChildAt(i);
1637bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
1638bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    if (vh.getAdapterPosition() == 2) {
1639bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        if (mRecyclerView.mChildHelper.isHidden(view)) {
1640bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                            assertThat(hidden, CoreMatchers.nullValue());
1641bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                            hidden = vh;
1642bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        } else {
1643bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                            assertThat(updated, CoreMatchers.nullValue());
1644bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                            updated = vh;
1645bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        }
1646bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    }
1647bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                }
1648bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(hidden, CoreMatchers.notNullValue());
1649bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(updated, CoreMatchers.notNullValue());
1650bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1651bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                mRecyclerView.eatRequestLayout();
1652bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1653bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                // first put the hidden child back
1654bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                int index1 = mRecyclerView.indexOfChild(hidden.itemView);
1655bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                int index2 = mRecyclerView.indexOfChild(updated.itemView);
1656bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                if (index1 < index2) {
1657bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    // swap views
1658bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                    swapViewsAtIndices(recyclerView, index1, index2);
1659bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                }
1660bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
1661bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1662bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
1663bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1664bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
1665bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1666bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForItemId(itemId),
1667bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1668bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1669bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                // now swap back
1670bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                swapViewsAtIndices(recyclerView, index1, index2);
1671bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1672bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
1673bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
1674bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1675bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
1676bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1677bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForItemId(itemId),
1678bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(updated));
1679bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1680bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                // now remove updated. re-assert fallback to the hidden one
1681bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                tlm.removeView(updated.itemView);
1682bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1683bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(tlm.findViewByPosition(2), CoreMatchers.nullValue());
1684bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
1685bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(hidden));
1686bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
1687bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(hidden));
1688bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                assertThat(recyclerView.findViewHolderForItemId(itemId),
1689bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar                        CoreMatchers.sameInstance(hidden));
1690bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            }
1691bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        });
1692bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1693bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    }
1694bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1695bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    private void swapViewsAtIndices(TestRecyclerView recyclerView, int index1, int index2) {
1696bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (index1 == index2) {
1697bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            return;
1698bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1699bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (index2 < index1) {
1700bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            int tmp = index1;
1701bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            index1 = index2;
1702bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            index2 = tmp;
1703bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1704bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final View v1 = recyclerView.getChildAt(index1);
1705bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        final View v2 = recyclerView.getChildAt(index2);
1706bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        boolean v1Hidden = recyclerView.mChildHelper.isHidden(v1);
1707bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        boolean v2Hidden = recyclerView.mChildHelper.isHidden(v2);
1708bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        // must unhide before swap otherwise bucket indices will become invalid.
1709bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (v1Hidden) {
1710bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            mRecyclerView.mChildHelper.unhide(v1);
1711bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1712bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (v2Hidden) {
1713bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            mRecyclerView.mChildHelper.unhide(v2);
1714bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1715bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.detachViewFromParent(index2);
1716bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.attachViewToParent(v2, index1, v2.getLayoutParams());
1717bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.detachViewFromParent(index1 + 1);
1718bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        recyclerView.attachViewToParent(v1, index2, v1.getLayoutParams());
1719bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1720bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (v1Hidden) {
1721bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            mRecyclerView.mChildHelper.hide(v1);
1722bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1723bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        if (v2Hidden) {
1724bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            mRecyclerView.mChildHelper.hide(v2);
1725bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
1726bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    }
1727bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
1728115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable {
1729115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
1730115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
1731115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1732115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1733115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                try {
1734115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    layoutRange(recycler, Math.min(state.getItemCount(), 2)
1735115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            , Math.min(state.getItemCount(), 7));
1736115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    layoutLatch.countDown();
1737115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                } catch (Throwable t) {
1738115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    postExceptionToInstrumentation(t);
1739115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
1740115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1741115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        };
1742115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
1743115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        recyclerView.setLayoutManager(tlm);
1744115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        recyclerView.setAdapter(testAdapter);
1745115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        tlm.expectLayouts(1);
1746115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        setRecyclerView(recyclerView);
1747115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        tlm.waitForLayout(1);
1748115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        runTestOnUiThread(new Runnable() {
1749115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
1750115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run() {
1751115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                try {
1752115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    final int count = recyclerView.getChildCount();
1753115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    Map<View, Integer> layoutPositions = new HashMap<View, Integer>();
1754115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    assertTrue("test sanity", count > 0);
17551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    for (int i = 0; i < count; i++) {
1756115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        View view = recyclerView.getChildAt(i);
1757115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view);
1758115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        int index = testAdapter.mItems.indexOf(vh.mBoundItem);
1759115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        assertEquals("should be able to find VH with adapter position " + index, vh,
1760115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                recyclerView.findViewHolderForAdapterPosition(index));
1761115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        assertEquals("get adapter position should return correct index", index,
1762115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                vh.getAdapterPosition());
1763115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        layoutPositions.put(view, vh.mPosition);
1764115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
1765115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    if (adapterChanges != null) {
1766115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        adapterChanges.run(testAdapter);
1767115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        for (int i = 0; i < count; i++) {
1768115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            View view = recyclerView.getChildAt(i);
1769115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            TestViewHolder vh = (TestViewHolder) recyclerView
1770115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    .getChildViewHolder(view);
1771115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            int index = testAdapter.mItems.indexOf(vh.mBoundItem);
1772115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            if (index >= 0) {
1773115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                assertEquals("should be able to find VH with adapter position "
17741a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                                                + index, vh,
1775115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                        recyclerView.findViewHolderForAdapterPosition(index));
1776115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            }
1777115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            assertSame("get adapter position should return correct index", index,
1778115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    vh.getAdapterPosition());
1779115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            assertSame("should be able to find view with layout position",
1780115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    vh, mRecyclerView.findViewHolderForLayoutPosition(
1781115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                            layoutPositions.get(view)));
1782115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        }
1783115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1784115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
1785115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1786115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                } catch (Throwable t) {
1787115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    postExceptionToInstrumentation(t);
1788115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
1789115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1790115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1791115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        checkForMainThreadException();
1792e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
1793e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1794be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
17950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForSmoothScroll() throws Throwable {
1796bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1797bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1798bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1799bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1800bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1801bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1802bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1803bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1804bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1805bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(2);
1806bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1807bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1808bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1809bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1810bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1811bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1812bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1813bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1814bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1815bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1816bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.smoothScrollBy(0, 500);
1817bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1818bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1819bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1820bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1821bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1822bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1823bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1824bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1825be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
18260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForSmoothScrollWithStop() throws Throwable {
1827bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1828bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1829bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1830bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1831bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1832bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1833bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1834bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1835bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1836bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(1);
1837bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1838bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1839bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1840bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1841bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1842bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1843bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1844bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1845bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1846bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1847bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.smoothScrollBy(0, 500);
1848bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1849bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1850bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1851bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1852bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1853bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1854bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.stopScroll();
1855bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1856bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1857bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1858bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1859bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1860bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1861bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1862bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1863be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
18640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForFling() throws Throwable {
1865bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1866bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1867bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1868bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1869bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1870bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1871bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1872bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1873bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1874bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(2);
1875bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1876bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1877bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1878bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1879bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1880bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1881bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1882bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
1883bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final float fling = vc.getScaledMinimumFlingVelocity()
1884bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f;
1885bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1886bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1887bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1888bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.fling(0, Math.round(fling));
1889bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1890bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1891bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1892bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1893bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1894bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1895bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1896bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1897be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
18980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForFlingWithStop() throws Throwable {
1899bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1900bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1901bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1902bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1903bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1904bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1905bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1906bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1907bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1908bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(1);
1909bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1910bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1911bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1912bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1913bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1914bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1915bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1916bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
1917bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final float fling = vc.getScaledMinimumFlingVelocity()
1918bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f;
1919bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1920bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1921bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1922bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.fling(0, Math.round(fling));
1923bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1924bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1925bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1926bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1927bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1928bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1929bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.stopScroll();
1930bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1931bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1932bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1933bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1934bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1935bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1936bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1937bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1938be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
19390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateDrag() throws Throwable {
1940bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1941bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1942bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1943bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1944bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1945bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1946bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1947bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1948bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1949bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1950bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1951bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1952bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1953bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1954bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1955bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        drag(mRecyclerView, 0, 0, 0, 500, 5);
1956bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]);
1957bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1958bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]);
1959bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1960bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1961bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY,
1962bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            int stepCount) throws Throwable {
1963bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        long downTime = SystemClock.uptimeMillis();
1964bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        long eventTime = SystemClock.uptimeMillis();
1965bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1966bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float y = fromY;
1967bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float x = fromX;
1968bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1969bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float yStep = (toY - fromY) / stepCount;
1970bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float xStep = (toX - fromX) / stepCount;
1971bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1972bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
1973bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                MotionEvent.ACTION_DOWN, x, y, 0);
1974bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        sendTouch(view, event);
1975bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        for (int i = 0; i < stepCount; ++i) {
1976bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            y += yStep;
1977bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            x += xStep;
1978bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            eventTime = SystemClock.uptimeMillis();
1979bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
1980bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            sendTouch(view, event);
1981bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
1982bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1983bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        eventTime = SystemClock.uptimeMillis();
1984bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
1985bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        sendTouch(view, event);
1986bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1987bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1988bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1989bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable {
1990bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1991bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1992bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1993bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                if (view.onInterceptTouchEvent(event)) {
1994bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                    view.onTouchEvent(event);
1995bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                }
1996bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1997bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1998bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1999bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
2000be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
20010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleScrap() throws Throwable {
200266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recycleScrapTest(false);
200366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        removeRecyclerView();
200466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recycleScrapTest(true);
200566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    }
200666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar
200766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    public void recycleScrapTest(final boolean useRecycler) throws Throwable {
200866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
200966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        final AtomicBoolean test = new AtomicBoolean(false);
201066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
201166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            @Override
201266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2013e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
201466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                if (test.get()) {
201566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    try {
201666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        detachAndScrapAttachedViews(recycler);
201766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) {
201866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            if (useRecycler) {
201966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                recycler.recycleView(recycler.getScrapList().get(i).itemView);
202066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            } else {
202166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                removeAndRecycleView(recycler.getScrapList().get(i).itemView,
202266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                        recycler);
202366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            }
202466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
2025e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                        if (infoStore.mOldChangedHolders != null) {
2026e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                            for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
202766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                if (useRecycler) {
202866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                    recycler.recycleView(
2029e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            infoStore.mOldChangedHolders.valueAt(i).itemView);
203066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                } else {
203166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                    removeAndRecycleView(
2032e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            infoStore.mOldChangedHolders.valueAt(i).itemView,
2033e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            recycler);
203466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                }
203566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            }
203666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
203766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
203866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("pre layout map should be empty", 0,
2039e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                InfoStoreTrojan.sizeOfPreLayout(infoStore));
204066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("post layout map should be empty", 0,
2041e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                InfoStoreTrojan.sizeOfPostLayout(infoStore));
2042e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                        if (infoStore.mOldChangedHolders != null) {
204366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            assertEquals("post old change map should be empty", 0,
2044e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                    infoStore.mOldChangedHolders.size());
204566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
204666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    } catch (Throwable t) {
204766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        postExceptionToInstrumentation(t);
204866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    }
204966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar
205066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                }
205166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                layoutRange(recycler, 0, 5);
205266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                layoutLatch.countDown();
205366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                super.onLayoutChildren(recycler, state);
205466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            }
205566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        };
205666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
205766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recyclerView.setAdapter(testAdapter);
205866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recyclerView.setLayoutManager(lm);
2059121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
206066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.expectLayouts(1);
206166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        setRecyclerView(recyclerView);
206266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.waitForLayout(2);
206366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        test.set(true);
206466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.expectLayouts(1);
206566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        testAdapter.changeAndNotify(3, 1);
206666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.waitForLayout(2);
206766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        checkForMainThreadException();
206866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    }
206922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
2070be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
20714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable {
20725cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        accessRecyclerOnOnMeasureTest(true);
20735cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    }
20745cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
2075be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
20764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable {
20774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        accessRecyclerOnOnMeasureTest(false);
20784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
20794143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
20804143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    @Test
20810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable {
2082cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        smoothScrollTest(true);
2083cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    }
2084cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar
2085cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    @Test
20860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void smoothScrollWithRemovedItems() throws Throwable {
2087ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        smoothScrollTest(false);
2088ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    }
2089ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2090ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    public void smoothScrollTest(final boolean removeItem) throws Throwable {
2091ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final LinearSmoothScroller[] lss = new LinearSmoothScroller[1];
2092ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final CountDownLatch calledOnStart = new CountDownLatch(1);
2093ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final CountDownLatch calledOnStop = new CountDownLatch(1);
2094ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final int visibleChildCount = 10;
2095ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
2096ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            int start = 0;
2097ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2098ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
2099ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2100ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                super.onLayoutChildren(recycler, state);
2101ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                layoutRange(recycler, start, visibleChildCount);
2102ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                layoutLatch.countDown();
2103ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2104ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2105ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
2106ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
2107ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    RecyclerView.State state) {
2108ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                start++;
2109ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                if (DEBUG) {
2110ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:"
2111ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            + visibleChildCount);
2112ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                }
2113ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                removeAndRecycleAllViews(recycler);
2114c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                layoutRange(recycler, start,
2115c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                        Math.max(state.getItemCount(), start + visibleChildCount));
2116ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                return dy;
2117ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2118ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2119ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
2120ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public boolean canScrollVertically() {
2121ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                return true;
2122ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2123ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2124ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
2125ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
2126ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    int position) {
2127ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                LinearSmoothScroller linearSmoothScroller =
2128ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
2129ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
2130ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
2131ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                return new PointF(0, 1);
2132ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
2133ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2134ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
2135ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            protected void onStart() {
2136ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                super.onStart();
2137ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                calledOnStart.countDown();
2138ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
2139ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2140ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
2141ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            protected void onStop() {
2142ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                super.onStop();
2143ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                calledOnStop.countDown();
2144ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
2145ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        };
2146ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                linearSmoothScroller.setTargetPosition(position);
2147ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                lss[0] = linearSmoothScroller;
2148ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                startSmoothScroll(linearSmoothScroller);
2149ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2150ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        };
2151ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
2152ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        TestAdapter testAdapter = new TestAdapter(500);
2153ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        rv.setLayoutManager(lm);
2154ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        rv.setAdapter(testAdapter);
2155ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        lm.expectLayouts(1);
2156ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        setRecyclerView(rv);
2157ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        lm.waitForLayout(1);
2158ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        // regular scroll
2159ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final int targetPosition = visibleChildCount * (removeItem ? 30 : 4);
2160ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        runTestOnUiThread(new Runnable() {
2161ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
2162ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void run() {
2163ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                rv.smoothScrollToPosition(targetPosition);
2164ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2165ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        });
2166ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        if (DEBUG) {
2167ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            Log.d(TAG, "scrolling to target position " + targetPosition);
2168ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        }
2169ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS));
2170ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        if (removeItem) {
2171ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            final int newTarget = targetPosition - 10;
2172ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1);
217390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            final CountDownLatch targetCheck = new CountDownLatch(1);
2174ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            runTestOnUiThread(new Runnable() {
2175ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                @Override
2176ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                public void run() {
2177ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    ViewCompat.postOnAnimationDelayed(rv, new Runnable() {
2178ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        @Override
2179ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        public void run() {
2180ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            try {
2181ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                assertEquals("scroll position should be updated to next available",
2182ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                        newTarget, lss[0].getTargetPosition());
2183ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            } catch (Throwable t) {
2184ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                postExceptionToInstrumentation(t);
2185ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
218690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                            targetCheck.countDown();
2187ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        }
218890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    }, 50);
2189ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                }
2190ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            });
219190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            assertTrue("target position should be checked on time ",
219290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    targetCheck.await(10, TimeUnit.SECONDS));
2193ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            checkForMainThreadException();
2194ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS));
2195ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            checkForMainThreadException();
2196ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertNotNull("should scroll to new target " + newTarget
2197115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    , rv.findViewHolderForLayoutPosition(newTarget));
2198ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            if (DEBUG) {
2199ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                Log.d(TAG, "on stop has been called on time");
2200ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
2201ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        } else {
2202ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertTrue("on stop should be called eventually",
2203ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    calledOnStop.await(30, TimeUnit.SECONDS));
2204ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertNotNull("scroll to position should succeed",
2205115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    rv.findViewHolderForLayoutPosition(targetPosition));
2206ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        }
2207ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        checkForMainThreadException();
2208ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    }
2209ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
2210be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
22110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void consecutiveSmoothScroll() throws Throwable {
221278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger visibleChildCount = new AtomicInteger(10);
221378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger totalScrolled = new AtomicInteger(0);
221478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
221578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            int start = 0;
221678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
221778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
221878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
221978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                super.onLayoutChildren(recycler, state);
222078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                layoutRange(recycler, start, visibleChildCount.get());
222178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                layoutLatch.countDown();
222278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
222378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
222478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
222578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
222678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                    RecyclerView.State state) {
222778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                totalScrolled.set(totalScrolled.get() + dy);
222878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                return dy;
222978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
223078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
223178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
223278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public boolean canScrollVertically() {
223378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                return true;
223478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
223578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        };
223678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
223778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        TestAdapter testAdapter = new TestAdapter(500);
223878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        rv.setLayoutManager(lm);
223978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        rv.setAdapter(testAdapter);
224078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        lm.expectLayouts(1);
224178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        setRecyclerView(rv);
224278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        lm.waitForLayout(1);
224378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        runTestOnUiThread(new Runnable() {
224478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
224578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void run() {
224678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                rv.smoothScrollBy(0, 2000);
224778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
224878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        });
224978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        Thread.sleep(250);
225078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger scrollAmt = new AtomicInteger();
225178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        runTestOnUiThread(new Runnable() {
225278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
225378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void run() {
225478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                final int soFar = totalScrolled.get();
225578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                scrollAmt.set(soFar);
225678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                rv.smoothScrollBy(0, 5000 - soFar);
225778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
225878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        });
22591a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        while (rv.getScrollState() != SCROLL_STATE_IDLE) {
226078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            Thread.sleep(100);
226178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        }
226278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final int soFar = totalScrolled.get();
226378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        assertEquals("second scroll should be competed properly", 5000, soFar);
226478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar    }
226578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
22665cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations)
22675cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            throws Throwable {
22685cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
22695cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10);
22705cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
22715cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
22725cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
22735cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                super.onLayoutChildren(recycler, state);
22745cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                try {
22755cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
22765cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutLatch.countDown();
22775cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                } catch (Throwable t) {
22785cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    postExceptionToInstrumentation(t);
22795cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                } finally {
22805cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutLatch.countDown();
22815cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                }
22825cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
22835cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
22845cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
22855cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
22865cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    int widthSpec, int heightSpec) {
22875cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                try {
22885cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    // make sure we access all views
22895cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    for (int i = 0; i < state.getItemCount(); i++) {
22905cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        View view = recycler.getViewForPosition(i);
22915cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        assertNotNull(view);
22925cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        assertEquals(i, getPosition(view));
22935cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    }
22944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    if (!state.isPreLayout()) {
22954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        assertEquals(state.toString(),
22964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                                expectedOnMeasureStateCount.get(), state.getItemCount());
22974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    }
2298824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                } catch (Throwable t) {
22995cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    postExceptionToInstrumentation(t);
23005cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                }
23015cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                super.onMeasure(recycler, state, widthSpec, heightSpec);
23025cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
23035cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
23045cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
23055cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public boolean supportsPredictiveItemAnimations() {
23065cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                return enablePredictiveAnimations;
23075cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
23085cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        };
23095cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
23105cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setLayoutManager(lm);
23115cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setAdapter(testAdapter);
23125cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setLayoutManager(lm);
23135cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.expectLayouts(1);
23145cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        setRecyclerView(recyclerView);
23155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.waitForLayout(2);
23165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        checkForMainThreadException();
23175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.expectLayouts(1);
23185cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        if (!enablePredictiveAnimations) {
23195cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            expectedOnMeasureStateCount.set(15);
23205cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        }
23215cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        testAdapter.addAndNotify(4, 5);
23225cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.waitForLayout(2);
23235cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        checkForMainThreadException();
23245cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    }
23255cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
2326be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
23270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void setCompatibleAdapter() throws Throwable {
23280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(true, true);
23290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
23300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(false, true);
23310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
23320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(true, false);
23330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
23340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(false, false);
23350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
23360b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
23370b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
23380b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews)
23390b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            throws Throwable {
23400b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
23410b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        final AtomicInteger recycledViewCount = new AtomicInteger();
23420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
23430b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
23440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
23450b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                try {
23460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
23470b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
23480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } catch (Throwable t) {
23490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    postExceptionToInstrumentation(t);
23500b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } finally {
23510b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
23520b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                }
23530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
23540b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        };
23550b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
23560b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
23570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setAdapter(testAdapter);
23580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
23590b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
23600b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onViewRecycled(RecyclerView.ViewHolder holder) {
23610b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                recycledViewCount.incrementAndGet();
23620b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
23630b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        });
23640b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
23650b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setRecyclerView(recyclerView, !useCustomPool);
23660b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
23670b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
23680b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
23690b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews);
23700b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
23710b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
23720b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        if (removeAndRecycleExistingViews) {
23730b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            assertTrue("Previous views should be recycled", recycledViewCount.get() > 0);
23740b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        } else {
23750b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            assertEquals("No views should be recycled if adapters are compatible and developer "
23760b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    + "did not request a recycle", 0, recycledViewCount.get());
23770b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
23780b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
23790b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
2380be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
23810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void setIncompatibleAdapter() throws Throwable {
23820b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        incompatibleAdapterTest(true);
23830b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        incompatibleAdapterTest(false);
23840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
23850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
23860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable {
23870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
23880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
23890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
23900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
23910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                super.onLayoutChildren(recycler, state);
23920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                try {
23930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
23940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
23950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } catch (Throwable t) {
23960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    postExceptionToInstrumentation(t);
23970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } finally {
23980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
23990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                }
24000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
24010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        };
24020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
24030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
24040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setAdapter(testAdapter);
24050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
24060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
24070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setRecyclerView(recyclerView, !useCustomPool);
24080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
24090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
24100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
24110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setAdapter(new TestAdapter2(10));
24120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
24130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
24140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
24150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
2416be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
24170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleIgnored() throws Throwable {
24186e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
24196e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
24206e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            @Override
24216e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
24226e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                layoutRange(recycler, 0, 5);
24236e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                layoutLatch.countDown();
24246e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            }
24256e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        };
24266e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
24276e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        recyclerView.setAdapter(adapter);
24286e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        recyclerView.setLayoutManager(lm);
24296e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        lm.expectLayouts(1);
24306e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        setRecyclerView(recyclerView);
24316e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        lm.waitForLayout(2);
24326e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        runTestOnUiThread(new Runnable() {
24336e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            @Override
24346e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            public void run() {
24356e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                View child1 = lm.findViewByPosition(0);
24366e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                View child2 = lm.findViewByPosition(1);
24376e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.ignoreView(child1);
24386e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.ignoreView(child2);
24396e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
24406e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.removeAndRecycleAllViews(recyclerView.mRecycler);
24416e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertEquals("ignored child should not be recycled or removed", 2,
24426e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                        lm.getChildCount());
24436e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
24446e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                Throwable[] throwables = new Throwable[1];
24456e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                try {
24466e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                    lm.removeAndRecycleView(child1, mRecyclerView.mRecycler);
24476e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                } catch (Throwable t) {
24486e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                    throwables[0] = t;
24496e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                }
24506e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertTrue("Trying to recycle an ignored view should throw IllegalArgException "
24515cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        , throwables[0] instanceof IllegalArgumentException);
24526e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.removeAllViews();
24536e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertEquals("ignored child should be removed as well ", 0, lm.getChildCount());
24546e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            }
24556e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        });
24566e560171b774afafd572b1896becac7b308a92e6Yigit Boyar    }
24576e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
2458be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
24590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findIgnoredByPosition() throws Throwable {
2460f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
2461f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
2462f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            @Override
2463f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2464f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                detachAndScrapAttachedViews(recycler);
2465f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                layoutRange(recycler, 0, 5);
2466f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                layoutLatch.countDown();
2467f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            }
2468f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        };
2469f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2470f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        recyclerView.setAdapter(adapter);
2471f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        recyclerView.setLayoutManager(lm);
2472f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.expectLayouts(1);
2473f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        setRecyclerView(recyclerView);
2474f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.waitForLayout(2);
2475f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        Thread.sleep(5000);
2476f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final int pos = 1;
2477f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final View[] ignored = new View[1];
2478f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        runTestOnUiThread(new Runnable() {
2479f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            @Override
2480f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            public void run() {
2481f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                View child = lm.findViewByPosition(pos);
2482f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                lm.ignoreView(child);
2483f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                ignored[0] = child;
2484f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            }
2485f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        });
2486f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotNull("ignored child should not be null", ignored[0]);
2487f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNull("find view by position should not return ignored child",
2488f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                lm.findViewByPosition(pos));
2489f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.expectLayouts(1);
2490f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        requestLayoutOnUIThread(mRecyclerView);
2491f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.waitForLayout(1);
2492f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertEquals("child count should be ", 6, lm.getChildCount());
2493f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        View replacement = lm.findViewByPosition(pos);
2494f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotNull("re-layout should replace ignored child w/ another one", replacement);
2495f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotSame("replacement should be a different view", replacement, ignored[0]);
2496f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar    }
2497f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar
2498be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
24990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void invalidateAllDecorOffsets() throws Throwable {
2500bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
2501bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2502bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true);
2503bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setAdapter(adapter);
2504bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(4);
2505bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() {
2506bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        };
2507bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        TestLayoutManager testLayoutManager = new TestLayoutManager() {
2508bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
2509bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2510bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                try {
2511bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    // test
2512824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    for (int i = 0; i < getChildCount(); i++) {
2513bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        View child = getChildAt(i);
2514bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
2515bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                child.getLayoutParams();
2516bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        assertEquals(
2517bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                "Decor insets validation for VH should have expected value.",
2518bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                invalidatedOffsets.get(), lp.mInsetsDirty);
2519bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    }
2520bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) {
2521bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
2522bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                vh.itemView.getLayoutParams();
2523bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        assertEquals(
2524bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                "Decor insets invalidation in cache for VH should have expected "
2525bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                        + "value.",
2526bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                invalidatedOffsets.get(), lp.mInsetsDirty);
2527bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    }
2528bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    detachAndScrapAttachedViews(recycler);
2529bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    layoutRange(recycler, 0, layoutCount.get());
2530bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                } catch (Throwable t) {
2531bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    postExceptionToInstrumentation(t);
2532bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                } finally {
2533bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    layoutLatch.countDown();
2534bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                }
2535bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
2536bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2537bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
2538bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
2539bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                return false;
2540bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
2541bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        };
2542bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // first layout
2543bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setItemViewCacheSize(5);
2544bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setLayoutManager(testLayoutManager);
2545bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2546e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        setRecyclerView(recyclerView, true, false);
2547bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(2);
2548bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2549bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2550bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // re-layout w/o any change
2551bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
2552bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2553bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(recyclerView);
2554bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2555bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2556bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2557bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // invalidate w/o an item decorator
2558e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
2559bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
2560bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2561bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
2562bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.assertNoLayout("layout should not happen", 2);
2563bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2564bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2565bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // set item decorator, should invalidate
2566bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
2567bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2568bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        addItemDecoration(mRecyclerView, dummyItemDecoration);
2569bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2570bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2571bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2572bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // re-layout w/o any change
2573bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
2574bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2575bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(recyclerView);
2576bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2577bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2578bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2579bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // invalidate w/ item decorator
2580bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
2581bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
2582bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2583bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
2584bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(2);
2585bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2586bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2587bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // trigger cache.
2588bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        layoutCount.set(3);
2589bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
2590bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2591bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(mRecyclerView);
2592bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2593bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2594bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size());
2595bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2596bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        layoutCount.set(5);
2597bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
2598bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2599bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
2600bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2601bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2602bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2603bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // remove item decorator
2604bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
2605bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
2606bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        removeItemDecoration(mRecyclerView, dummyItemDecoration);
2607bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
2608bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
2609bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
2610bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2611bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void addItemDecoration(final RecyclerView recyclerView, final
2612824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
2613bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
2614bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
2615bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
2616bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.addItemDecoration(itemDecoration);
2617bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
2618bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
2619bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
2620bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2621bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void removeItemDecoration(final RecyclerView recyclerView, final
2622bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
2623bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
2624bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
2625bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
2626bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.removeItemDecoration(itemDecoration);
2627bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
2628bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
2629bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
2630bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2631bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable {
2632bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
2633bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
2634bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
2635bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.invalidateItemDecorations();
2636bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
2637bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
2638bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
2639bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
2640be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
26410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void invalidateDecorOffsets() throws Throwable {
2642cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final TestAdapter adapter = new TestAdapter(10);
2643cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.setHasStableIds(true);
2644cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final RecyclerView recyclerView = new RecyclerView(getActivity());
2645cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        recyclerView.setAdapter(adapter);
2646cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2647cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final Map<Long, Boolean> changes = new HashMap<Long, Boolean>();
2648cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2649cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        TestLayoutManager testLayoutManager = new TestLayoutManager() {
2650cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            @Override
2651cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2652cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                try {
2653cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    if (changes.size() > 0) {
2654cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                        // test
2655824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        for (int i = 0; i < getChildCount(); i++) {
2656cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            View child = getChildAt(i);
2657cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
2658cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    child.getLayoutParams();
2659cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            RecyclerView.ViewHolder vh = lp.mViewHolder;
2660cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            if (!changes.containsKey(vh.getItemId())) {
2661cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                continue; //nothing to test
2662cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            }
2663cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            assertEquals(
2664cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    "Decord insets validation for VH should have expected value.",
2665cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    changes.get(vh.getItemId()).booleanValue(),
2666cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    lp.mInsetsDirty);
2667cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                        }
2668cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    }
2669cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    detachAndScrapAttachedViews(recycler);
2670cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    layoutRange(recycler, 0, state.getItemCount());
2671cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                } catch (Throwable t) {
2672cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    postExceptionToInstrumentation(t);
2673cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                } finally {
2674cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    layoutLatch.countDown();
2675cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                }
2676cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            }
2677cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2678cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            @Override
2679cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            public boolean supportsPredictiveItemAnimations() {
2680cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                return false;
2681cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            }
2682cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        };
2683cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        recyclerView.setLayoutManager(testLayoutManager);
2684cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
2685cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        setRecyclerView(recyclerView);
2686cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
2687cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        int itemAddedTo = 5;
2688cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        for (int i = 0; i < itemAddedTo; i++) {
2689115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
2690cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
2691cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) {
2692115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
2693cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
2694cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
2695cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.addAndNotify(5, 1);
2696cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
2697cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
2698cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2699cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        changes.clear();
2700cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        int[] changedItems = new int[]{3, 5, 6};
2701824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < adapter.getItemCount(); i++) {
2702115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
2703cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
2704824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < changedItems.length; i++) {
27051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItems[i]).getItemId(),
27061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    true);
2707cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
2708cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
2709cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.changePositionsAndNotify(changedItems);
2710cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
2711cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
2712cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2713824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < adapter.getItemCount(); i++) {
2714115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
2715cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
2716cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
2717cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.dispatchDataSetChanged();
2718cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
2719cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
2720cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase    }
2721cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2722be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
27230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void movingViaStableIds() throws Throwable {
2724c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        stableIdsMoveTest(true);
2725c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        removeRecyclerView();
2726c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        stableIdsMoveTest(false);
2727c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        removeRecyclerView();
2728c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    }
2729c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2730c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable {
2731c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
2732c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        testAdapter.setHasStableIds(true);
2733c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final AtomicBoolean test = new AtomicBoolean(false);
2734c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final int movedViewFromIndex = 3;
2735c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final int movedViewToIndex = 6;
2736c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final View[] movedView = new View[1];
2737c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
2738c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
2739c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2740c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                detachAndScrapAttachedViews(recycler);
2741c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                try {
2742c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    if (test.get()) {
2743c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        if (state.isPreLayout()) {
2744c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            View view = recycler.getViewForPosition(movedViewFromIndex, true);
2745c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertSame("In pre layout, should be able to get moved view w/ old "
2746c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                                    + "position", movedView[0], view);
2747c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
2748c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
2749c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            // clear scrap flag
2750c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            holder.clearReturnedFromScrapFlag();
2751c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        } else {
2752c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            View view = recycler.getViewForPosition(movedViewToIndex, true);
2753c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertSame("In post layout, should be able to get moved view w/ new "
2754c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                                    + "position", movedView[0], view);
2755c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
2756c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
2757c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            // clear scrap flag
2758c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            holder.clearReturnedFromScrapFlag();
2759c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        }
2760c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    }
2761c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
2762c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                } catch (Throwable t) {
2763c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    postExceptionToInstrumentation(t);
2764c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                } finally {
2765c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    layoutLatch.countDown();
2766c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                }
2767c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2768c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2769c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2770c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2771c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
2772c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public boolean supportsPredictiveItemAnimations() {
2773c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                return supportsPredictive;
2774c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2775c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        };
2776c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        RecyclerView recyclerView = new RecyclerView(this.getActivity());
2777c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        recyclerView.setAdapter(testAdapter);
2778c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        recyclerView.setLayoutManager(lm);
2779c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.expectLayouts(1);
2780c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        setRecyclerView(recyclerView);
2781c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.waitForLayout(1);
2782c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2783c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        movedView[0] = recyclerView.getChildAt(movedViewFromIndex);
2784c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        test.set(true);
2785c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.expectLayouts(supportsPredictive ? 2 : 1);
2786c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        runTestOnUiThread(new Runnable() {
2787c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
2788c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public void run() {
2789c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                Item item = testAdapter.mItems.remove(movedViewFromIndex);
2790c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.mItems.add(movedViewToIndex, item);
2791c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.notifyItemRemoved(movedViewFromIndex);
2792c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.notifyItemInserted(movedViewToIndex);
2793c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2794c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        });
2795c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.waitForLayout(2);
2796c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        checkForMainThreadException();
2797c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    }
2798cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2799be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringLayout() throws Throwable {
28010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() {
28020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
28030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
28040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyDataSetChanged();
28050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
28060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
28070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() {
28090bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
28100bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
28110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemChanged(2);
28120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
28130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
28140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() {
28160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
28170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
28180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemInserted(2);
28190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
28200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
28210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() {
28220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
28230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
28240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemRemoved(2);
28250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
28260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
28270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
28280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void adapterChangeInMainThreadTest(String msg,
28300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            final Runnable onLayoutRunnable) throws Throwable {
283166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        setIgnoreMainThreadException(true);
28320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        final AtomicBoolean doneFirstLayout = new AtomicBoolean(false);
28330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
28340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
28350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
28360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
28370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                super.onLayoutChildren(recycler, state);
28380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
28390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
28400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    if (doneFirstLayout.get()) {
28410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        onLayoutRunnable.run();
28420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    }
28430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
28440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
28450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
28460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
28470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
28480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
28500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        };
28510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
28520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setLayoutManager(lm);
28530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setAdapter(testAdapter);
28540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
28550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        setRecyclerView(recyclerView);
28560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
28570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        doneFirstLayout.set(true);
28580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
28590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        requestLayoutOnUIThread(recyclerView);
28600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
28610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        removeRecyclerView();
28620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertTrue("Invalid data updates should be caught:" + msg,
286366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar                getMainThreadException() instanceof IllegalStateException);
28640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
28650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2866be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringScroll() throws Throwable {
28680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        for (int orientation : new int[]{OrientationHelper.HORIZONTAL,
28690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                OrientationHelper.VERTICAL}) {
28700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyDataSetChanged", orientation,
28710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    new Runnable() {
28720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        @Override
28730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        public void run() {
28740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            mRecyclerView.getAdapter().notifyDataSetChanged();
28750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        }
28760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    });
28770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() {
28780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
28790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
28800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemChanged(2);
28810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
28820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
28830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() {
28850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
28860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
28870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemInserted(2);
28880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
28890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
28900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() {
28910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
28920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
28930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemRemoved(2);
28940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
28950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
28960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
28970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
28980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
28990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void adapterChangeDuringScrollTest(String msg, final int orientation,
29000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            final Runnable onScrollRunnable) throws Throwable {
290166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        setIgnoreMainThreadException(true);
29020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestAdapter testAdapter = new TestAdapter(100);
29030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
29040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
29050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
29060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                super.onLayoutChildren(recycler, state);
29070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
29080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutRange(recycler, 0, 10);
29090bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
29100bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
29110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
29120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
29130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
29140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
29160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
29170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public boolean canScrollVertically() {
29180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return orientation == OrientationHelper.VERTICAL;
29190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
29210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
29220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public boolean canScrollHorizontally() {
29230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return orientation == OrientationHelper.HORIZONTAL;
29240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
29260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int mockScroll() {
29270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
29280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    onScrollRunnable.run();
29290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
29300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
29310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
29320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
29330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
29340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return 0;
29350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
29370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
29380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
29390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    RecyclerView.State state) {
29400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return mockScroll();
29410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
29430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
29440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
29450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    RecyclerView.State state) {
29460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return mockScroll();
29470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
29480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        };
29490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
29500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setLayoutManager(lm);
29510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setAdapter(testAdapter);
29520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
29530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        setRecyclerView(recyclerView);
29540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
29550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
29560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        scrollBy(200);
29570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
29580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        removeRecyclerView();
29590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertTrue("Invalid data updates should be caught:" + msg,
296066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar                getMainThreadException() instanceof IllegalStateException);
29610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
29620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2963be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
29640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleOnDetach() throws Throwable {
296549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
296649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
296749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final AtomicBoolean didRunOnDetach = new AtomicBoolean(false);
296849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
296949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            @Override
297049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
297149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                super.onLayoutChildren(recycler, state);
297249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                layoutRange(recycler, 0, state.getItemCount() - 1);
297349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                layoutLatch.countDown();
297449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            }
297549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
297649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            @Override
297749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
297849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                super.onDetachedFromWindow(view, recycler);
297949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                didRunOnDetach.set(true);
298049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                removeAndRecycleAllViews(recycler);
298149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            }
298249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        };
298349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        recyclerView.setAdapter(testAdapter);
298449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        recyclerView.setLayoutManager(lm);
298549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        lm.expectLayouts(1);
298649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        setRecyclerView(recyclerView);
298749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        lm.waitForLayout(2);
298849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        removeRecyclerView();
298949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get());
299049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        assertEquals("All children should be recycled", recyclerView.getChildCount(), 0);
299149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    }
29920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2993be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
29940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updatesWhileDetached() throws Throwable {
2995bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2996bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int initialAdapterSize = 20;
2997bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
2998bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(0);
2999bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
3000bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
3001bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3002bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                super.onLayoutChildren(recycler, state);
3003bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutRange(recycler, 0, 5);
3004bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.incrementAndGet();
3005bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutLatch.countDown();
3006bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
3007bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        };
3008bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setAdapter(adapter);
3009bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setLayoutManager(lm);
3010bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setHasFixedSize(true);
3011bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
3012bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        adapter.addAndNotify(4, 5);
3013bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
3014bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar    }
3015bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar
3016be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
30170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updatesAfterDetach() throws Throwable {
3018bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3019bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int initialAdapterSize = 20;
3020bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
3021bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(0);
3022bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
3023bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
3024bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3025bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                super.onLayoutChildren(recycler, state);
3026bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutRange(recycler, 0, 5);
3027bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.incrementAndGet();
3028bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutLatch.countDown();
3029bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
3030bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        };
3031bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setAdapter(adapter);
3032bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setLayoutManager(lm);
3033bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
3034bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setHasFixedSize(true);
3035bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        setRecyclerView(recyclerView);
3036bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.waitForLayout(2);
3037bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
3038bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int prevLayoutCount = layoutCount.get();
3039bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        runTestOnUiThread(new Runnable() {
3040bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
3041bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void run() {
3042bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                try {
3043bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                    adapter.addAndNotify(4, 5);
3044bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                    removeRecyclerView();
3045bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                } catch (Throwable throwable) {
304690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    postExceptionToInstrumentation(throwable);
3047bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                }
3048bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
3049bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        });
305090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        checkForMainThreadException();
3051bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar
3052bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
3053bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        assertEquals("No extra layout should happen when detached", prevLayoutCount,
3054bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.get());
3055bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar    }
305649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
3057be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
30580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChangedWithStableIds() throws Throwable {
3059e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int defaultViewType = 1;
3060e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final Map<Item, Integer> viewTypeMap = new HashMap<Item, Integer>();
3061e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final Map<Integer, Integer> oldPositionToNewPositionMapping =
3062e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                new HashMap<Integer, Integer>();
3063e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
3064e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
3065e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public int getItemViewType(int position) {
3066e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                Integer type = viewTypeMap.get(mItems.get(position));
3067e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return type == null ? defaultViewType : type;
3068e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
3069e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
3070e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
3071e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public long getItemId(int position) {
3072e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return mItems.get(position).mId;
3073e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
3074e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
3075e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        adapter.setHasStableIds(true);
3076e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final ArrayList<Item> previousItems = new ArrayList<Item>();
3077e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        previousItems.addAll(adapter.mItems);
3078e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
3079e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final AtomicInteger layoutStart = new AtomicInteger(50);
3080e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final AtomicBoolean validate = new AtomicBoolean(false);
3081e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int childCount = 10;
3082e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
3083e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
3084e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3085e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                try {
3086e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    super.onLayoutChildren(recycler, state);
3087e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
3088e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("Cached views should be kept", 5, recycler
3089e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                .mCachedViews.size());
3090e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (RecyclerView.ViewHolder vh : recycler.mCachedViews) {
3091e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) vh;
30920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            assertTrue("view holder should be marked for update",
30930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                                    tvh.needsUpdate());
3094e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
3095e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        }
3096e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
3097e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    detachAndScrapAttachedViews(recycler);
3098e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
3099e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("cache size should stay the same", 5,
3100e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                recycler.mCachedViews.size());
3101e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("all views should be scrapped", childCount,
3102e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                recycler.getScrapList().size());
3103e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
3104e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            // TODO create test case for type change
3105e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) vh;
31060bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            assertTrue("view holder should be marked for update",
31070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                                    tvh.needsUpdate());
3108e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
3109e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        }
3110e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
3111e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
3112e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
3113e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (int i = 0; i < getChildCount(); i++) {
3114e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            View view = getChildAt(i);
3115e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) mRecyclerView
3116e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                    .getChildViewHolder(view);
3117115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            final int oldPos = previousItems.indexOf(tvh.mBoundItem);
3118e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertEquals("view holder's position should be correct",
3119e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                    oldPositionToNewPositionMapping.get(oldPos).intValue(),
3120115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    tvh.getLayoutPosition());
31210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            ;
31220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        }
3123e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
3124e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } catch (Throwable t) {
3125e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    postExceptionToInstrumentation(t);
3126e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } finally {
3127e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    layoutLatch.countDown();
3128e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                }
3129e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
3130e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
3131e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3132e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setItemAnimator(null);
3133e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setAdapter(adapter);
3134e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setLayoutManager(lm);
3135e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setItemViewCacheSize(10);
3136e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
3137e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        setRecyclerView(recyclerView);
3138e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
3139e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
3140e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        getInstrumentation().waitForIdleSync();
3141e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        layoutStart.set(layoutStart.get() + 5);//55
3142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
3143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        requestLayoutOnUIThread(recyclerView);
3144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
3145e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        validate.set(true);
3146e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
3147e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        runTestOnUiThread(new Runnable() {
3148e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
3149e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public void run() {
3150e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                try {
3151e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    adapter.moveItems(false,
3152e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2},
3153e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64},
3154e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{75, 58});
3155e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    for (int i = 0; i < previousItems.size(); i++) {
3156e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        Item item = previousItems.get(i);
3157e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item));
3158e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
3159cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    adapter.dispatchDataSetChanged();
3160e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } catch (Throwable throwable) {
3161e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    postExceptionToInstrumentation(throwable);
3162e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                }
3163e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
3164e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        });
3165e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
3166e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
3167e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
3168e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
3169be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
31700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void callbacksDuringAdapterSwap() throws Throwable {
3171824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        callbacksDuringAdapterChange(true);
3172824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
3173824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3174be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
31750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void callbacksDuringAdapterSet() throws Throwable {
3176824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        callbacksDuringAdapterChange(false);
3177824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
3178824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3179824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    public void callbacksDuringAdapterChange(boolean swap) throws Throwable {
3180824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter()
3181824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                : createOwnerCheckingAdapter();
3182824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter()
3183824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                : createOwnerCheckingAdapter();
3184824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3185824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3186824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3187824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3188824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                try {
3189824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
3190824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                } catch (Throwable t) {
3191824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    postExceptionToInstrumentation(t);
3192824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                }
3193824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                layoutLatch.countDown();
3194824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3195824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
3196824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
3197824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        rv.setAdapter(adapter1);
3198824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        rv.setLayoutManager(tlm);
3199824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.expectLayouts(1);
3200824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        setRecyclerView(rv);
3201824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.waitForLayout(1);
3202824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
3203824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.expectLayouts(1);
3204824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        if (swap) {
3205824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            swapAdapter(adapter2, true);
3206824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        } else {
3207824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            setAdapter(adapter2);
3208824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        }
3209824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
3210824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.waitForLayout(1);
3211824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
3212824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
3213824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3214824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    private TestAdapter2 createOwnerCheckingAdapter() {
3215824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        return new TestAdapter2(10) {
3216824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3217824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onViewRecycled(TestViewHolder2 holder) {
3218824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on recycled should be called w/ the creator adapter", this,
3219824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        holder.mData);
3220824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onViewRecycled(holder);
3221824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3222824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3223824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3224824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onBindViewHolder(TestViewHolder2 holder, int position) {
3225824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onBindViewHolder(holder, position);
3226824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on bind should be called w/ the creator adapter", this, holder.mData);
3227824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3228824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3229824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3230824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
3231824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    int viewType) {
3232824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType);
3233824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                vh.mData = this;
3234824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                return vh;
3235824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3236824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
3237824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
3238824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3239824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    private TestAdapter2 createBinderCheckingAdapter() {
3240824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        return new TestAdapter2(10) {
3241824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3242824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onViewRecycled(TestViewHolder2 holder) {
3243824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on recycled should be called w/ the creator adapter", this,
3244824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        holder.mData);
3245824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                holder.mData = null;
3246824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onViewRecycled(holder);
3247824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3248824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3249824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
3250824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onBindViewHolder(TestViewHolder2 holder, int position) {
3251824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onBindViewHolder(holder, position);
3252824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                holder.mData = this;
3253824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
3254824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
3255824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
3256824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3257be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
32580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findViewById() throws Throwable {
32595ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        findViewByIdTest(false);
32605ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        removeRecyclerView();
32615ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        findViewByIdTest(true);
32625ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    }
32635ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
32645ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    public void findViewByIdTest(final boolean supportPredictive) throws Throwable {
32655ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
32665ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int initialAdapterSize = 20;
32675ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
32685ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int deleteStart = 6;
32695ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int deleteCount = 5;
32705ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        recyclerView.setAdapter(adapter);
32715ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final AtomicBoolean assertPositions = new AtomicBoolean(false);
32725ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
32735ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            @Override
32745ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
32755ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                super.onLayoutChildren(recycler, state);
32765ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                if (assertPositions.get()) {
32775ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    if (state.isPreLayout()) {
32780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < deleteStart; i++) {
32795ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
32805ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull("find view by position for existing items should work "
32815ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    + "fine", view);
32825ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
32835ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
32845ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
32855ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
32860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < deleteCount; i++) {
32875ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i + deleteStart);
32885ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull("find view by position should work fine for removed "
32895ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    + "views in pre-layout", view);
32905ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertTrue("view should be marked as removed",
32915ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
32925ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
32935ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
32945ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        for (int i = deleteStart + deleteCount; i < 20; i++) {
32955ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
32965ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull(view);
32975ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
32985ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
32995ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
33005ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
33015ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    } else {
33020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < initialAdapterSize - deleteCount; i++) {
33035ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
3304fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar                            assertNotNull("find view by position for existing item " + i +
3305fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar                                    " should work fine. child count:" + getChildCount(), view);
33065ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            TestViewHolder viewHolder =
33075ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    (TestViewHolder) mRecyclerView.getChildViewHolder(view);
33085ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertSame("should be the correct item " + viewHolder
3309115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    , viewHolder.mBoundItem,
33105ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    adapter.mItems.get(viewHolder.mPosition));
33115ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
33125ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
33135ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
33145ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
33155ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    }
33165ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                }
33175ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                detachAndScrapAttachedViews(recycler);
33185ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                layoutRange(recycler, state.getItemCount() - 1, -1);
33195ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                layoutLatch.countDown();
33205ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            }
33215ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
33225ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            @Override
33235ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
33245ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                return supportPredictive;
33255ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            }
33265ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        };
33275ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        recyclerView.setLayoutManager(lm);
33285ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.expectLayouts(1);
33295ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        setRecyclerView(recyclerView);
33305ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.waitForLayout(2);
33315ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        getInstrumentation().waitForIdleSync();
33325ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
33335ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        assertPositions.set(true);
33345ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.expectLayouts(supportPredictive ? 2 : 1);
33355ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1});
33365ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.waitForLayout(2);
33375ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    }
33385ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
3339be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
33400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void typeForCache() throws Throwable {
334122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final AtomicInteger viewType = new AtomicInteger(1);
334222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
334322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
334422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public int getItemViewType(int position) {
334522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                return viewType.get();
334622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
334722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
334822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
334922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public long getItemId(int position) {
335022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                return mItems.get(position).mId;
335122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
335222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        };
335322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        adapter.setHasStableIds(true);
335422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final AtomicInteger layoutStart = new AtomicInteger(2);
335522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final int childCount = 10;
335622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
335722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
335822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
335922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                super.onLayoutChildren(recycler, state);
336022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                detachAndScrapAttachedViews(recycler);
336122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
336222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                layoutLatch.countDown();
336322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
336422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        };
336522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3366668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        recyclerView.setItemAnimator(null);
336722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setAdapter(adapter);
336822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setLayoutManager(lm);
336922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setItemViewCacheSize(10);
337022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
337122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        setRecyclerView(recyclerView);
337222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
337322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        getInstrumentation().waitForIdleSync();
337422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        layoutStart.set(4); // trigger a cache for 3,4
337522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
337622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        requestLayoutOnUIThread(recyclerView);
337722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
337822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        //
337922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        viewType.incrementAndGet();
338022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        layoutStart.set(2); // go back to bring views from cache
338122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
338222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        adapter.mItems.remove(1);
3383cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.dispatchDataSetChanged();
338422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
338522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        runTestOnUiThread(new Runnable() {
338622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
338722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public void run() {
338822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                for (int i = 2; i < 4; i++) {
3389115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i);
339022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                    assertEquals("View holder's type should match latest type", viewType.get(),
339122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                            vh.getItemViewType());
339222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                }
339322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
339422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        });
339522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    }
339622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
3397be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
33980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void typeForExistingViews() throws Throwable {
33997e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final AtomicInteger viewType = new AtomicInteger(1);
34007e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int invalidatedCount = 2;
34017e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int layoutStart = 2;
34027e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
34037e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
34047e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public int getItemViewType(int position) {
34057e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                return viewType.get();
34067e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
34077e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
34087e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
34097e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
34107e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    int position) {
34117e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                super.onBindViewHolder(holder, position);
34127e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                if (position >= layoutStart && position < invalidatedCount + layoutStart) {
34137e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    try {
34147e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                        assertEquals("holder type should match current view type at position " +
34157e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                                position, viewType.get(), holder.getItemViewType());
34167e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    } catch (Throwable t) {
34177e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                        postExceptionToInstrumentation(t);
34187e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    }
34197e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                }
34207e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
34217e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
34227e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
34237e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public long getItemId(int position) {
34247e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                return mItems.get(position).mId;
34257e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
34267e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        };
34277e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        adapter.setHasStableIds(true);
34287e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
34297e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int childCount = 10;
34307e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
34317e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
34327e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
34337e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                super.onLayoutChildren(recycler, state);
34347e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                detachAndScrapAttachedViews(recycler);
34357e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                layoutRange(recycler, layoutStart, layoutStart + childCount);
34367e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                layoutLatch.countDown();
34377e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
34387e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        };
34397e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
34407e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        recyclerView.setAdapter(adapter);
34417e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        recyclerView.setLayoutManager(lm);
34427e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.expectLayouts(1);
34437e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        setRecyclerView(recyclerView);
34447e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.waitForLayout(2);
34457e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        getInstrumentation().waitForIdleSync();
34467e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        viewType.incrementAndGet();
34477e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.expectLayouts(1);
3448cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.changeAndNotify(layoutStart, invalidatedCount);
34497e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.waitForLayout(2);
34507e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        checkForMainThreadException();
34517e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar    }
34527e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
34537e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
3454be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
34550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void state() throws Throwable {
3456d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final TestAdapter adapter = new TestAdapter(10);
3457d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final RecyclerView recyclerView = new RecyclerView(getActivity());
3458d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setAdapter(adapter);
3459d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setItemAnimator(null);
3460d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final AtomicInteger itemCount = new AtomicInteger();
3461d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final AtomicBoolean structureChanged = new AtomicBoolean();
3462d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        TestLayoutManager testLayoutManager = new TestLayoutManager() {
3463d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
3464d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
34658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                detachAndScrapAttachedViews(recycler);
3466d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                layoutRange(recycler, 0, state.getItemCount());
3467d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.set(state.getItemCount());
3468d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.set(state.didStructureChange());
3469d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                layoutLatch.countDown();
3470d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
3471d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        };
3472d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setLayoutManager(testLayoutManager);
3473d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        testLayoutManager.expectLayouts(1);
3474d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        runTestOnUiThread(new Runnable() {
3475d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
3476d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void run() {
3477a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar                getActivity().getContainer().addView(recyclerView);
3478d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
3479d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        });
348066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar        testLayoutManager.waitForLayout(2);
3481d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
3482d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("item count in state should be correct", adapter.getItemCount()
3483d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                , itemCount.get());
3484d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true for first layout", true,
3485d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
3486d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        Thread.sleep(1000); //wait for other layouts.
3487d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        testLayoutManager.expectLayouts(1);
3488d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        runTestOnUiThread(new Runnable() {
3489d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
3490d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void run() {
3491d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                recyclerView.requestLayout();
3492d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
3493d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        });
34948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
3495d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("in second layout,structure changed should be false", false,
3496d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
34978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.expectLayouts(1); //
3498b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        adapter.deleteAndNotify(3, 2);
34998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
3500d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("when items are removed, item count in state should be updated",
3501d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adapter.getItemCount(),
3502d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.get());
3503d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true when items are removed", true,
3504d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
35058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.expectLayouts(1);
3506b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        adapter.addAndNotify(2, 5);
35078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
3508d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
3509d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("when items are added, item count in state should be updated",
3510d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adapter.getItemCount(),
3511d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.get());
3512d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true when items are removed", true,
3513d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
35140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
35150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
3516be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
35170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detachWithoutLayoutManager() throws Throwable {
3518abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
3519abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        runTestOnUiThread(new Runnable() {
3520abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            @Override
3521abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            public void run() {
3522abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                try {
3523abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    setRecyclerView(recyclerView);
3524abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    removeRecyclerView();
3525abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                } catch (Throwable t) {
3526abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    postExceptionToInstrumentation(t);
3527abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                }
3528abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            }
3529abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        });
3530abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        checkForMainThreadException();
3531abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
3532abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
3533be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
35340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updateHiddenView() throws Throwable {
35351a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
35361a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final int[] preLayoutRange = new int[]{0, 10};
35371a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final int[] postLayoutRange = new int[]{0, 10};
35381a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final AtomicBoolean enableGetViewTest = new AtomicBoolean(false);
3539959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        final List<Integer> disappearingPositions = new ArrayList<>();
35401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final TestLayoutManager tlm = new TestLayoutManager() {
35411a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
35421a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
35431a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                return true;
35441a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
35451a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
35461a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
35471a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
35481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                try {
35491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    final int[] layoutRange = state.isPreLayout() ? preLayoutRange
35501a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            : postLayoutRange;
35511a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    detachAndScrapAttachedViews(recycler);
35521a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    layoutRange(recycler, layoutRange[0], layoutRange[1]);
35531a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    if (!state.isPreLayout()) {
35541a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                        for (Integer position : disappearingPositions) {
35551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            // test sanity.
35561a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            assertNull(findViewByPosition(position));
35571a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            final View view = recycler.getViewForPosition(position);
3558959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                            assertNotNull(view);
35591a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            addDisappearingView(view);
35601a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            measureChildWithMargins(view, 0, 0);
35611a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            // position item out of bounds.
35621a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            view.layout(0, -500, view.getMeasuredWidth(),
35631a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                                    -500 + view.getMeasuredHeight());
35641a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                        }
35651a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    }
35661a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                } catch (Throwable t) {
35671a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    postExceptionToInstrumentation(t);
35681a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                }
35691a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                layoutLatch.countDown();
35701a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
35711a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        };
3572959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        recyclerView.getItemAnimator().setMoveDuration(4000);
3573959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        recyclerView.getItemAnimator().setRemoveDuration(4000);
35741a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final TestAdapter adapter = new TestAdapter(100);
35751a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.setAdapter(adapter);
35761a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.setLayoutManager(tlm);
35771a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(1);
35781a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        setRecyclerView(recyclerView);
35791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(1);
35801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
35811a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // now, a child disappears
35821a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        disappearingPositions.add(0);
35831a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // layout one shifted
35841a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        postLayoutRange[0] = 1;
35851a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        postLayoutRange[1] = 11;
35861a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(2);
35871a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        adapter.addAndNotify(8, 1);
35881a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(2);
35891a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
35901a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
35911a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(2);
35921a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        disappearingPositions.clear();
35931a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // now that item should be moving, invalidate it and delete it.
35941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        enableGetViewTest.set(true);
35951a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        runTestOnUiThread(new Runnable() {
35961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
35971a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public void run() {
35981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                try {
3599959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                    assertThat("test sanity, should still be animating",
3600959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                            mRecyclerView.isAnimating(), CoreMatchers.is(true));
36011a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    adapter.changeAndNotify(0, 1);
36021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    adapter.deleteAndNotify(0, 1);
36031a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                } catch (Throwable throwable) {
3604959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar                    fail(throwable.getMessage());
36051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                }
36061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
36071a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        });
36081a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(2);
36091a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
36101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar    }
36111a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
3612be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnTop() throws Throwable {
36146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.TOP);
36156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3617be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnLeft() throws Throwable {
36196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.LEFT);
36206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3622be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnRight() throws Throwable {
36246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.RIGHT);
36256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3627be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnBottom() throws Throwable {
36296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.BOTTOM);
36306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3632be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnLeftRTL() throws Throwable {
36346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.LEFT, true);
36356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
36366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                mRecyclerView.getLayoutManager().getLayoutDirection());
36376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3639be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
36400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnRightRTL() throws Throwable {
36416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.RIGHT, true);
36426d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
36436d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                mRecyclerView.getLayoutManager().getLayoutDirection());
36446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
36456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
36466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    public void focusTooBigViewTest(final int gravity) throws Throwable {
36476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(gravity, false);
36486d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
3649be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
36506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable {
36516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
36526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        if (rtl) {
36536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL);
36546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        }
36556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger vScrollDist = new AtomicInteger(0);
36566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger hScrollDist = new AtomicInteger(0);
36576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger vDesiredDist = new AtomicInteger(0);
36586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger hDesiredDist = new AtomicInteger(0);
36596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
36606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
36616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
36626d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int getLayoutDirection() {
36636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
36646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
36656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
36666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
36676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
36686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                detachAndScrapAttachedViews(recycler);
36696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                final View view = recycler.getViewForPosition(0);
36706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                addView(view);
36716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                int left = 0, top = 0;
36726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                view.setBackgroundColor(Color.rgb(0, 0, 255));
36736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                switch (gravity) {
36746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.LEFT:
36756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.RIGHT:
36766d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        view.measure(
36776d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5),
36786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.EXACTLY),
36796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9),
36806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.AT_MOST));
36816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80
36826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                : 90;
36836d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top = 0;
36846d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) {
36856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                            hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth());
36866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        } else {
36876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                            hDesiredDist.set(left);
36886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        }
36896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        break;
36906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.TOP:
36916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.BOTTOM:
36926d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        view.measure(
36936d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9),
36946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.AT_MOST),
36956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5),
36966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.EXACTLY));
36976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() -
36986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                80 : 90;
36996d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        left = 0;
37006d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        vDesiredDist.set(top);
37016d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        break;
37026d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                }
37036d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
37046d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                view.layout(left, top, left + view.getMeasuredWidth(),
37056d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top + view.getMeasuredHeight());
37066d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                layoutLatch.countDown();
37076d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
37086d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
37096d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
37106d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public boolean canScrollVertically() {
37116d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return true;
37126d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
37136d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
37146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
37156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public boolean canScrollHorizontally() {
37166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return super.canScrollHorizontally();
37176d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
37186d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
37196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
37206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
37216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    RecyclerView.State state) {
37226d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                vScrollDist.addAndGet(dy);
37236d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                getChildAt(0).offsetTopAndBottom(-dy);
37246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return dy;
37256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
37266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
37276d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
37286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
37296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    RecyclerView.State state) {
37306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                hScrollDist.addAndGet(dx);
37316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                getChildAt(0).offsetLeftAndRight(-dx);
37326d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return dx;
37336d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
37346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        };
37356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
37366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        rv.setAdapter(adapter);
37376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        rv.setLayoutManager(tlm);
37386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        tlm.expectLayouts(1);
37396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        setRecyclerView(rv);
37406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        tlm.waitForLayout(2);
37416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        View view = rv.getChildAt(0);
3742959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertTrue("test sanity", requestFocus(view, true));
3743959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        assertTrue("test sanity", view.hasFocus());
37446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(vDesiredDist.get(), vScrollDist.get());
37456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(hDesiredDist.get(), hScrollDist.get());
37466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(mRecyclerView.getPaddingTop(), view.getTop());
37476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        if (rtl) {
3748be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar            assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
3749be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar                    view.getRight());
37506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        } else {
37516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft());
37526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        }
37536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
37546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
3755be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
37560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void firstLayoutWithAdapterChanges() throws Throwable {
37574bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        final TestAdapter adapter = new TestAdapter(0);
37584bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
37594bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        setVisibility(rv, View.GONE);
37604bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
37614bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
37624bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
37634bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                try {
37644bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    super.onLayoutChildren(recycler, state);
37654bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
37664bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } catch (Throwable t) {
37674bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    postExceptionToInstrumentation(t);
37684bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } finally {
37694bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    layoutLatch.countDown();
37704bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                }
37714bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
37724bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar
37734bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
37744bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public boolean supportsPredictiveItemAnimations() {
37754bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                return true;
37764bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
37774bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        };
37784bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setLayoutManager(tlm);
37794bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setAdapter(adapter);
37804bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setHasFixedSize(true);
37814bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        setRecyclerView(rv);
37824bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.expectLayouts(1);
37834bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.assertNoLayout("test sanity, layout should not run", 1);
37844bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        getInstrumentation().waitForIdleSync();
37854bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        runTestOnUiThread(new Runnable() {
37864bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
37874bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public void run() {
37884bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                try {
37894bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    adapter.addAndNotify(2);
37904bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } catch (Throwable throwable) {
37914bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    throwable.printStackTrace();
37924bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                }
37934bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                rv.setVisibility(View.VISIBLE);
37944bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
37954bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        });
37964bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        checkForMainThreadException();
37974bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.waitForLayout(2);
37984bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        assertEquals(2, rv.getChildCount());
37994bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        checkForMainThreadException();
38004bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar    }
38014bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar
38024bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar    @Test
380314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    public void computeScrollOfsetWithoutLayoutManager() throws Throwable {
380414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
380514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        rv.setAdapter(new TestAdapter(10));
380614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        setRecyclerView(rv);
380714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollExtent());
380814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollOffset());
380914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollRange());
381014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
381114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollExtent());
381214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollOffset());
381314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollRange());
381414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    }
381514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
381614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    @Test
381714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    public void computeScrollOfsetWithoutAdapter() throws Throwable {
381814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
381914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        rv.setLayoutManager(new TestLayoutManager());
382014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        setRecyclerView(rv);
382114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollExtent());
382214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollOffset());
382314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollRange());
382414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
382514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollExtent());
382614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollOffset());
382714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollRange());
382814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    }
382914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
383014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    @Test
38310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusRectOnScreenWithDecorOffsets() throws Throwable {
3832f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        focusRectOnScreenTest(true);
3833f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3834f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3835be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
38360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusRectOnScreenWithout() throws Throwable {
3837f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        focusRectOnScreenTest(false);
3838f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3839f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3840f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable {
3841f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
3842f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        final AtomicInteger scrollDist = new AtomicInteger(0);
3843f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3844f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3845f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3846f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                detachAndScrapAttachedViews(recycler);
3847f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                final View view = recycler.getViewForPosition(0);
3848f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                addView(view);
3849f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                measureChildWithMargins(view, 0, 0);
3850f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                view.layout(0, -20, view.getWidth(),
3851f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                        -20 + view.getHeight());// ignore decors on purpose
3852f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                layoutLatch.countDown();
3853f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3854f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3855f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3856f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public boolean canScrollVertically() {
3857f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                return true;
3858f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3859f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3860f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3861f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
3862f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                    RecyclerView.State state) {
3863f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                scrollDist.addAndGet(dy);
3864f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                return dy;
3865f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3866f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        };
3867f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
3868f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        if (addItemDecors) {
3869f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
3870f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                @Override
3871f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
3872f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                        RecyclerView.State state) {
3873f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                    outRect.set(0, 10, 0, 10);
3874f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                }
3875f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            });
3876f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        }
3877f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        rv.setAdapter(adapter);
3878f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        rv.setLayoutManager(tlm);
3879f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        tlm.expectLayouts(1);
3880f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        setRecyclerView(rv);
3881f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        tlm.waitForLayout(2);
3882f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3883f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        View view = rv.getChildAt(0);
3884959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        requestFocus(view, true);
3885f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        assertEquals(addItemDecors ? -30 : -20, scrollDist.get());
3886f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3887f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3888e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
38890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void unimplementedSmoothScroll() throws Throwable {
3890e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1);
3891e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1);
3892e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final CountDownLatch cbLatch = new CountDownLatch(2);
3893e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3894e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3895e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3896e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                detachAndScrapAttachedViews(recycler);
3897e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutRange(recycler, 0, 10);
3898e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutLatch.countDown();
3899e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3900e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3901e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3902e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
3903e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    int position) {
3904e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                assertEquals(-1, receivedSmoothScrollToPosition.get());
3905e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedSmoothScrollToPosition.set(position);
3906e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                RecyclerView.SmoothScroller ss =
3907e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
3908e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
3909e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
3910e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                return null;
3911e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
3912e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        };
3913e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                ss.setTargetPosition(position);
3914e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                startSmoothScroll(ss);
3915e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                cbLatch.countDown();
3916e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3917e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3918e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3919e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void scrollToPosition(int position) {
3920e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                assertEquals(-1, receivedScrollToPosition.get());
3921e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedScrollToPosition.set(position);
3922e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                cbLatch.countDown();
3923e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3924e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        };
3925e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
3926e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setAdapter(new TestAdapter(100));
3927e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setLayoutManager(tlm);
3928e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.expectLayouts(1);
3929e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        setRecyclerView(rv);
3930e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.waitForLayout(2);
3931ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
3932959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        smoothScrollToPosition(35, false);
3933ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("smoothScrollToPosition should be ignored when frozen",
3934ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                -1, receivedSmoothScrollToPosition.get());
3935ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
3936959f4c0fac89425a8a9842e82fc180ec736fffacYigit Boyar        smoothScrollToPosition(35, false);
3937e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS));
3938e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        checkForMainThreadException();
3939e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(35, receivedSmoothScrollToPosition.get());
3940e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(35, receivedScrollToPosition.get());
3941e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3942e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3943e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
39440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void jumpingJackSmoothScroller() throws Throwable {
3945e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        jumpingJackSmoothScrollerTest(true);
3946e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3947e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3948e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
39490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void jumpingJackSmoothScrollerGoesIdle() throws Throwable {
3950e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        jumpingJackSmoothScrollerTest(false);
3951e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3952e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
39537f5e94985f795f81884334ca2752a0469a998762Yigit Boyar    @Test
39547f5e94985f795f81884334ca2752a0469a998762Yigit Boyar    public void testScrollByBeforeFirstLayout() throws Throwable {
39557f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
39567f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
39577f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        recyclerView.setLayoutManager(new TestLayoutManager() {
39587f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            AtomicBoolean didLayout = new AtomicBoolean(false);
39597f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            @Override
39607f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
39617f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                super.onLayoutChildren(recycler, state);
39627f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                didLayout.set(true);
39637f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            }
39647f5e94985f795f81884334ca2752a0469a998762Yigit Boyar
39657f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            @Override
39667f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
39677f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                    RecyclerView.State state) {
39687f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                assertThat("should run layout before scroll",
39697f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                        didLayout.get(), CoreMatchers.is(true));
39707f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                return super.scrollVerticallyBy(dy, recycler, state);
39717f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            }
39727f5e94985f795f81884334ca2752a0469a998762Yigit Boyar
39737f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            @Override
39747f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            public boolean canScrollVertically() {
39757f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                return true;
39767f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            }
39777f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        });
39787f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        recyclerView.setAdapter(adapter);
39797f5e94985f795f81884334ca2752a0469a998762Yigit Boyar
39807f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        runTestOnUiThread(new Runnable() {
39817f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            @Override
39827f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            public void run() {
39837f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                try {
39847f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                    setRecyclerView(recyclerView);
39857f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                    recyclerView.scrollBy(10, 19);
39867f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                } catch (Throwable throwable) {
39877f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                    postExceptionToInstrumentation(throwable);
39887f5e94985f795f81884334ca2752a0469a998762Yigit Boyar                }
39897f5e94985f795f81884334ca2752a0469a998762Yigit Boyar            }
39907f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        });
39917f5e94985f795f81884334ca2752a0469a998762Yigit Boyar
39927f5e94985f795f81884334ca2752a0469a998762Yigit Boyar        checkForMainThreadException();
39937f5e94985f795f81884334ca2752a0469a998762Yigit Boyar    }
39947f5e94985f795f81884334ca2752a0469a998762Yigit Boyar
3995e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable {
3996e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final List<Integer> receivedScrollToPositions = new ArrayList<>();
3997e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final TestAdapter testAdapter = new TestAdapter(200);
3998e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicBoolean mTargetFound = new AtomicBoolean(false);
3999e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
4000e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            int pendingScrollPosition = -1;
4001e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
4002e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
4003e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                detachAndScrapAttachedViews(recycler);
4004e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition;
4005e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutRange(recycler, pos, pos + 10);
4006e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                if (layoutLatch != null) {
4007e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    layoutLatch.countDown();
4008e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                }
4009e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
4010e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4011e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
4012e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
4013e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    final int position) {
4014e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                RecyclerView.SmoothScroller ss =
4015e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
4016e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
4017e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
4018e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                return new PointF(0, 1);
4019e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
4020e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4021e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
4022e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            protected void onTargetFound(View targetView, RecyclerView.State state,
4023e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                         Action action) {
4024e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                super.onTargetFound(targetView, state, action);
4025e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                mTargetFound.set(true);
4026e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
4027e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4028e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
4029e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            protected void updateActionForInterimTarget(Action action) {
4030e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                int limit = succeed ? getTargetPosition() : 100;
4031e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                if (pendingScrollPosition + 2 < limit) {
4032e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    if (pendingScrollPosition != NO_POSITION) {
4033e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                        assertEquals(pendingScrollPosition,
4034e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                getChildViewHolderInt(getChildAt(0))
4035e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                        .getAdapterPosition());
4036e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    }
4037e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    action.jumpTo(pendingScrollPosition + 2);
4038e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                }
4039e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
4040e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        };
4041e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                ss.setTargetPosition(position);
4042e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                startSmoothScroll(ss);
4043e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
4044e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4045e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
4046e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void scrollToPosition(int position) {
4047e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedScrollToPositions.add(position);
4048e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                pendingScrollPosition = position;
4049e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                requestLayout();
4050e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
4051e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        };
4052e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
4053e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setAdapter(testAdapter);
4054e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setLayoutManager(tlm);
4055e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4056e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.expectLayouts(1);
4057e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        setRecyclerView(rv);
4058e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.waitForLayout(2);
4059e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4060e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        runTestOnUiThread(new Runnable() {
4061e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
4062e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void run() {
4063e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                rv.smoothScrollToPosition(150);
4064e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
4065e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        });
4066e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        int limit = 100;
4067e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) {
4068e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            Thread.sleep(200);
4069e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            checkForMainThreadException();
4070e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        }
4071e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        checkForMainThreadException();
4072e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertTrue(limit > 0);
4073e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        for (int i = 1; i < 100; i+=2) {
4074e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i));
4075e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        }
4076e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4077e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(succeed, mTargetFound.get());
4078e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
4079e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
4080e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
40810b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private static class TestViewHolder2 extends RecyclerView.ViewHolder {
4082824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
4083824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        Object mData;
4084824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
40850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public TestViewHolder2(View itemView) {
40860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            super(itemView);
40870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
40880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
4089d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
40900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> {
4091824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
40920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        List<Item> mItems;
40930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
40940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        private TestAdapter2(int count) {
40950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            mItems = new ArrayList<Item>(count);
40960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            for (int i = 0; i < count; i++) {
40970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                mItems.add(new Item(i, "Item " + i));
40980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
40990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
41000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
41010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
41020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
41030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                int viewType) {
41040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            return new TestViewHolder2(new TextView(parent.getContext()));
41050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
41060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
41070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
41080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public void onBindViewHolder(TestViewHolder2 holder, int position) {
41090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            final Item item = mItems.get(position);
41100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")");
41110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
41120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
41130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
41140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public int getItemCount() {
41150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            return mItems.size();
41160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
4117d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
4118d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
4119e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar    public interface AdapterRunnable {
41201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
41213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        void run(TestAdapter adapter) throws Throwable;
4122115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
4123115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
41243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    public class LayoutAllLayoutManager extends TestLayoutManager {
41253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        @Override
41263d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
41273e61562902afe237012a2d01ac0468d6b70268f4Yigit Boyar            detachAndScrapAttachedViews(recycler);
41283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            layoutRange(recycler, 0, state.getItemCount());
41293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            layoutLatch.countDown();
41303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        }
41313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    }
4132bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4133bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    /**
4134bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar     * Proxy class to make protected methods public
4135bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar     */
4136bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    public static class TestRecyclerView extends RecyclerView {
4137bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4138bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        public TestRecyclerView(Context context) {
4139bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            super(context);
4140bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
4141bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4142bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        public TestRecyclerView(Context context, @Nullable AttributeSet attrs) {
4143bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            super(context, attrs);
4144bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
4145bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4146bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        public TestRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
4147bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            super(context, attrs, defStyle);
4148bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
4149bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4150bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        @Override
4151bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        public void detachViewFromParent(int index) {
4152bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            super.detachViewFromParent(index);
4153bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
4154bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar
4155bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        @Override
4156bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        public void attachViewToParent(View child, int index, ViewGroup.LayoutParams params) {
4157bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar            super.attachViewToParent(child, index, params);
4158bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar        }
4159bd1424dffe99916b724feef9fec6d40639c6b779Yigit Boyar    }
41604510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar
41614510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    private static interface ViewRunnable {
41624510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar        void run(View view) throws RuntimeException;
41634510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar    }
41647a59e4b36500bcfddd842376d6c3abe0d9f23d84Yigit Boyar}
4165