RecyclerViewLayoutTest.java revision 3d37afbbf7bf547c1e1c541df9be9696da668884
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;
21be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.After;
22be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Before;
23be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.Test;
24be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport org.junit.runner.RunWith;
253d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport org.mockito.Mockito;
26be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
27be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyarimport android.support.test.InstrumentationRegistry;
286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyarimport android.graphics.Color;
29ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.graphics.PointF;
30f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyarimport android.graphics.Rect;
31bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.os.SystemClock;
324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.InstrumentationRegistry;
334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
34ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.support.v4.view.ViewCompat;
350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.v7.util.TouchUtils;
36f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest;
37ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport android.util.Log;
38670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyarimport android.view.Gravity;
39bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.MotionEvent;
405ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyarimport android.view.View;
41bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport android.view.ViewConfiguration;
420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.view.ViewGroup;
434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyarimport android.view.ViewTreeObserver;
440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport android.widget.TextView;
455ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
46e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.ArrayList;
47e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.HashMap;
480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyarimport java.util.List;
49e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyarimport java.util.Map;
50ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyarimport java.util.concurrent.CountDownLatch;
51d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit;
52d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicBoolean;
53d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.atomic.AtomicInteger;
54824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
55e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION;
56bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
58bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyarimport static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
59e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyarimport static android.support.v7.widget.RecyclerView.getChildViewHolderInt;
600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*;
613d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyarimport static org.mockito.Mockito.*;
62be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
63be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar@RunWith(AndroidJUnit4.class)
64f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest
65d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest {
66cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_HORIZONTAL = 1;
67cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_VERTICAL = 1 << 1;
68cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private static final int FLAG_FLING = 1 << 2;
69d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
707bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar    private static final boolean DEBUG = false;
7122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
72ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    private static final String TAG = "RecyclerViewLayoutTest";
73ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
7422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    public RecyclerViewLayoutTest() {
7522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        super(DEBUG);
7622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    }
77bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
78be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingFrozen() throws Throwable {
80ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        testScrollFrozen(true);
81ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
82ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
83ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragFrozen() throws Throwable {
85ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        testScrollFrozen(false);
86ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
87ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
883d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    @Test
893d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    public void requestRectOnScreenWithScrollOffset() throws Throwable {
903d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
913d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager());
923d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final int scrollY = 50;
933d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
943d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
953d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
963d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                View view = new View(parent.getContext());
973d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                view.setScrollY(scrollY);
983d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                return new RecyclerView.ViewHolder(view) {
993d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                };
1003d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
1013d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
1023d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
1033d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
1043d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public int getItemCount() {
1053d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                return 1;
1063d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
1073d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        };
1083d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        recyclerView.setAdapter(adapter);
1093d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        recyclerView.setLayoutManager(tlm);
1103d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        tlm.expectLayouts(1);
1113d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        setRecyclerView(recyclerView);
1123d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        tlm.waitForLayout(1);
1133d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        final View child = recyclerView.getChildAt(0);
1143d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        assertThat(child.getScrollY(), CoreMatchers.is(scrollY));
1153d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        runTestOnUiThread(new Runnable() {
1163d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            @Override
1173d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            public void run() {
1183d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true);
1193d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class),
1203d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar                        any(RecyclerView.State.class));
1213d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            }
1223d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        });
1233d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    }
1243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar
125ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    private void testScrollFrozen(boolean fling) throws Throwable {
126ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
127ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
128ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int horizontalScrollCount = 3;
129ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int verticalScrollCount = 3;
130ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int horizontalVelocity = 1000;
131ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final int verticalVelocity = 1000;
132ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
133ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
134ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
135ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
136ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
137ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
138ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
139ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
140ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
141ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
142ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
143ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
144ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
145ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
146ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
147ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
148ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
149ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
150ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
151ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
152ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
153ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
154ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                if (verticalCounter.get() > 0) {
155ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    verticalCounter.decrementAndGet();
156ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    return dy;
157ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                }
158ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return 0;
159ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
160ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
161ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
162ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
163ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
164ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                if (horizontalCounter.get() > 0) {
165ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    horizontalCounter.decrementAndGet();
166ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    return dx;
167ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                }
168ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return 0;
169ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
170ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
171ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
172ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
173ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
174ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
175ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
176ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
177ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
178ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
179ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
180ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        if (fling) {
181ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity));
182ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        } else { // drag
1830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
184ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    Gravity.LEFT | Gravity.TOP,
185ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
186ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        }
187ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount,
188ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                horizontalCounter.get());
189ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's vertical scroll cb must not run", verticalScrollCount,
190ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                verticalCounter.get());
191ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
192ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
193ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
194ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        if (fling) {
195ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity));
196ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        } else { // drag
1970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
198ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    Gravity.LEFT | Gravity.TOP,
199ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
200ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        }
201ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get());
202ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get());
203ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
204ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
205ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
2067bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar    public void  testFocusSearchFailFrozen() throws Throwable {
207ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
2087bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar        final CountDownLatch focusLatch = new CountDownLatch(1);
209ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
210ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
211ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
212ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
213ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
214ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
215ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
216ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
217ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
218ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
219ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
220ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
221ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
222ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
223ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
224ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
225ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
226ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
227ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
228121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar            public View onFocusSearchFailed(View focused, int direction,
229121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    RecyclerView.Recycler recycler, RecyclerView.State state) {
230ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                focusSearchCalled.addAndGet(1);
2317bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar                focusLatch.countDown();
232ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return null;
233ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
234ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
235ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
236ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
237ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
238ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
239ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
240ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
241ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
242ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
243ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        runTestOnUiThread(new Runnable() {
244ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
245ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void run() {
246ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                c.requestFocus();
247ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
248ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        });
249ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertTrue(c.hasFocus());
250ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
2514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        focusSearch(recyclerView, c, View.FOCUS_DOWN);
252ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("onFocusSearchFailed should not be called when layout is frozen",
253ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                0, focusSearchCalled.get());
254ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
2554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        focusSearch(recyclerView, c, View.FOCUS_DOWN);
2567bb9b2507dc5ed5fa2609d6b8ecf7d274f7bb619Yigit Boyar        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
257ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals(1, focusSearchCalled.get());
258ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
259ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
2604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void focusSearch(final ViewGroup parent, final View focused, final int direction)
2614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            throws Throwable {
2624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        runTestOnUiThread(new Runnable() {
2634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            @Override
2644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            public void run() {
2654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                parent.focusSearch(focused, direction);
2664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
2674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        });
2684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
2694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
270ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
2710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void frozenAndChangeAdapter() throws Throwable {
272ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        RecyclerView recyclerView = new RecyclerView(getActivity());
273ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
274ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
275ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestLayoutManager tlm = new TestLayoutManager() {
276ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
277ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollHorizontally() {
278ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
279ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
280ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
281ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
282ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public boolean canScrollVertically() {
283ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return true;
284ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
285ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
286ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
287ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
288ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutRange(recycler, 0, 10);
289ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                layoutLatch.countDown();
290ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
291ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
292ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            @Override
293ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
294ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                    RecyclerView.State state) {
295ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                focusSearchCalled.addAndGet(1);
296ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                return null;
297ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu            }
298ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        };
299ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter = new TestAdapter(100);
300ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setAdapter(adapter);
301ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        recyclerView.setLayoutManager(tlm);
302ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.expectLayouts(1);
303ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setRecyclerView(recyclerView);
304ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.waitForLayout(2);
305ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
306ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
307ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter2 = new TestAdapter(1000);
308ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        setAdapter(adapter2);
309ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertFalse(recyclerView.isLayoutFrozen());
310ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertSame(adapter2, recyclerView.getAdapter());
311ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
312ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
313ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        TestAdapter adapter3 = new TestAdapter(1000);
314ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        swapAdapter(adapter3, true);
315ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertFalse(recyclerView.isLayoutFrozen());
316ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertSame(adapter3, recyclerView.getAdapter());
317ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    }
318ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu
319ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu    @Test
3200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollToPositionCallback() throws Throwable {
3214965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
3224965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3234965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            int scrollPos = RecyclerView.NO_POSITION;
3241a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
3254965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
3264965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3274965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                layoutLatch.countDown();
3284965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                if (scrollPos == RecyclerView.NO_POSITION) {
3294965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    layoutRange(recycler, 0, 10);
3304965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                } else {
3314965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    layoutRange(recycler, scrollPos, scrollPos + 10);
3324965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                }
3334965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
3341a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
3354965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
3364965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void scrollToPosition(int position) {
3374965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                scrollPos = position;
3384965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                requestLayout();
3394965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
3404965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        };
3414965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setLayoutManager(tlm);
3424965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        TestAdapter adapter = new TestAdapter(100);
3434965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setAdapter(adapter);
3444965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        final AtomicInteger rvCounter = new AtomicInteger(0);
3454965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        final AtomicInteger viewGroupCounter = new AtomicInteger(0);
3464965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.getViewTreeObserver().addOnScrollChangedListener(
3474965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                new ViewTreeObserver.OnScrollChangedListener() {
3484965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    @Override
3494965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    public void onScrollChanged() {
3504965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                        viewGroupCounter.incrementAndGet();
3514965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                    }
3524965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                });
3534965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
3544965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            @Override
3554965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
3564965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                rvCounter.incrementAndGet();
3574965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                super.onScrolled(recyclerView, dx, dy);
3584965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar            }
3594965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        });
3604965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
3613f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar
3624965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        setRecyclerView(recyclerView);
3634965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
3643f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        // wait for draw :/
3653f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        Thread.sleep(1000);
3663f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar
3673f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get());
3683f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("VTO on scroll should be called for initialization", 1,
3694965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar                viewGroupCounter.get());
3704965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
371ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
372ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        scrollToPosition(3);
373ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        tlm.assertNoLayout("scrollToPosition should be ignored", 2);
374ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
3754965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        scrollToPosition(3);
3764965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
3773f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("RV on scroll should be called", 2, rvCounter.get());
3783f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get());
3794965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.expectLayouts(1);
3804965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        requestLayoutOnUIThread(recyclerView);
3814965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        tlm.waitForLayout(2);
3823f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        // wait for draw :/
3833f937299abacc5ff1be7a5ffa91793396aca0a57Yigit Boyar        Thread.sleep(1000);
3844965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        assertEquals("on scroll should NOT be called", 2, rvCounter.get());
3854965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar        assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get());
3864965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar
3874965046abec63014d2a5e7f72f6c9e11b73a4907Yigit Boyar    }
388670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
389be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
3900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionEqual() throws Throwable {
391670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 3, 1000, 1000);
392670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
393670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
394be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
3950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreVertical() throws Throwable {
396670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(2, 3, 1000, 1000);
397670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
398670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
399be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreHorizontal() throws Throwable {
401670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 2, 1000, 1000);
402670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
403670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
404be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollHorizontalOnly() throws Throwable {
406670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 0, 1000, 0);
407670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
408670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
409be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollVerticalOnly() throws Throwable {
411670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(0, 3, 0, 1000);
412670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
413670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
414be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionEqualReverse() throws Throwable {
416670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 3, -1000, -1000);
417670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
418670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
419be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreVerticalReverse() throws Throwable {
421670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(2, 3, -1000, -1000);
422670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
423670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
424be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable {
426670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 2, -1000, -1000);
427670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
428670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
429be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollHorizontalOnlyReverse() throws Throwable {
431670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(3, 0, -1000, 0);
432670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
433670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
434be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollVerticalOnlyReverse() throws Throwable {
436670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        scrollInBothDirection(0, 3, 0, -1000);
437670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
438670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
439670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount,
440670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            int horizontalVelocity, int verticalVelocity)
441670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            throws Throwable {
442670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
443670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
444670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
445670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
446670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
447670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollHorizontally() {
448670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return true;
449670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
450670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
451670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
452670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollVertically() {
453670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return true;
454670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
455670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
456670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
457670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
458670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutRange(recycler, 0, 10);
459670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutLatch.countDown();
460670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
461670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
462670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
463670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
464670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
465670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                if (verticalCounter.get() > 0) {
466670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    verticalCounter.decrementAndGet();
467670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    return dy;
468670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                }
469670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return 0;
470670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
471670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
472670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
473670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
474670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
475670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                if (horizontalCounter.get() > 0) {
476670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    horizontalCounter.decrementAndGet();
477670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    return dx;
478670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                }
479670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                return 0;
480670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
481670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        };
482670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestAdapter adapter = new TestAdapter(100);
483670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setAdapter(adapter);
484670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setLayoutManager(tlm);
485670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.expectLayouts(1);
486670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        setRecyclerView(recyclerView);
487670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.waitForLayout(2);
488670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity));
489670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0,
490670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                horizontalCounter.get());
491670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0,
492670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                verticalCounter.get());
493670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
494670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
495be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
4960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragHorizontal() throws Throwable {
497cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL);
498670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
499670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
500be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void dragVertical() throws Throwable {
502cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL);
503670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
504670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
505be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingHorizontal() throws Throwable {
507cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING);
508670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
509670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
510be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
5110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void flingVertical() throws Throwable {
512cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING);
513670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
514670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
515f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    @Test
5160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragVertical() throws Throwable {
517f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        TestedFrameLayout tfl = getActivity().mContainer;
518f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
519f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
520cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
521f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
522f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
523f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    @Test
5240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragHorizontal() throws Throwable {
525f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        TestedFrameLayout tfl = getActivity().mContainer;
526f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
527f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
528cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
529f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
530670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
531d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    @Test
5320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragHorizontalCallsStopNestedScroll() throws Throwable {
533d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        TestedFrameLayout tfl = getActivity().mContainer;
534d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
535d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
536d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
537d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled());
538d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    }
539d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
540d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    @Test
5410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void nestedDragVerticalCallsStopNestedScroll() throws Throwable {
542d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        TestedFrameLayout tfl = getActivity().mContainer;
543d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedScrollMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
544d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        tfl.setNestedFlingMode(TestedFrameLayout.TEST_NESTED_SCROLL_MODE_CONSUME);
545d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
546d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes        assertTrue("onStopNestedScroll called", tfl.stopNestedScrollCalled());
547d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes    }
548d4c72f08279df548fbc4d556fe1a8b3500fafdbcChris Banes
549cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private void scrollInOtherOrientationTest(int flags)
550f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes            throws Throwable {
551364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar        scrollInOtherOrientationTest(flags, flags);
552f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes    }
553f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
554cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable {
555670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
556670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false);
557670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean scrolledVertical = new AtomicBoolean(false);
558f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes
559f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        final TestLayoutManager tlm = new TestLayoutManager() {
560670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
561670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollHorizontally() {
562cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                return (flags & FLAG_HORIZONTAL) != 0;
563670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
564670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
565670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
566670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public boolean canScrollVertically() {
567cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                return (flags & FLAG_VERTICAL) != 0;
568670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
569670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
570670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
571670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
572670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutRange(recycler, 0, 10);
573670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                layoutLatch.countDown();
574670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
575670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
576670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
577670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
578670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
579670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                scrolledVertical.set(true);
580f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes                return super.scrollVerticallyBy(dy, recycler, state);
581670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
582670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
583670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
584670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
585670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                    RecyclerView.State state) {
586670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                scrolledHorizontal.set(true);
587f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes                return super.scrollHorizontallyBy(dx, recycler, state);
588670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
589670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        };
590670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        TestAdapter adapter = new TestAdapter(100);
591670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setAdapter(adapter);
592670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        recyclerView.setLayoutManager(tlm);
593670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.expectLayouts(1);
594670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        setRecyclerView(recyclerView);
595670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        tlm.waitForLayout(2);
596cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        if ( (flags & FLAG_FLING) != 0 ) {
597cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar            int flingVelocity = (mRecyclerView.getMaxFlingVelocity() +
598cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    mRecyclerView.getMinFlingVelocity()) / 2;
599cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar            assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0,
600cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    fling(flingVelocity, flingVelocity));
601f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        } else { // drag
6020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar            TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP,
603cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
604670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        }
605f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount,
606cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get());
607f129f1b050d2542a91fe8175eac30183beb07b41Chris Banes        assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount,
608cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar                (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get());
609670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
610670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
611670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    private boolean fling(final int velocityX, final int velocityY) throws Throwable {
612670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        final AtomicBoolean didStart = new AtomicBoolean(false);
613670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        runTestOnUiThread(new Runnable() {
614670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            @Override
615670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            public void run() {
616670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                boolean result = mRecyclerView.fling(velocityX, velocityY);
617670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar                didStart.set(result);
618670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            }
619670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        });
620670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        if (!didStart.get()) {
621670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            return false;
622670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        }
623670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        // cannot set scroll listener in case it is subject to some test so instead doing a busy
624670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        // loop until state goes idle
625670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        while (mRecyclerView.getScrollState() != SCROLL_STATE_IDLE) {
626670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar            getInstrumentation().waitForIdleSync();
627670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        }
628670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar        return true;
629670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar    }
630670a72b9301fa53a763344036e4d3ff1995f36dfYigit Boyar
631da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    private void assertPendingUpdatesAndLayout(TestLayoutManager testLayoutManager,
632da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            final Runnable runnable) throws Throwable {
633da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        testLayoutManager.expectLayouts(1);
634da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        runTestOnUiThread(new Runnable() {
635da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
636da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
637da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                runnable.run();
638da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                assertTrue(mRecyclerView.hasPendingAdapterUpdates());
639da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
640da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
641da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        testLayoutManager.waitForLayout(1);
642da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
643da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
644da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
645da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm,
646da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            TestAdapter adapter, boolean waitForFirstLayout) throws Throwable {
647da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        recyclerView.setLayoutManager(tlm);
648da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        recyclerView.setAdapter(adapter);
649da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        if (waitForFirstLayout) {
650da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            tlm.expectLayouts(1);
651da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            setRecyclerView(recyclerView);
652da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            tlm.waitForLayout(1);
653da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        } else {
654da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            setRecyclerView(recyclerView);
655da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        }
656da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
657da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
658be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
6590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void hasPendingUpdatesBeforeFirstLayout() throws Throwable {
660da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
661da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
662da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
663da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, false);
664da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertTrue(mRecyclerView.hasPendingAdapterUpdates());
665da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
666da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
667be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
6680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void noPendingUpdatesAfterLayout() throws Throwable {
669da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
670da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
671da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
672da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, true);
673da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
674da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
675da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
676be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
6770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void hasPendingUpdatesWhenAdapterIsChanged() throws Throwable {
678da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
679da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        TestLayoutManager layoutManager = new DumbLayoutManager();
680da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
681da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        setupBasic(recyclerView, layoutManager, testAdapter, false);
682da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertPendingUpdatesAndLayout(layoutManager, new Runnable() {
683da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
684da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
685da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                testAdapter.notifyItemRemoved(1);
686da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
687da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
688da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertPendingUpdatesAndLayout(layoutManager, new Runnable() {
689da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
690da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
691da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                testAdapter.notifyItemInserted(2);
692da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
693da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
694da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
695da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertPendingUpdatesAndLayout(layoutManager, new Runnable() {
696da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
697da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
698da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                testAdapter.notifyItemMoved(2, 3);
699da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
700da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
701da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
702da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertPendingUpdatesAndLayout(layoutManager, new Runnable() {
703da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
704da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
705da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                testAdapter.notifyItemChanged(2);
706da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
707da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
708da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
709da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        assertPendingUpdatesAndLayout(layoutManager, new Runnable() {
710da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            @Override
711da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            public void run() {
712da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar                testAdapter.notifyDataSetChanged();
713da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar            }
714da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar        });
715da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar    }
716da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar
717be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
7180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateRecycleViaAdapter() throws Throwable {
719e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(true, false);
720e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
721e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
722be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
7230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateRecycleViaTransientStateCleanup() throws Throwable {
724e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(false, true);
725e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
726e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
727be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
7280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void transientStateDontRecycle() throws Throwable {
729e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        transientStateRecycleTest(false, false);
730e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
731e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
732e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState)
733e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            throws Throwable {
734e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        final List<View> failedToRecycle = new ArrayList<View>();
735e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        final List<View> recycled = new ArrayList<View>();
736e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10) {
737e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
738e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public boolean onFailedToRecycleView(
739e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    TestViewHolder holder) {
740e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                failedToRecycle.add(holder.itemView);
741e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (unsetTransientState) {
742e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    setHasTransientState(holder.itemView, false);
743e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
744e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                return succeed;
745e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
746e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
747e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
748e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public void onViewRecycled(TestViewHolder holder) {
749e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                recycled.add(holder.itemView);
750e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                super.onViewRecycled(holder);
751e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
752e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        };
753e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
754e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            @Override
755e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
756e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (getChildCount() == 0) {
757e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    detachAndScrapAttachedViews(recycler);
758e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    layoutRange(recycler, 0, 5);
759e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                } else {
760e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    removeAndRecycleAllViews(recycler);
761e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
762e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                if (layoutLatch != null) {
763e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                    layoutLatch.countDown();
764e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar                }
765e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar            }
766e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        };
767e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
768e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setAdapter(testAdapter);
769e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setLayoutManager(tlm);
770e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        recyclerView.setItemAnimator(null);
771e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        setRecyclerView(recyclerView);
772e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        getInstrumentation().waitForIdleSync();
773e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        // make sure we have enough views after this position so that we'll receive the on recycled
774e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        // callback
775e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        View view = recyclerView.getChildAt(3);//this has to be greater than def cache size.
776e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        setHasTransientState(view, true);
777e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        tlm.expectLayouts(1);
778e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        requestLayoutOnUIThread(recyclerView);
779e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        tlm.waitForLayout(2);
780e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
781e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        assertTrue(failedToRecycle.contains(view));
782e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar        assertEquals(succeed || unsetTransientState, recycled.contains(view));
783e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar    }
784e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
785be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
7860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionInvalidation() throws Throwable {
787e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
788e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final TestAdapter adapter = new TestAdapter(10);
789e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        final TestLayoutManager tlm = new TestLayoutManager() {
790e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            @Override
791e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
792e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                layoutRange(recycler, 0, state.getItemCount());
793e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                layoutLatch.countDown();
794e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            }
795e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        };
796e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        recyclerView.setAdapter(adapter);
797e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        recyclerView.setLayoutManager(tlm);
798e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        tlm.expectLayouts(1);
799e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        setRecyclerView(recyclerView);
800e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        tlm.waitForLayout(1);
801e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        runTestOnUiThread(new Runnable() {
802e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            @Override
803e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            public void run() {
8041a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < tlm.getChildCount(); i++) {
805e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                    assertNotSame("adapter positions should not be undefined",
806e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
807e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            RecyclerView.NO_POSITION);
808e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                }
809e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                adapter.notifyDataSetChanged();
8101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < tlm.getChildCount(); i++) {
811e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                    assertSame("adapter positions should be undefined",
812e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
813e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                            RecyclerView.NO_POSITION);
814e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar                }
815e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar            }
816e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        });
817e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar    }
818e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
819be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsBasic() throws Throwable {
821115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(null);
822115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
823115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
824be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsRemoveItems() throws Throwable {
826115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
827115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
828115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
829115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.deleteAndNotify(3, 4);
830115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
831115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
832115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
833115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
834be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsRemoveItemsBefore() throws Throwable {
836115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
837115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
838115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
839115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.deleteAndNotify(0, 1);
840115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
841115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
842115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
843115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
844be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsAddItemsBefore() throws Throwable {
846115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
847115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
848115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
849115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.addAndNotify(0, 5);
850115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
851115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
852115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
853115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
854be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsAddItemsInside() throws Throwable {
856115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
857115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
858115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
859115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.addAndNotify(3, 2);
860115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
861115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
862115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
863115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
864be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsMoveItems() throws Throwable {
866115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
867115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
868115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
869115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.moveAndNotify(3, 5);
870115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
871115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
872115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
873115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
874be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterPositionsNotifyDataSetChanged() throws Throwable {
876115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        adapterPositionsTest(new AdapterRunnable() {
877115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
878115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run(TestAdapter adapter) throws Throwable {
879115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.mItems.clear();
8801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                for (int i = 0; i < 20; i++) {
881115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    adapter.mItems.add(new Item(i, "added item"));
882115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
883115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                adapter.notifyDataSetChanged();
884115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
885115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
886115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
887115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
888be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
8890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable {
890619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final AtomicBoolean failedToRecycle = new AtomicBoolean(false);
891619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
892619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
893619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
894619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
895619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                detachAndScrapAttachedViews(recycler);
896619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutRange(recycler, 0, state.getItemCount());
897619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutLatch.countDown();
898619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
899619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
900619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestAdapter adapter = new TestAdapter(10) {
901619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
902619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public boolean onFailedToRecycleView(
903619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    TestViewHolder holder) {
904619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                failedToRecycle.set(true);
905619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                return false;
906619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
907619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
908619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setAdapter(adapter);
909619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setLayoutManager(tlm);
910619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
911619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        setRecyclerView(rv);
912619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(1);
913619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
914619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        runTestOnUiThread(new Runnable() {
915619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
916619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void run() {
917619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                ViewCompat.setHasTransientState(vh.itemView, true);
918619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
919619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        });
920619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
921619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        adapter.deleteAndNotify(0, 10);
922619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(2);
923619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final CountDownLatch animationsLatch = new CountDownLatch(1);
924619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.getItemAnimator().isRunning(
925619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
926619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    @Override
927619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    public void onAnimationsFinished() {
928619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                        animationsLatch.countDown();
929619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    }
930619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                });
931619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
932619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(failedToRecycle.get());
933619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertNull(vh.mOwnerRecyclerView);
934619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        checkForMainThreadException();
935619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar    }
936619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar
937be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
9380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable {
939619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
940619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
941619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            @Override
942619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
943619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                detachAndScrapAttachedViews(recycler);
944619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutRange(recycler, 0, state.getItemCount());
945619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                layoutLatch.countDown();
946619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar            }
947619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        };
948619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
949619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setAdapter(adapter);
950619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.setLayoutManager(tlm);
951619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
952619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        setRecyclerView(rv);
953619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(1);
954619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
955619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.expectLayouts(1);
956619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        adapter.deleteAndNotify(0, 10);
957619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        tlm.waitForLayout(2);
958619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        final CountDownLatch animationsLatch = new CountDownLatch(1);
959619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        rv.getItemAnimator().isRunning(
960619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
961619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    @Override
962619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    public void onAnimationsFinished() {
963619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                        animationsLatch.countDown();
964619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                    }
965619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar                });
966619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
967619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        assertNull(vh.mOwnerRecyclerView);
968619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar        checkForMainThreadException();
969619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar    }
970619ac016831a5ad75c2e0921c9036b6f030a9e63Yigit Boyar
971115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable {
972115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
973115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
974115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
975115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
976115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                try {
977115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    layoutRange(recycler, Math.min(state.getItemCount(), 2)
978115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            , Math.min(state.getItemCount(), 7));
979115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    layoutLatch.countDown();
980115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                } catch (Throwable t) {
981115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    postExceptionToInstrumentation(t);
982115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
983115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
984115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        };
985115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
986115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        recyclerView.setLayoutManager(tlm);
987115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        recyclerView.setAdapter(testAdapter);
988115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        tlm.expectLayouts(1);
989115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        setRecyclerView(recyclerView);
990115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        tlm.waitForLayout(1);
991115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        runTestOnUiThread(new Runnable() {
992115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            @Override
993115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            public void run() {
994115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                try {
995115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    final int count = recyclerView.getChildCount();
996115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    Map<View, Integer> layoutPositions = new HashMap<View, Integer>();
997115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    assertTrue("test sanity", count > 0);
9981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    for (int i = 0; i < count; i++) {
999115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        View view = recyclerView.getChildAt(i);
1000115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view);
1001115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        int index = testAdapter.mItems.indexOf(vh.mBoundItem);
1002115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        assertEquals("should be able to find VH with adapter position " + index, vh,
1003115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                recyclerView.findViewHolderForAdapterPosition(index));
1004115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        assertEquals("get adapter position should return correct index", index,
1005115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                vh.getAdapterPosition());
1006115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        layoutPositions.put(view, vh.mPosition);
1007115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
1008115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    if (adapterChanges != null) {
1009115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        adapterChanges.run(testAdapter);
1010115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        for (int i = 0; i < count; i++) {
1011115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            View view = recyclerView.getChildAt(i);
1012115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            TestViewHolder vh = (TestViewHolder) recyclerView
1013115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    .getChildViewHolder(view);
1014115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            int index = testAdapter.mItems.indexOf(vh.mBoundItem);
1015115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            if (index >= 0) {
1016115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                assertEquals("should be able to find VH with adapter position "
10171a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                                                + index, vh,
1018115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                        recyclerView.findViewHolderForAdapterPosition(index));
1019115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            }
1020115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            assertSame("get adapter position should return correct index", index,
1021115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    vh.getAdapterPosition());
1022115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            assertSame("should be able to find view with layout position",
1023115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    vh, mRecyclerView.findViewHolderForLayoutPosition(
1024115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                            layoutPositions.get(view)));
1025115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        }
1026115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1027115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    }
1028115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
1029115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                } catch (Throwable t) {
1030115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    postExceptionToInstrumentation(t);
1031115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                }
1032115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            }
1033115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        });
1034115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        checkForMainThreadException();
1035e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar    }
1036e2437126f0225135891544315ff72e54c7de0f59Yigit Boyar
1037be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForSmoothScroll() throws Throwable {
1039bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1040bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1041bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1042bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1043bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1044bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1045bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1046bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1047bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1048bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(2);
1049bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1050bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1051bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1052bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1053bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1054bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1055bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1056bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1057bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1058bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1059bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.smoothScrollBy(0, 500);
1060bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1061bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1062bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1063bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1064bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1065bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1066bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1067bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1068be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
10690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForSmoothScrollWithStop() throws Throwable {
1070bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1071bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1072bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1073bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1074bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1075bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1076bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1077bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1078bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1079bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(1);
1080bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1081bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1082bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1083bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1084bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1085bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1086bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1087bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1088bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1089bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1090bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.smoothScrollBy(0, 500);
1091bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1092bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1093bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1094bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1095bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1096bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1097bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.stopScroll();
1098bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1099bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1100bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1101bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1102bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1103bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1104bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1105bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1106be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForFling() throws Throwable {
1108bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1109bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1110bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1111bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1112bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1113bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1114bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1115bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1116bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1117bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(2);
1118bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1119bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1120bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1121bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1122bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1123bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1124bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1125bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
1126bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final float fling = vc.getScaledMinimumFlingVelocity()
1127bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f;
1128bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1129bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1130bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1131bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.fling(0, Math.round(fling));
1132bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1133bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1134bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1135bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1136bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1137bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1138bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1139bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1140be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateForFlingWithStop() throws Throwable {
1142bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1143bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1144bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1145bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1146bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1147bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1148bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1149bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1150bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1151bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final CountDownLatch latch = new CountDownLatch(1);
1152bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1153bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1154bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1155bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1156bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                latch.countDown();
1157bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1158bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1159bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
1160bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final float fling = vc.getScaledMinimumFlingVelocity()
1161bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f;
1162bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1163bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1164bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1165bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.fling(0, Math.round(fling));
1166bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1167bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1168bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        latch.await(5, TimeUnit.SECONDS);
1169bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1170bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1171bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1172bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                mRecyclerView.stopScroll();
1173bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1174bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1175bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1176bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
1177bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1178bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
1179bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1180bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1181be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
11820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void scrollStateDrag() throws Throwable {
1183bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
1184bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager();
1185bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
1186bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setAdapter(testAdapter);
1187bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setLayoutManager(tlm);
1188bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        setRecyclerView(recyclerView);
1189bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1190bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
1191bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        final int[] stateCnts = new int[10];
1192bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
1193bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1194bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
1195bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                stateCnts[newState] = stateCnts[newState] + 1;
1196bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1197bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1198bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        drag(mRecyclerView, 0, 0, 0, 500, 5);
1199bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]);
1200bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
1201bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]);
1202bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1203bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1204bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY,
1205bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            int stepCount) throws Throwable {
1206bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        long downTime = SystemClock.uptimeMillis();
1207bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        long eventTime = SystemClock.uptimeMillis();
1208bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1209bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float y = fromY;
1210bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float x = fromX;
1211bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1212bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float yStep = (toY - fromY) / stepCount;
1213bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        float xStep = (toX - fromX) / stepCount;
1214bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1215bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
1216bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                MotionEvent.ACTION_DOWN, x, y, 0);
1217bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        sendTouch(view, event);
1218bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        for (int i = 0; i < stepCount; ++i) {
1219bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            y += yStep;
1220bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            x += xStep;
1221bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            eventTime = SystemClock.uptimeMillis();
1222bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
1223bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            sendTouch(view, event);
1224bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
1225bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1226bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        eventTime = SystemClock.uptimeMillis();
1227bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
1228bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        sendTouch(view, event);
1229bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        getInstrumentation().waitForIdleSync();
1230bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1231bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1232bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable {
1233bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        runTestOnUiThread(new Runnable() {
1234bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            @Override
1235bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            public void run() {
1236bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                if (view.onInterceptTouchEvent(event)) {
1237bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                    view.onTouchEvent(event);
1238bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                }
1239bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            }
1240bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        });
1241bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar    }
1242bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
1243be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
12440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleScrap() throws Throwable {
124566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recycleScrapTest(false);
124666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        removeRecyclerView();
124766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recycleScrapTest(true);
124866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    }
124966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar
125066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    public void recycleScrapTest(final boolean useRecycler) throws Throwable {
125166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
125266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        final AtomicBoolean test = new AtomicBoolean(false);
125366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
125466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            @Override
125566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1256e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
125766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                if (test.get()) {
125866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    try {
125966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        detachAndScrapAttachedViews(recycler);
126066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) {
126166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            if (useRecycler) {
126266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                recycler.recycleView(recycler.getScrapList().get(i).itemView);
126366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            } else {
126466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                removeAndRecycleView(recycler.getScrapList().get(i).itemView,
126566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                        recycler);
126666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            }
126766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
1268e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                        if (infoStore.mOldChangedHolders != null) {
1269e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                            for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
127066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                if (useRecycler) {
127166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                    recycler.recycleView(
1272e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            infoStore.mOldChangedHolders.valueAt(i).itemView);
127366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                } else {
127466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                    removeAndRecycleView(
1275e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            infoStore.mOldChangedHolders.valueAt(i).itemView,
1276e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                            recycler);
127766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                                }
127866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            }
127966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
128066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
128166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("pre layout map should be empty", 0,
1282e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                InfoStoreTrojan.sizeOfPreLayout(infoStore));
128366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        assertEquals("post layout map should be empty", 0,
1284e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                InfoStoreTrojan.sizeOfPostLayout(infoStore));
1285e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                        if (infoStore.mOldChangedHolders != null) {
128666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                            assertEquals("post old change map should be empty", 0,
1287e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar                                    infoStore.mOldChangedHolders.size());
128866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        }
128966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    } catch (Throwable t) {
129066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                        postExceptionToInstrumentation(t);
129166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                    }
129266a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar
129366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                }
129466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                layoutRange(recycler, 0, 5);
129566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                layoutLatch.countDown();
129666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar                super.onLayoutChildren(recycler, state);
129766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar            }
129866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        };
129966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
130066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recyclerView.setAdapter(testAdapter);
130166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        recyclerView.setLayoutManager(lm);
1302121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar        ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
130366a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.expectLayouts(1);
130466a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        setRecyclerView(recyclerView);
130566a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.waitForLayout(2);
130666a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        test.set(true);
130766a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.expectLayouts(1);
130866a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        testAdapter.changeAndNotify(3, 1);
130966a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        lm.waitForLayout(2);
131066a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar        checkForMainThreadException();
131166a5670ac0e58e1d08f6af57b13648c1ab9df441Yigit Boyar    }
131222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
1313be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
13144143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable {
13155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        accessRecyclerOnOnMeasureTest(true);
13165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    }
13175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
1318be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
13194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable {
13204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        accessRecyclerOnOnMeasureTest(false);
13214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
13224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
13234143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    @Test
13240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable {
1325cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar        smoothScrollTest(true);
1326cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    }
1327cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar
1328cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar    @Test
13290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void smoothScrollWithRemovedItems() throws Throwable {
1330ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        smoothScrollTest(false);
1331ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    }
1332ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1333ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    public void smoothScrollTest(final boolean removeItem) throws Throwable {
1334ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final LinearSmoothScroller[] lss = new LinearSmoothScroller[1];
1335ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final CountDownLatch calledOnStart = new CountDownLatch(1);
1336ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final CountDownLatch calledOnStop = new CountDownLatch(1);
1337ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final int visibleChildCount = 10;
1338ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
1339ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            int start = 0;
1340ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1341ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
1342ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1343ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                super.onLayoutChildren(recycler, state);
1344ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                layoutRange(recycler, start, visibleChildCount);
1345ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                layoutLatch.countDown();
1346ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1347ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1348ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
1349ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
1350ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    RecyclerView.State state) {
1351ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                start++;
1352ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                if (DEBUG) {
1353ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:"
1354ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            + visibleChildCount);
1355ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                }
1356ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                removeAndRecycleAllViews(recycler);
1357c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                layoutRange(recycler, start,
1358c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                        Math.max(state.getItemCount(), start + visibleChildCount));
1359ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                return dy;
1360ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1361ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1362ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
1363ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public boolean canScrollVertically() {
1364ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                return true;
1365ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1366ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1367ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
1368ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
1369ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    int position) {
1370ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                LinearSmoothScroller linearSmoothScroller =
1371ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
1372ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
1373ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
1374ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                return new PointF(0, 1);
1375ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
1376ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1377ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
1378ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            protected void onStart() {
1379ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                super.onStart();
1380ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                calledOnStart.countDown();
1381ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
1382ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1383ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            @Override
1384ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            protected void onStop() {
1385ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                super.onStop();
1386ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                calledOnStop.countDown();
1387ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
1388ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        };
1389ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                linearSmoothScroller.setTargetPosition(position);
1390ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                lss[0] = linearSmoothScroller;
1391ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                startSmoothScroll(linearSmoothScroller);
1392ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1393ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        };
1394ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
1395ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        TestAdapter testAdapter = new TestAdapter(500);
1396ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        rv.setLayoutManager(lm);
1397ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        rv.setAdapter(testAdapter);
1398ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        lm.expectLayouts(1);
1399ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        setRecyclerView(rv);
1400ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        lm.waitForLayout(1);
1401ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        // regular scroll
1402ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        final int targetPosition = visibleChildCount * (removeItem ? 30 : 4);
1403ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        runTestOnUiThread(new Runnable() {
1404ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            @Override
1405ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            public void run() {
1406ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                rv.smoothScrollToPosition(targetPosition);
1407ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1408ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        });
1409ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        if (DEBUG) {
1410ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            Log.d(TAG, "scrolling to target position " + targetPosition);
1411ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        }
1412ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS));
1413ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        if (removeItem) {
1414ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            final int newTarget = targetPosition - 10;
1415ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1);
141690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            final CountDownLatch targetCheck = new CountDownLatch(1);
1417ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            runTestOnUiThread(new Runnable() {
1418ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                @Override
1419ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                public void run() {
1420ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    ViewCompat.postOnAnimationDelayed(rv, new Runnable() {
1421ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        @Override
1422ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        public void run() {
1423ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            try {
1424ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                assertEquals("scroll position should be updated to next available",
1425ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                        newTarget, lss[0].getTargetPosition());
1426ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            } catch (Throwable t) {
1427ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                                postExceptionToInstrumentation(t);
1428ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                            }
142990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                            targetCheck.countDown();
1430ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                        }
143190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    }, 50);
1432ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                }
1433ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            });
143490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar            assertTrue("target position should be checked on time ",
143590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    targetCheck.await(10, TimeUnit.SECONDS));
1436ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            checkForMainThreadException();
1437ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS));
1438ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            checkForMainThreadException();
1439ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertNotNull("should scroll to new target " + newTarget
1440115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    , rv.findViewHolderForLayoutPosition(newTarget));
1441ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            if (DEBUG) {
1442ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                Log.d(TAG, "on stop has been called on time");
1443ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            }
1444ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        } else {
1445ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertTrue("on stop should be called eventually",
1446ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar                    calledOnStop.await(30, TimeUnit.SECONDS));
1447ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar            assertNotNull("scroll to position should succeed",
1448115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    rv.findViewHolderForLayoutPosition(targetPosition));
1449ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        }
1450ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar        checkForMainThreadException();
1451ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar    }
1452ee30f03253207f694cc46063b0c8c7cb91d24a6eYigit Boyar
1453be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
14540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void consecutiveSmoothScroll() throws Throwable {
145578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger visibleChildCount = new AtomicInteger(10);
145678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger totalScrolled = new AtomicInteger(0);
145778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
145878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            int start = 0;
145978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
146078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
146178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
146278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                super.onLayoutChildren(recycler, state);
146378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                layoutRange(recycler, start, visibleChildCount.get());
146478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                layoutLatch.countDown();
146578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
146678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
146778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
146878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
146978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                    RecyclerView.State state) {
147078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                totalScrolled.set(totalScrolled.get() + dy);
147178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                return dy;
147278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
147378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
147478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
147578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public boolean canScrollVertically() {
147678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                return true;
147778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
147878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        };
147978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
148078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        TestAdapter testAdapter = new TestAdapter(500);
148178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        rv.setLayoutManager(lm);
148278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        rv.setAdapter(testAdapter);
148378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        lm.expectLayouts(1);
148478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        setRecyclerView(rv);
148578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        lm.waitForLayout(1);
148678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        runTestOnUiThread(new Runnable() {
148778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
148878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void run() {
148978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                rv.smoothScrollBy(0, 2000);
149078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
149178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        });
149278f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        Thread.sleep(250);
149378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final AtomicInteger scrollAmt = new AtomicInteger();
149478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        runTestOnUiThread(new Runnable() {
149578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            @Override
149678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            public void run() {
149778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                final int soFar = totalScrolled.get();
149878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                scrollAmt.set(soFar);
149978f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar                rv.smoothScrollBy(0, 5000 - soFar);
150078f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            }
150178f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        });
15021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        while (rv.getScrollState() != SCROLL_STATE_IDLE) {
150378f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar            Thread.sleep(100);
150478f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        }
150578f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        final int soFar = totalScrolled.get();
150678f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar        assertEquals("second scroll should be competed properly", 5000, soFar);
150778f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar    }
150878f659a66b021d5d0e36800a7144e956d8054ceaYigit Boyar
15095cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations)
15105cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            throws Throwable {
15115cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
15125cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10);
15135cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
15145cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
15155cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
15165cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                super.onLayoutChildren(recycler, state);
15175cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                try {
15185cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
15195cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutLatch.countDown();
15205cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                } catch (Throwable t) {
15215cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    postExceptionToInstrumentation(t);
15225cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                } finally {
15235cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    layoutLatch.countDown();
15245cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                }
15255cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
15265cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
15275cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
15285cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
15295cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    int widthSpec, int heightSpec) {
15305cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                try {
15315cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    // make sure we access all views
15325cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    for (int i = 0; i < state.getItemCount(); i++) {
15335cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        View view = recycler.getViewForPosition(i);
15345cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        assertNotNull(view);
15355cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        assertEquals(i, getPosition(view));
15365cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    }
15374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    if (!state.isPreLayout()) {
15384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        assertEquals(state.toString(),
15394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                                expectedOnMeasureStateCount.get(), state.getItemCount());
15404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    }
1541824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                } catch (Throwable t) {
15425cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                    postExceptionToInstrumentation(t);
15435cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                }
15445cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                super.onMeasure(recycler, state, widthSpec, heightSpec);
15455cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
15465cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
15475cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            @Override
15485cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            public boolean supportsPredictiveItemAnimations() {
15495cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                return enablePredictiveAnimations;
15505cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            }
15515cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        };
15525cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
15535cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setLayoutManager(lm);
15545cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setAdapter(testAdapter);
15555cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        recyclerView.setLayoutManager(lm);
15565cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.expectLayouts(1);
15575cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        setRecyclerView(recyclerView);
15585cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.waitForLayout(2);
15595cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        checkForMainThreadException();
15605cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.expectLayouts(1);
15615cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        if (!enablePredictiveAnimations) {
15625cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar            expectedOnMeasureStateCount.set(15);
15635cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        }
15645cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        testAdapter.addAndNotify(4, 5);
15655cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        lm.waitForLayout(2);
15665cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar        checkForMainThreadException();
15675cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar    }
15685cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar
1569be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
15700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void setCompatibleAdapter() throws Throwable {
15710b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(true, true);
15720b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
15730b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(false, true);
15740b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
15750b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(true, false);
15760b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
15770b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        compatibleAdapterTest(false, false);
15780b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        removeRecyclerView();
15790b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
15800b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
15810b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews)
15820b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            throws Throwable {
15830b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
15840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        final AtomicInteger recycledViewCount = new AtomicInteger();
15850b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
15860b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
15870b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
15880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                try {
15890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
15900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
15910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } catch (Throwable t) {
15920b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    postExceptionToInstrumentation(t);
15930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } finally {
15940b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
15950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                }
15960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
15970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        };
15980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
15990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
16000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setAdapter(testAdapter);
16010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
16020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
16030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onViewRecycled(RecyclerView.ViewHolder holder) {
16040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                recycledViewCount.incrementAndGet();
16050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
16060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        });
16070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
16080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setRecyclerView(recyclerView, !useCustomPool);
16090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
16100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
16110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
16120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews);
16130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
16140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
16150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        if (removeAndRecycleExistingViews) {
16160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            assertTrue("Previous views should be recycled", recycledViewCount.get() > 0);
16170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        } else {
16180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            assertEquals("No views should be recycled if adapters are compatible and developer "
16190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    + "did not request a recycle", 0, recycledViewCount.get());
16200b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
16210b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
16220b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
1623be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
16240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void setIncompatibleAdapter() throws Throwable {
16250b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        incompatibleAdapterTest(true);
16260b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        incompatibleAdapterTest(false);
16270b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
16280b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
16290b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable {
16300b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
16310b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
16320b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            @Override
16330b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
16340b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                super.onLayoutChildren(recycler, state);
16350b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                try {
16360b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
16370b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
16380b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } catch (Throwable t) {
16390b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    postExceptionToInstrumentation(t);
16400b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                } finally {
16410b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                    layoutLatch.countDown();
16420b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                }
16430b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
16440b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        };
16450b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
16460b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
16470b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setAdapter(testAdapter);
16480b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        recyclerView.setLayoutManager(lm);
16490b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
16500b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setRecyclerView(recyclerView, !useCustomPool);
16510b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
16520b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
16530b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.expectLayouts(1);
16540b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        setAdapter(new TestAdapter2(10));
16550b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        lm.waitForLayout(2);
16560b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        checkForMainThreadException();
16570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
16580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
1659be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
16600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleIgnored() throws Throwable {
16616e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
16626e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
16636e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            @Override
16646e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
16656e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                layoutRange(recycler, 0, 5);
16666e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                layoutLatch.countDown();
16676e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            }
16686e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        };
16696e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
16706e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        recyclerView.setAdapter(adapter);
16716e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        recyclerView.setLayoutManager(lm);
16726e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        lm.expectLayouts(1);
16736e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        setRecyclerView(recyclerView);
16746e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        lm.waitForLayout(2);
16756e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        runTestOnUiThread(new Runnable() {
16766e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            @Override
16776e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            public void run() {
16786e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                View child1 = lm.findViewByPosition(0);
16796e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                View child2 = lm.findViewByPosition(1);
16806e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.ignoreView(child1);
16816e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.ignoreView(child2);
16826e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
16836e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.removeAndRecycleAllViews(recyclerView.mRecycler);
16846e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertEquals("ignored child should not be recycled or removed", 2,
16856e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                        lm.getChildCount());
16866e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
16876e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                Throwable[] throwables = new Throwable[1];
16886e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                try {
16896e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                    lm.removeAndRecycleView(child1, mRecyclerView.mRecycler);
16906e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                } catch (Throwable t) {
16916e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                    throwables[0] = t;
16926e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                }
16936e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertTrue("Trying to recycle an ignored view should throw IllegalArgException "
16945cfed5428d421f179f83382ad72ec6edd11a066dYigit Boyar                        , throwables[0] instanceof IllegalArgumentException);
16956e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                lm.removeAllViews();
16966e560171b774afafd572b1896becac7b308a92e6Yigit Boyar                assertEquals("ignored child should be removed as well ", 0, lm.getChildCount());
16976e560171b774afafd572b1896becac7b308a92e6Yigit Boyar            }
16986e560171b774afafd572b1896becac7b308a92e6Yigit Boyar        });
16996e560171b774afafd572b1896becac7b308a92e6Yigit Boyar    }
17006e560171b774afafd572b1896becac7b308a92e6Yigit Boyar
1701be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
17020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findIgnoredByPosition() throws Throwable {
1703f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
1704f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
1705f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            @Override
1706f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1707f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                detachAndScrapAttachedViews(recycler);
1708f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                layoutRange(recycler, 0, 5);
1709f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                layoutLatch.countDown();
1710f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            }
1711f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        };
1712f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
1713f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        recyclerView.setAdapter(adapter);
1714f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        recyclerView.setLayoutManager(lm);
1715f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.expectLayouts(1);
1716f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        setRecyclerView(recyclerView);
1717f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.waitForLayout(2);
1718f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        Thread.sleep(5000);
1719f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final int pos = 1;
1720f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        final View[] ignored = new View[1];
1721f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        runTestOnUiThread(new Runnable() {
1722f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            @Override
1723f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            public void run() {
1724f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                View child = lm.findViewByPosition(pos);
1725f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                lm.ignoreView(child);
1726f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                ignored[0] = child;
1727f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar            }
1728f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        });
1729f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotNull("ignored child should not be null", ignored[0]);
1730f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNull("find view by position should not return ignored child",
1731f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar                lm.findViewByPosition(pos));
1732f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.expectLayouts(1);
1733f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        requestLayoutOnUIThread(mRecyclerView);
1734f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        lm.waitForLayout(1);
1735f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertEquals("child count should be ", 6, lm.getChildCount());
1736f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        View replacement = lm.findViewByPosition(pos);
1737f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotNull("re-layout should replace ignored child w/ another one", replacement);
1738f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar        assertNotSame("replacement should be a different view", replacement, ignored[0]);
1739f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar    }
1740f485be9def4c0f72cfdfa6b0c616c23f04652817Yigit Boyar
1741be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
17420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void invalidateAllDecorOffsets() throws Throwable {
1743bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final TestAdapter adapter = new TestAdapter(10);
1744bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
1745bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true);
1746bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setAdapter(adapter);
1747bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(4);
1748bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() {
1749bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        };
1750bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        TestLayoutManager testLayoutManager = new TestLayoutManager() {
1751bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
1752bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1753bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                try {
1754bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    // test
1755824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    for (int i = 0; i < getChildCount(); i++) {
1756bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        View child = getChildAt(i);
1757bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
1758bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                child.getLayoutParams();
1759bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        assertEquals(
1760bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                "Decor insets validation for VH should have expected value.",
1761bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                invalidatedOffsets.get(), lp.mInsetsDirty);
1762bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    }
1763bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) {
1764bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
1765bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                vh.itemView.getLayoutParams();
1766bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                        assertEquals(
1767bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                "Decor insets invalidation in cache for VH should have expected "
1768bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                        + "value.",
1769bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                                invalidatedOffsets.get(), lp.mInsetsDirty);
1770bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    }
1771bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    detachAndScrapAttachedViews(recycler);
1772bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    layoutRange(recycler, 0, layoutCount.get());
1773bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                } catch (Throwable t) {
1774bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    postExceptionToInstrumentation(t);
1775bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                } finally {
1776bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                    layoutLatch.countDown();
1777bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                }
1778bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
1779bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1780bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
1781bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
1782bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                return false;
1783bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
1784bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        };
1785bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // first layout
1786bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setItemViewCacheSize(5);
1787bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        recyclerView.setLayoutManager(testLayoutManager);
1788bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1789e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar        setRecyclerView(recyclerView, true, false);
1790bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(2);
1791bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1792bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1793bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // re-layout w/o any change
1794bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
1795bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1796bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(recyclerView);
1797bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1798bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1799bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1800bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // invalidate w/o an item decorator
1801e37d2e63f16bc5c2938e372238ba54679a9e578eYigit Boyar
1802bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
1803bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1804bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
1805bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.assertNoLayout("layout should not happen", 2);
1806bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1807bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1808bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // set item decorator, should invalidate
1809bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
1810bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1811bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        addItemDecoration(mRecyclerView, dummyItemDecoration);
1812bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1813bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1814bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1815bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // re-layout w/o any change
1816bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
1817bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1818bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(recyclerView);
1819bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1820bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1821bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1822bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // invalidate w/ item decorator
1823bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
1824bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
1825bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1826bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
1827bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(2);
1828bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1829bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1830bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // trigger cache.
1831bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        layoutCount.set(3);
1832bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(false);
1833bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1834bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        requestLayoutOnUIThread(mRecyclerView);
1835bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1836bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1837bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size());
1838bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1839bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        layoutCount.set(5);
1840bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
1841bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1842bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidateDecorOffsets(recyclerView);
1843bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1844bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1845bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1846bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        // remove item decorator
1847bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        invalidatedOffsets.set(true);
1848bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.expectLayouts(1);
1849bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        removeItemDecoration(mRecyclerView, dummyItemDecoration);
1850bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        testLayoutManager.waitForLayout(1);
1851bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        checkForMainThreadException();
1852bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
1853bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1854bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void addItemDecoration(final RecyclerView recyclerView, final
1855824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
1856bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
1857bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
1858bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
1859bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.addItemDecoration(itemDecoration);
1860bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
1861bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
1862bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
1863bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1864bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void removeItemDecoration(final RecyclerView recyclerView, final
1865bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
1866bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
1867bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
1868bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
1869bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.removeItemDecoration(itemDecoration);
1870bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
1871bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
1872bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
1873bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1874bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable {
1875bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        runTestOnUiThread(new Runnable() {
1876bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            @Override
1877bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            public void run() {
1878bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar                recyclerView.invalidateItemDecorations();
1879bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar            }
1880bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar        });
1881bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar    }
1882bc2c6d6432a227d46a43fd18eb204d89ca472064Yigit Boyar
1883be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
18840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void invalidateDecorOffsets() throws Throwable {
1885cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final TestAdapter adapter = new TestAdapter(10);
1886cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.setHasStableIds(true);
1887cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final RecyclerView recyclerView = new RecyclerView(getActivity());
1888cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        recyclerView.setAdapter(adapter);
1889cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1890cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        final Map<Long, Boolean> changes = new HashMap<Long, Boolean>();
1891cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1892cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        TestLayoutManager testLayoutManager = new TestLayoutManager() {
1893cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            @Override
1894cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1895cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                try {
1896cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    if (changes.size() > 0) {
1897cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                        // test
1898824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        for (int i = 0; i < getChildCount(); i++) {
1899cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            View child = getChildAt(i);
1900cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
1901cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    child.getLayoutParams();
1902cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            RecyclerView.ViewHolder vh = lp.mViewHolder;
1903cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            if (!changes.containsKey(vh.getItemId())) {
1904cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                continue; //nothing to test
1905cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            }
1906cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                            assertEquals(
1907cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    "Decord insets validation for VH should have expected value.",
1908cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    changes.get(vh.getItemId()).booleanValue(),
1909cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                                    lp.mInsetsDirty);
1910cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                        }
1911cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    }
1912cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    detachAndScrapAttachedViews(recycler);
1913cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    layoutRange(recycler, 0, state.getItemCount());
1914cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                } catch (Throwable t) {
1915cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    postExceptionToInstrumentation(t);
1916cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                } finally {
1917cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    layoutLatch.countDown();
1918cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                }
1919cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            }
1920cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1921cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            @Override
1922cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            public boolean supportsPredictiveItemAnimations() {
1923cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                return false;
1924cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase            }
1925cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        };
1926cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        recyclerView.setLayoutManager(testLayoutManager);
1927cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
1928cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        setRecyclerView(recyclerView);
1929cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
1930cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        int itemAddedTo = 5;
1931cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        for (int i = 0; i < itemAddedTo; i++) {
1932115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
1933cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
1934cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) {
1935115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
1936cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
1937cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
1938cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.addAndNotify(5, 1);
1939cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
1940cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
1941cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1942cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        changes.clear();
1943cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        int[] changedItems = new int[]{3, 5, 6};
1944824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < adapter.getItemCount(); i++) {
1945115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
1946cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
1947824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < changedItems.length; i++) {
19481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItems[i]).getItemId(),
19491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    true);
1950cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
1951cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
1952cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.changePositionsAndNotify(changedItems);
1953cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
1954cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
1955cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1956824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        for (int i = 0; i < adapter.getItemCount(); i++) {
1957115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
1958cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        }
1959cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.expectLayouts(1);
1960cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.dispatchDataSetChanged();
1961cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        testLayoutManager.waitForLayout(2);
1962cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        checkForMainThreadException();
1963cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase    }
1964cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
1965be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
19660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void movingViaStableIds() throws Throwable {
1967c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        stableIdsMoveTest(true);
1968c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        removeRecyclerView();
1969c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        stableIdsMoveTest(false);
1970c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        removeRecyclerView();
1971c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    }
1972c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
1973c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable {
1974c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
1975c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        testAdapter.setHasStableIds(true);
1976c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final AtomicBoolean test = new AtomicBoolean(false);
1977c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final int movedViewFromIndex = 3;
1978c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final int movedViewToIndex = 6;
1979c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        final View[] movedView = new View[1];
1980c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
1981c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
1982c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
1983c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                detachAndScrapAttachedViews(recycler);
1984c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                try {
1985c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    if (test.get()) {
1986c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        if (state.isPreLayout()) {
1987c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            View view = recycler.getViewForPosition(movedViewFromIndex, true);
1988c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertSame("In pre layout, should be able to get moved view w/ old "
1989c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                                    + "position", movedView[0], view);
1990c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
1991c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
1992c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            // clear scrap flag
1993c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            holder.clearReturnedFromScrapFlag();
1994c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        } else {
1995c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            View view = recycler.getViewForPosition(movedViewToIndex, true);
1996c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertSame("In post layout, should be able to get moved view w/ new "
1997c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                                    + "position", movedView[0], view);
1998c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
1999c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
2000c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            // clear scrap flag
2001c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                            holder.clearReturnedFromScrapFlag();
2002c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                        }
2003c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    }
2004c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
2005c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                } catch (Throwable t) {
2006c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    postExceptionToInstrumentation(t);
2007c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                } finally {
2008c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                    layoutLatch.countDown();
2009c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                }
2010c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2011c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2012c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2013c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2014c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
2015c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public boolean supportsPredictiveItemAnimations() {
2016c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                return supportsPredictive;
2017c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2018c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        };
2019c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        RecyclerView recyclerView = new RecyclerView(this.getActivity());
2020c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        recyclerView.setAdapter(testAdapter);
2021c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        recyclerView.setLayoutManager(lm);
2022c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.expectLayouts(1);
2023c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        setRecyclerView(recyclerView);
2024c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.waitForLayout(1);
2025c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar
2026c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        movedView[0] = recyclerView.getChildAt(movedViewFromIndex);
2027c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        test.set(true);
2028c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.expectLayouts(supportsPredictive ? 2 : 1);
2029c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        runTestOnUiThread(new Runnable() {
2030c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            @Override
2031c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            public void run() {
2032c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                Item item = testAdapter.mItems.remove(movedViewFromIndex);
2033c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.mItems.add(movedViewToIndex, item);
2034c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.notifyItemRemoved(movedViewFromIndex);
2035c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar                testAdapter.notifyItemInserted(movedViewToIndex);
2036c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar            }
2037c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        });
2038c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        lm.waitForLayout(2);
2039c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar        checkForMainThreadException();
2040c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar    }
2041cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase
2042be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
20430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringLayout() throws Throwable {
20440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() {
20450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
20460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
20470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyDataSetChanged();
20480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
20490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
20500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
20510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() {
20520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
20530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
20540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemChanged(2);
20550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
20560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
20570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
20580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() {
20590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
20600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
20610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemInserted(2);
20620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
20630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
20640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() {
20650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
20660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void run() {
20670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mRecyclerView.getAdapter().notifyItemRemoved(2);
20680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
20690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        });
20700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
20710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
20720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void adapterChangeInMainThreadTest(String msg,
20730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            final Runnable onLayoutRunnable) throws Throwable {
20740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        final AtomicBoolean doneFirstLayout = new AtomicBoolean(false);
20750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestAdapter testAdapter = new TestAdapter(10);
20760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
20770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
20780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
20790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                super.onLayoutChildren(recycler, state);
20800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
20810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
20820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    if (doneFirstLayout.get()) {
20830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        onLayoutRunnable.run();
20840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    }
20850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
20860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
20870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
20880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
20890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
20900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
20910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
20920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        };
20930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
20940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setLayoutManager(lm);
20950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setAdapter(testAdapter);
20960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
20970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        setRecyclerView(recyclerView);
20980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
20990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        doneFirstLayout.set(true);
21000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
21010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        requestLayoutOnUIThread(recyclerView);
21020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
21030bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        removeRecyclerView();
21040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertTrue("Invalid data updates should be caught:" + msg,
21050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mainThreadException instanceof IllegalStateException);
21066b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        mainThreadException = null;
21070bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
21080bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2109be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
21100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void adapterChangeDuringScroll() throws Throwable {
21110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        for (int orientation : new int[]{OrientationHelper.HORIZONTAL,
21120bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                OrientationHelper.VERTICAL}) {
21130bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyDataSetChanged", orientation,
21140bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    new Runnable() {
21150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        @Override
21160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        public void run() {
21170bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            mRecyclerView.getAdapter().notifyDataSetChanged();
21180bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        }
21190bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    });
21200bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() {
21210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
21220bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
21230bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemChanged(2);
21240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
21250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
21260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() {
21280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
21290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
21300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemInserted(2);
21310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
21320bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
21330bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() {
21340bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                @Override
21350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                public void run() {
21360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    mRecyclerView.getAdapter().notifyItemRemoved(2);
21370bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
21380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            });
21390bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
21400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
21410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void adapterChangeDuringScrollTest(String msg, final int orientation,
21430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            final Runnable onScrollRunnable) throws Throwable {
21440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestAdapter testAdapter = new TestAdapter(100);
21450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
21460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
21470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
21480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                super.onLayoutChildren(recycler, state);
21490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
21500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutRange(recycler, 0, 10);
21510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
21520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
21530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
21540bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
21550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
21560bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21570bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21580bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
21590bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public boolean canScrollVertically() {
21600bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return orientation == OrientationHelper.VERTICAL;
21610bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21620bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21630bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
21640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public boolean canScrollHorizontally() {
21650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return orientation == OrientationHelper.HORIZONTAL;
21660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int mockScroll() {
21690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                try {
21700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    onScrollRunnable.run();
21710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } catch (Throwable t) {
21720bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    postExceptionToInstrumentation(t);
21730bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                } finally {
21740bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    layoutLatch.countDown();
21750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                }
21760bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return 0;
21770bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21780bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21790bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
21800bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
21810bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    RecyclerView.State state) {
21820bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return mockScroll();
21830bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21840bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
21850bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            @Override
21860bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
21870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                    RecyclerView.State state) {
21880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                return mockScroll();
21890bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            }
21900bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        };
21910bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        RecyclerView recyclerView = new RecyclerView(getActivity());
21920bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setLayoutManager(lm);
21930bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        recyclerView.setAdapter(testAdapter);
21940bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
21950bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        setRecyclerView(recyclerView);
21960bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
21970bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.expectLayouts(1);
21980bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        scrollBy(200);
21990bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        lm.waitForLayout(2);
22000bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        removeRecyclerView();
22010bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertTrue("Invalid data updates should be caught:" + msg,
22020bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                mainThreadException instanceof IllegalStateException);
22036b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        mainThreadException = null;
22040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
22050bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2206be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
22070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void recycleOnDetach() throws Throwable {
220849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
220949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final TestAdapter testAdapter = new TestAdapter(10);
221049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final AtomicBoolean didRunOnDetach = new AtomicBoolean(false);
221149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
221249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            @Override
221349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
221449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                super.onLayoutChildren(recycler, state);
221549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                layoutRange(recycler, 0, state.getItemCount() - 1);
221649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                layoutLatch.countDown();
221749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            }
221849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
221949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            @Override
222049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
222149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                super.onDetachedFromWindow(view, recycler);
222249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                didRunOnDetach.set(true);
222349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar                removeAndRecycleAllViews(recycler);
222449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            }
222549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        };
222649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        recyclerView.setAdapter(testAdapter);
222749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        recyclerView.setLayoutManager(lm);
222849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        lm.expectLayouts(1);
222949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        setRecyclerView(recyclerView);
223049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        lm.waitForLayout(2);
223149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        removeRecyclerView();
223249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get());
223349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        assertEquals("All children should be recycled", recyclerView.getChildCount(), 0);
223449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    }
22350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
2236be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
22370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updatesWhileDetached() throws Throwable {
2238bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2239bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int initialAdapterSize = 20;
2240bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
2241bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(0);
2242bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
2243bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
2244bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2245bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                super.onLayoutChildren(recycler, state);
2246bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutRange(recycler, 0, 5);
2247bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.incrementAndGet();
2248bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutLatch.countDown();
2249bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
2250bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        };
2251bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setAdapter(adapter);
2252bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setLayoutManager(lm);
2253bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setHasFixedSize(true);
2254bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
2255bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        adapter.addAndNotify(4, 5);
2256bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
2257bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar    }
2258bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar
2259be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
22600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updatesAfterDetach() throws Throwable {
2261bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2262bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int initialAdapterSize = 20;
2263bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
2264bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final AtomicInteger layoutCount = new AtomicInteger(0);
2265bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
2266bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
2267bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2268bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                super.onLayoutChildren(recycler, state);
2269bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutRange(recycler, 0, 5);
2270bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.incrementAndGet();
2271bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutLatch.countDown();
2272bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
2273bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        };
2274bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setAdapter(adapter);
2275bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setLayoutManager(lm);
2276bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
2277bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        recyclerView.setHasFixedSize(true);
2278bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        setRecyclerView(recyclerView);
2279bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.waitForLayout(2);
2280bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.expectLayouts(1);
2281bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        final int prevLayoutCount = layoutCount.get();
2282bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        runTestOnUiThread(new Runnable() {
2283bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            @Override
2284bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            public void run() {
2285bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                try {
2286bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                    adapter.addAndNotify(4, 5);
2287bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                    removeRecyclerView();
2288bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                } catch (Throwable throwable) {
228990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar                    postExceptionToInstrumentation(throwable);
2290bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                }
2291bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar            }
2292bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        });
229390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar        checkForMainThreadException();
2294bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar
2295bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
2296bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar        assertEquals("No extra layout should happen when detached", prevLayoutCount,
2297bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar                layoutCount.get());
2298bbf19899050278ae64da0a8bfce209a9f359c853Yigit Boyar    }
229949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
2300be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
23010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void notifyDataSetChangedWithStableIds() throws Throwable {
2302e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int defaultViewType = 1;
2303e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final Map<Item, Integer> viewTypeMap = new HashMap<Item, Integer>();
2304e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final Map<Integer, Integer> oldPositionToNewPositionMapping =
2305e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                new HashMap<Integer, Integer>();
2306e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
2307e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
2308e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public int getItemViewType(int position) {
2309e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                Integer type = viewTypeMap.get(mItems.get(position));
2310e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return type == null ? defaultViewType : type;
2311e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
2312e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
2313e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
2314e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public long getItemId(int position) {
2315e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                return mItems.get(position).mId;
2316e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
2317e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
2318e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        adapter.setHasStableIds(true);
2319e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final ArrayList<Item> previousItems = new ArrayList<Item>();
2320e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        previousItems.addAll(adapter.mItems);
2321e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
2322e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final AtomicInteger layoutStart = new AtomicInteger(50);
2323e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final AtomicBoolean validate = new AtomicBoolean(false);
2324e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final int childCount = 10;
2325e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
2326e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
2327e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2328e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                try {
2329e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    super.onLayoutChildren(recycler, state);
2330e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
2331e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("Cached views should be kept", 5, recycler
2332e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                .mCachedViews.size());
2333e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (RecyclerView.ViewHolder vh : recycler.mCachedViews) {
2334e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) vh;
23350bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            assertTrue("view holder should be marked for update",
23360bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                                    tvh.needsUpdate());
2337e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
2338e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        }
2339e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
2340e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    detachAndScrapAttachedViews(recycler);
2341e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
2342e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("cache size should stay the same", 5,
2343e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                recycler.mCachedViews.size());
2344e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        assertEquals("all views should be scrapped", childCount,
2345e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                recycler.getScrapList().size());
2346e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
2347e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            // TODO create test case for type change
2348e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) vh;
23490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            assertTrue("view holder should be marked for update",
23500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                                    tvh.needsUpdate());
2351e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
2352e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        }
2353e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
2354e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
2355e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    if (validate.get()) {
2356e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        for (int i = 0; i < getChildCount(); i++) {
2357e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            View view = getChildAt(i);
2358e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            TestViewHolder tvh = (TestViewHolder) mRecyclerView
2359e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                    .getChildViewHolder(view);
2360115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                            final int oldPos = previousItems.indexOf(tvh.mBoundItem);
2361e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            assertEquals("view holder's position should be correct",
2362e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                                    oldPositionToNewPositionMapping.get(oldPos).intValue(),
2363115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    tvh.getLayoutPosition());
23640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                            ;
23650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        }
2366e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
2367e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } catch (Throwable t) {
2368e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    postExceptionToInstrumentation(t);
2369e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } finally {
2370e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    layoutLatch.countDown();
2371e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                }
2372e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
2373e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        };
2374e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2375e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setItemAnimator(null);
2376e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setAdapter(adapter);
2377e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setLayoutManager(lm);
2378e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        recyclerView.setItemViewCacheSize(10);
2379e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
2380e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        setRecyclerView(recyclerView);
2381e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
2382e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
2383e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        getInstrumentation().waitForIdleSync();
2384e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        layoutStart.set(layoutStart.get() + 5);//55
2385e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
2386e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        requestLayoutOnUIThread(recyclerView);
2387e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
2388e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        validate.set(true);
2389e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.expectLayouts(1);
2390e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        runTestOnUiThread(new Runnable() {
2391e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            @Override
2392e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            public void run() {
2393e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                try {
2394e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    adapter.moveItems(false,
2395e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2},
2396e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64},
2397e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                            new int[]{75, 58});
2398e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    for (int i = 0; i < previousItems.size(); i++) {
2399e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        Item item = previousItems.get(i);
2400e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                        oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item));
2401e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    }
2402cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase                    adapter.dispatchDataSetChanged();
2403e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                } catch (Throwable throwable) {
2404e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                    postExceptionToInstrumentation(throwable);
2405e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar                }
2406e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar            }
2407e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        });
2408e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        lm.waitForLayout(2);
2409e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar        checkForMainThreadException();
2410e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar    }
2411e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar
2412be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
24130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void callbacksDuringAdapterSwap() throws Throwable {
2414824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        callbacksDuringAdapterChange(true);
2415824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
2416824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2417be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
24180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void callbacksDuringAdapterSet() throws Throwable {
2419824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        callbacksDuringAdapterChange(false);
2420824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
2421824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2422824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    public void callbacksDuringAdapterChange(boolean swap) throws Throwable {
2423824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter()
2424824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                : createOwnerCheckingAdapter();
2425824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter()
2426824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                : createOwnerCheckingAdapter();
2427824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2428824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
2429824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2430824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
2431824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                try {
2432824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
2433824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                } catch (Throwable t) {
2434824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    postExceptionToInstrumentation(t);
2435824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                }
2436824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                layoutLatch.countDown();
2437824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2438824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
2439824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
2440824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        rv.setAdapter(adapter1);
2441824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        rv.setLayoutManager(tlm);
2442824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.expectLayouts(1);
2443824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        setRecyclerView(rv);
2444824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.waitForLayout(1);
2445824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
2446824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.expectLayouts(1);
2447824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        if (swap) {
2448824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            swapAdapter(adapter2, true);
2449824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        } else {
2450824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            setAdapter(adapter2);
2451824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        }
2452824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
2453824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        tlm.waitForLayout(1);
2454824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        checkForMainThreadException();
2455824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
2456824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2457824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    private TestAdapter2 createOwnerCheckingAdapter() {
2458824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        return new TestAdapter2(10) {
2459824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2460824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onViewRecycled(TestViewHolder2 holder) {
2461824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on recycled should be called w/ the creator adapter", this,
2462824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        holder.mData);
2463824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onViewRecycled(holder);
2464824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2465824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2466824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2467824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onBindViewHolder(TestViewHolder2 holder, int position) {
2468824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onBindViewHolder(holder, position);
2469824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on bind should be called w/ the creator adapter", this, holder.mData);
2470824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2471824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2472824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2473824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
2474824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                    int viewType) {
2475824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType);
2476824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                vh.mData = this;
2477824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                return vh;
2478824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2479824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
2480824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
2481824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2482824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    private TestAdapter2 createBinderCheckingAdapter() {
2483824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        return new TestAdapter2(10) {
2484824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2485824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onViewRecycled(TestViewHolder2 holder) {
2486824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                assertSame("on recycled should be called w/ the creator adapter", this,
2487824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                        holder.mData);
2488824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                holder.mData = null;
2489824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onViewRecycled(holder);
2490824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2491824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2492824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            @Override
2493824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            public void onBindViewHolder(TestViewHolder2 holder, int position) {
2494824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                super.onBindViewHolder(holder, position);
2495824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar                holder.mData = this;
2496824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar            }
2497824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        };
2498824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar    }
2499824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
2500be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
25010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void findViewById() throws Throwable {
25025ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        findViewByIdTest(false);
25035ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        removeRecyclerView();
25045ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        findViewByIdTest(true);
25055ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    }
25065ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
25075ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    public void findViewByIdTest(final boolean supportPredictive) throws Throwable {
25085ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
25095ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int initialAdapterSize = 20;
25105ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
25115ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int deleteStart = 6;
25125ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final int deleteCount = 5;
25135ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        recyclerView.setAdapter(adapter);
25145ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        final AtomicBoolean assertPositions = new AtomicBoolean(false);
25155ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        TestLayoutManager lm = new TestLayoutManager() {
25165ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            @Override
25175ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
25185ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                super.onLayoutChildren(recycler, state);
25195ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                if (assertPositions.get()) {
25205ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    if (state.isPreLayout()) {
25210bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < deleteStart; i++) {
25225ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
25235ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull("find view by position for existing items should work "
25245ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    + "fine", view);
25255ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
25265ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
25275ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
25285ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
25290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < deleteCount; i++) {
25305ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i + deleteStart);
25315ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull("find view by position should work fine for removed "
25325ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    + "views in pre-layout", view);
25335ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertTrue("view should be marked as removed",
25345ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
25355ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
25365ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
25375ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        for (int i = deleteStart + deleteCount; i < 20; i++) {
25385ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
25395ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertNotNull(view);
25405ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
25415ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
25425ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
25435ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
25445ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    } else {
25450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar                        for (int i = 0; i < initialAdapterSize - deleteCount; i++) {
25465ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            View view = findViewByPosition(i);
2547fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar                            assertNotNull("find view by position for existing item " + i +
2548fe3996cf5af65fe11cc3ed47b67123ec267bd336Yigit Boyar                                    " should work fine. child count:" + getChildCount(), view);
25495ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            TestViewHolder viewHolder =
25505ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    (TestViewHolder) mRecyclerView.getChildViewHolder(view);
25515ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertSame("should be the correct item " + viewHolder
2552115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                                    , viewHolder.mBoundItem,
25535ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    adapter.mItems.get(viewHolder.mPosition));
25545ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                            assertFalse("view should not be marked as removed",
25555ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
25565ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                                            .isItemRemoved());
25575ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                        }
25585ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                    }
25595ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                }
25605ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                detachAndScrapAttachedViews(recycler);
25615ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                layoutRange(recycler, state.getItemCount() - 1, -1);
25625ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                layoutLatch.countDown();
25635ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            }
25645ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
25655ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            @Override
25665ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
25675ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar                return supportPredictive;
25685ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar            }
25695ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        };
25705ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        recyclerView.setLayoutManager(lm);
25715ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.expectLayouts(1);
25725ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        setRecyclerView(recyclerView);
25735ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.waitForLayout(2);
25745ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        getInstrumentation().waitForIdleSync();
25755ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
25765ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        assertPositions.set(true);
25775ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.expectLayouts(supportPredictive ? 2 : 1);
25785ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1});
25795ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar        lm.waitForLayout(2);
25805ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar    }
25815ced882cabdcefbb469e332f6f73983999aad0e5Yigit Boyar
2582be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
25830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void typeForCache() throws Throwable {
258422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final AtomicInteger viewType = new AtomicInteger(1);
258522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
258622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
258722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public int getItemViewType(int position) {
258822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                return viewType.get();
258922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
259022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
259122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
259222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public long getItemId(int position) {
259322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                return mItems.get(position).mId;
259422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
259522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        };
259622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        adapter.setHasStableIds(true);
259722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final AtomicInteger layoutStart = new AtomicInteger(2);
259822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final int childCount = 10;
259922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
260022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
260122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
260222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                super.onLayoutChildren(recycler, state);
260322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                detachAndScrapAttachedViews(recycler);
260422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
260522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                layoutLatch.countDown();
260622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
260722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        };
260822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2609668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        recyclerView.setItemAnimator(null);
261022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setAdapter(adapter);
261122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setLayoutManager(lm);
261222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        recyclerView.setItemViewCacheSize(10);
261322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
261422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        setRecyclerView(recyclerView);
261522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
261622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        getInstrumentation().waitForIdleSync();
261722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        layoutStart.set(4); // trigger a cache for 3,4
261822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
261922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        requestLayoutOnUIThread(recyclerView);
262022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
262122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        //
262222b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        viewType.incrementAndGet();
262322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        layoutStart.set(2); // go back to bring views from cache
262422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.expectLayouts(1);
262522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        adapter.mItems.remove(1);
2626cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.dispatchDataSetChanged();
262722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        lm.waitForLayout(2);
262822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        runTestOnUiThread(new Runnable() {
262922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            @Override
263022b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            public void run() {
263122b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                for (int i = 2; i < 4; i++) {
2632115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                    RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i);
263322b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                    assertEquals("View holder's type should match latest type", viewType.get(),
263422b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                            vh.getItemViewType());
263522b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar                }
263622b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar            }
263722b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar        });
263822b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar    }
263922b6b8163d2e15eb6d0a89906854dec801945f1dYigit Boyar
2640be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
26410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void typeForExistingViews() throws Throwable {
26427e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final AtomicInteger viewType = new AtomicInteger(1);
26437e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int invalidatedCount = 2;
26447e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int layoutStart = 2;
26457e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final TestAdapter adapter = new TestAdapter(100) {
26467e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
26477e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public int getItemViewType(int position) {
26487e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                return viewType.get();
26497e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
26507e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
26517e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
26527e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
26537e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    int position) {
26547e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                super.onBindViewHolder(holder, position);
26557e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                if (position >= layoutStart && position < invalidatedCount + layoutStart) {
26567e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    try {
26577e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                        assertEquals("holder type should match current view type at position " +
26587e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                                position, viewType.get(), holder.getItemViewType());
26597e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    } catch (Throwable t) {
26607e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                        postExceptionToInstrumentation(t);
26617e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                    }
26627e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                }
26637e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
26647e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
26657e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
26667e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public long getItemId(int position) {
26677e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                return mItems.get(position).mId;
26687e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
26697e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        };
26707e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        adapter.setHasStableIds(true);
26717e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
26727e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final int childCount = 10;
26737e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final TestLayoutManager lm = new TestLayoutManager() {
26747e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            @Override
26757e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
26767e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                super.onLayoutChildren(recycler, state);
26777e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                detachAndScrapAttachedViews(recycler);
26787e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                layoutRange(recycler, layoutStart, layoutStart + childCount);
26797e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar                layoutLatch.countDown();
26807e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar            }
26817e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        };
26827e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
26837e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        recyclerView.setAdapter(adapter);
26847e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        recyclerView.setLayoutManager(lm);
26857e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.expectLayouts(1);
26867e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        setRecyclerView(recyclerView);
26877e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.waitForLayout(2);
26887e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        getInstrumentation().waitForIdleSync();
26897e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        viewType.incrementAndGet();
26907e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.expectLayouts(1);
2691cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase        adapter.changeAndNotify(layoutStart, invalidatedCount);
26927e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        lm.waitForLayout(2);
26937e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar        checkForMainThreadException();
26947e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar    }
26957e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
26967e9da1a2629b657d56e2f54abd18c6249f3be037Yigit Boyar
2697be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
26980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void state() throws Throwable {
2699d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final TestAdapter adapter = new TestAdapter(10);
2700d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final RecyclerView recyclerView = new RecyclerView(getActivity());
2701d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setAdapter(adapter);
2702d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setItemAnimator(null);
2703d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final AtomicInteger itemCount = new AtomicInteger();
2704d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final AtomicBoolean structureChanged = new AtomicBoolean();
2705d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        TestLayoutManager testLayoutManager = new TestLayoutManager() {
2706d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
2707d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
27088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar                detachAndScrapAttachedViews(recycler);
2709d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                layoutRange(recycler, 0, state.getItemCount());
2710d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.set(state.getItemCount());
2711d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.set(state.didStructureChange());
2712d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                layoutLatch.countDown();
2713d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
2714d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        };
2715d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        recyclerView.setLayoutManager(testLayoutManager);
2716d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        testLayoutManager.expectLayouts(1);
2717d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        runTestOnUiThread(new Runnable() {
2718d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
2719d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void run() {
2720d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                getActivity().mContainer.addView(recyclerView);
2721d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
2722d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        });
2723d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        testLayoutManager.waitForLayout(2, TimeUnit.SECONDS);
2724d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
2725d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("item count in state should be correct", adapter.getItemCount()
2726d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                , itemCount.get());
2727d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true for first layout", true,
2728d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
2729d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        Thread.sleep(1000); //wait for other layouts.
2730d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        testLayoutManager.expectLayouts(1);
2731d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        runTestOnUiThread(new Runnable() {
2732d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
2733d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void run() {
2734d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                recyclerView.requestLayout();
2735d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
2736d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        });
27378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
2738d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("in second layout,structure changed should be false", false,
2739d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
27408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.expectLayouts(1); //
2741b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        adapter.deleteAndNotify(3, 2);
27428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
2743d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("when items are removed, item count in state should be updated",
2744d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adapter.getItemCount(),
2745d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.get());
2746d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true when items are removed", true,
2747d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
27488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.expectLayouts(1);
2749b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        adapter.addAndNotify(2, 5);
27508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar        testLayoutManager.waitForLayout(2);
2751d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
2752d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("when items are added, item count in state should be updated",
2753d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adapter.getItemCount(),
2754d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                itemCount.get());
2755d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        assertEquals("structure changed should be true when items are removed", true,
2756d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                structureChanged.get());
27570b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
27580b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
2759be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
27600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void detachWithoutLayoutManager() throws Throwable {
2761abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
2762abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        runTestOnUiThread(new Runnable() {
2763abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            @Override
2764abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            public void run() {
2765abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                try {
2766abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    setRecyclerView(recyclerView);
2767abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    removeRecyclerView();
2768abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                } catch (Throwable t) {
2769abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                    postExceptionToInstrumentation(t);
2770abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar                }
2771abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar            }
2772abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        });
2773abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        checkForMainThreadException();
2774abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
2775abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
2776be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
27770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void updateHiddenView() throws Throwable {
27781a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final RecyclerView.ViewHolder[] mTargetVH = new RecyclerView.ViewHolder[1];
27791a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
27801a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final int[] preLayoutRange = new int[]{0, 10};
27811a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final int[] postLayoutRange = new int[]{0, 10};
27821a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final AtomicBoolean enableGetViewTest = new AtomicBoolean(false);
27831a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final List<Integer> disappearingPositions = new ArrayList<Integer>();
27841a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final TestLayoutManager tlm = new TestLayoutManager() {
27851a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
27861a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
27871a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                return true;
27881a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
27891a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
27901a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
27911a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
27921a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                try {
27931a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    final int[] layoutRange = state.isPreLayout() ? preLayoutRange
27941a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            : postLayoutRange;
27951a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    detachAndScrapAttachedViews(recycler);
27961a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    layoutRange(recycler, layoutRange[0], layoutRange[1]);
27971a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    if (!state.isPreLayout()) {
27981a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                        for (Integer position : disappearingPositions) {
27991a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            // test sanity.
28001a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            assertNull(findViewByPosition(position));
28011a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            final View view = recycler.getViewForPosition(position);
28021a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            addDisappearingView(view);
28031a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            measureChildWithMargins(view, 0, 0);
28041a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            // position item out of bounds.
28051a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                            view.layout(0, -500, view.getMeasuredWidth(),
28061a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                                    -500 + view.getMeasuredHeight());
28071a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                        }
28081a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    }
28091a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                } catch (Throwable t) {
28101a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    postExceptionToInstrumentation(t);
28111a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                }
28121a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                layoutLatch.countDown();
28131a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
28141a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        };
28151a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
28161a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.getItemAnimator().setMoveDuration(2000);
28171a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.getItemAnimator().setRemoveDuration(2000);
28181a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        final TestAdapter adapter = new TestAdapter(100);
28191a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.setAdapter(adapter);
28201a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        recyclerView.setLayoutManager(tlm);
28211a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(1);
28221a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        setRecyclerView(recyclerView);
28231a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
28241a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(1);
28251a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
28261a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        mTargetVH[0] = recyclerView.findViewHolderForAdapterPosition(0);
28271a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // now, a child disappears
28281a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        disappearingPositions.add(0);
28291a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // layout one shifted
28301a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        postLayoutRange[0] = 1;
28311a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        postLayoutRange[1] = 11;
28321a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(2);
28331a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        adapter.addAndNotify(8, 1);
28341a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(2);
28351a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
28361a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
28371a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.expectLayouts(2);
28381a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        disappearingPositions.clear();
28391a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        // now that item should be moving, invalidate it and delete it.
28401a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        enableGetViewTest.set(true);
28411a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        runTestOnUiThread(new Runnable() {
28421a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            @Override
28431a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            public void run() {
28441a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                try {
28451a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    adapter.changeAndNotify(0, 1);
28461a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    adapter.deleteAndNotify(0, 1);
28471a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                } catch (Throwable throwable) {
28481a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                    throwable.printStackTrace();
28491a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar                }
28501a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar            }
28511a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        });
28521a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        tlm.waitForLayout(2);
28531a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar        checkForMainThreadException();
28541a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar    }
28551a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
2856be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnTop() throws Throwable {
28586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.TOP);
28596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2861be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnLeft() throws Throwable {
28636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.LEFT);
28646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2866be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnRight() throws Throwable {
28686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.RIGHT);
28696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2871be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnBottom() throws Throwable {
28736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.BOTTOM);
28746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2876be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnLeftRTL() throws Throwable {
28786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.LEFT, true);
28796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
28806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                mRecyclerView.getLayoutManager().getLayoutDirection());
28816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2883be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
28840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusBigViewOnRightRTL() throws Throwable {
28856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(Gravity.RIGHT, true);
28866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
28876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                mRecyclerView.getLayoutManager().getLayoutDirection());
28886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
28896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
28906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    public void focusTooBigViewTest(final int gravity) throws Throwable {
28916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        focusTooBigViewTest(gravity, false);
28926d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
2893be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar
28946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable {
28956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
28966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        if (rtl) {
28976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL);
28986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        }
28996d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger vScrollDist = new AtomicInteger(0);
29006d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger hScrollDist = new AtomicInteger(0);
29016d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger vDesiredDist = new AtomicInteger(0);
29026d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        final AtomicInteger hDesiredDist = new AtomicInteger(0);
29036d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
29046d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29056d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29066d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int getLayoutDirection() {
29076d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
29086d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29096d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29106d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29116d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
29126d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                detachAndScrapAttachedViews(recycler);
29136d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                final View view = recycler.getViewForPosition(0);
29146d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                addView(view);
29156d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                int left = 0, top = 0;
29166d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                view.setBackgroundColor(Color.rgb(0, 0, 255));
29176d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                switch (gravity) {
29186d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.LEFT:
29196d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.RIGHT:
29206d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        view.measure(
29216d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5),
29226d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.EXACTLY),
29236d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9),
29246d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.AT_MOST));
29256d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80
29266d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                : 90;
29276d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top = 0;
29286d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) {
29296d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                            hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth());
29306d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        } else {
29316d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                            hDesiredDist.set(left);
29326d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        }
29336d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        break;
29346d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.TOP:
29356d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    case Gravity.BOTTOM:
29366d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        view.measure(
29376d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9),
29386d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.AT_MOST),
29396d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5),
29406d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                        View.MeasureSpec.EXACTLY));
29416d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() -
29426d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                                80 : 90;
29436d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        left = 0;
29446d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        vDesiredDist.set(top);
29456d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        break;
29466d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                }
29476d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29486d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                view.layout(left, top, left + view.getMeasuredWidth(),
29496d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                        top + view.getMeasuredHeight());
29506d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                layoutLatch.countDown();
29516d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29526d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29536d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29546d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public boolean canScrollVertically() {
29556d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return true;
29566d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29576d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29586d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29596d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public boolean canScrollHorizontally() {
29606d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return super.canScrollHorizontally();
29616d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29626d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29636d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29646d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
29656d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    RecyclerView.State state) {
29666d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                vScrollDist.addAndGet(dy);
29676d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                getChildAt(0).offsetTopAndBottom(-dy);
29686d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return dy;
29696d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29706d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
29716d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            @Override
29726d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
29736d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                    RecyclerView.State state) {
29746d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                hScrollDist.addAndGet(dx);
29756d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                getChildAt(0).offsetLeftAndRight(-dx);
29766d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar                return dx;
29776d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            }
29786d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        };
29796d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
29806d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        rv.setAdapter(adapter);
29816d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        rv.setLayoutManager(tlm);
29826d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        tlm.expectLayouts(1);
29836d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        setRecyclerView(rv);
29846d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        tlm.waitForLayout(2);
29856d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        View view = rv.getChildAt(0);
29866d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        requestFocus(view);
29876d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        Thread.sleep(1000);
29886d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(vDesiredDist.get(), vScrollDist.get());
29896d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(hDesiredDist.get(), hScrollDist.get());
29906d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        assertEquals(mRecyclerView.getPaddingTop(), view.getTop());
29916d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        if (rtl) {
2992be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar            assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
2993be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar                    view.getRight());
29946d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        } else {
29956d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar            assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft());
29966d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar        }
29976d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar    }
29986d109dd6676f6bca949643d2d04365494eaeb867Yigit Boyar
2999be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
30000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void firstLayoutWithAdapterChanges() throws Throwable {
30014bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        final TestAdapter adapter = new TestAdapter(0);
30024bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
30034bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        setVisibility(rv, View.GONE);
30044bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
30054bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
30064bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
30074bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                try {
30084bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    super.onLayoutChildren(recycler, state);
30094bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    layoutRange(recycler, 0, state.getItemCount());
30104bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } catch (Throwable t) {
30114bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    postExceptionToInstrumentation(t);
30124bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } finally {
30134bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    layoutLatch.countDown();
30144bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                }
30154bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
30164bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar
30174bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
30184bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public boolean supportsPredictiveItemAnimations() {
30194bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                return true;
30204bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
30214bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        };
30224bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setLayoutManager(tlm);
30234bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setAdapter(adapter);
30244bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        rv.setHasFixedSize(true);
30254bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        setRecyclerView(rv);
30264bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.expectLayouts(1);
30274bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.assertNoLayout("test sanity, layout should not run", 1);
30284bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        getInstrumentation().waitForIdleSync();
30294bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        runTestOnUiThread(new Runnable() {
30304bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            @Override
30314bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            public void run() {
30324bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                try {
30334bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    adapter.addAndNotify(2);
30344bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                } catch (Throwable throwable) {
30354bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                    throwable.printStackTrace();
30364bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                }
30374bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar                rv.setVisibility(View.VISIBLE);
30384bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar            }
30394bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        });
30404bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        checkForMainThreadException();
30414bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        tlm.waitForLayout(2);
30424bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        assertEquals(2, rv.getChildCount());
30434bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar        checkForMainThreadException();
30444bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar    }
30454bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar
30464bcf88a56f3048a7ead6f423faa8fa08b95c5daeYigit Boyar    @Test
304714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    public void computeScrollOfsetWithoutLayoutManager() throws Throwable {
304814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
304914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        rv.setAdapter(new TestAdapter(10));
305014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        setRecyclerView(rv);
305114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollExtent());
305214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollOffset());
305314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollRange());
305414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
305514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollExtent());
305614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollOffset());
305714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollRange());
305814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    }
305914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
306014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    @Test
306114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    public void computeScrollOfsetWithoutAdapter() throws Throwable {
306214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
306314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        rv.setLayoutManager(new TestLayoutManager());
306414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        setRecyclerView(rv);
306514d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollExtent());
306614d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollOffset());
306714d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeHorizontalScrollRange());
306814d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
306914d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollExtent());
307014d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollOffset());
307114d75838c4578e079d75ea149e9833250c5d741bYigit Boyar        assertEquals(0, rv.computeVerticalScrollRange());
307214d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    }
307314d75838c4578e079d75ea149e9833250c5d741bYigit Boyar
307414d75838c4578e079d75ea149e9833250c5d741bYigit Boyar    @Test
30750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusRectOnScreenWithDecorOffsets() throws Throwable {
3076f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        focusRectOnScreenTest(true);
3077f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3078f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3079be7a54a6e02c9230a08e63f1c964907d129b6a10Yigit Boyar    @Test
30800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void focusRectOnScreenWithout() throws Throwable {
3081f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        focusRectOnScreenTest(false);
3082f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3083f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3084f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable {
3085f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
3086f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        final AtomicInteger scrollDist = new AtomicInteger(0);
3087f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3088f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3089f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3090f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                detachAndScrapAttachedViews(recycler);
3091f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                final View view = recycler.getViewForPosition(0);
3092f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                addView(view);
3093f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                measureChildWithMargins(view, 0, 0);
3094f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                view.layout(0, -20, view.getWidth(),
3095f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                        -20 + view.getHeight());// ignore decors on purpose
3096f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                layoutLatch.countDown();
3097f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3098f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3099f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3100f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public boolean canScrollVertically() {
3101f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                return true;
3102f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3103f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3104f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            @Override
3105f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
3106f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                    RecyclerView.State state) {
3107f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                scrollDist.addAndGet(dy);
3108f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                return dy;
3109f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            }
3110f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        };
3111f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        TestAdapter adapter = new TestAdapter(10);
3112f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        if (addItemDecors) {
3113f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
3114f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                @Override
3115f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
3116f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                        RecyclerView.State state) {
3117f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                    outRect.set(0, 10, 0, 10);
3118f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar                }
3119f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar            });
3120f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        }
3121f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        rv.setAdapter(adapter);
3122f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        rv.setLayoutManager(tlm);
3123f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        tlm.expectLayouts(1);
3124f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        setRecyclerView(rv);
3125f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        tlm.waitForLayout(2);
3126f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3127f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        View view = rv.getChildAt(0);
3128f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        requestFocus(view);
3129f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        Thread.sleep(1000);
3130f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar        assertEquals(addItemDecors ? -30 : -20, scrollDist.get());
3131f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar    }
3132f225a3b785fe24c31aa5f75501754b974e106859Yigit Boyar
3133e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
31340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void unimplementedSmoothScroll() throws Throwable {
3135e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1);
3136e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1);
3137e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final CountDownLatch cbLatch = new CountDownLatch(2);
3138e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3139e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3140e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3141e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                detachAndScrapAttachedViews(recycler);
3142e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutRange(recycler, 0, 10);
3143e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutLatch.countDown();
3144e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3145e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3146e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3147e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
3148e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    int position) {
3149e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                assertEquals(-1, receivedSmoothScrollToPosition.get());
3150e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedSmoothScrollToPosition.set(position);
3151e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                RecyclerView.SmoothScroller ss =
3152e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
3153e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
3154e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
3155e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                return null;
3156e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
3157e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        };
3158e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                ss.setTargetPosition(position);
3159e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                startSmoothScroll(ss);
3160e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                cbLatch.countDown();
3161e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3162e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3163e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3164e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void scrollToPosition(int position) {
3165e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                assertEquals(-1, receivedScrollToPosition.get());
3166e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedScrollToPosition.set(position);
3167e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                cbLatch.countDown();
3168e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3169e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        };
3170e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        RecyclerView rv = new RecyclerView(getActivity());
3171e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setAdapter(new TestAdapter(100));
3172e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setLayoutManager(tlm);
3173e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.expectLayouts(1);
3174e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        setRecyclerView(rv);
3175e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.waitForLayout(2);
3176ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(true);
3177ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        smoothScrollToPosition(35);
3178ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        assertEquals("smoothScrollToPosition should be ignored when frozen",
3179ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu                -1, receivedSmoothScrollToPosition.get());
3180ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu        freezeLayout(false);
3181e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        smoothScrollToPosition(35);
3182e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS));
3183e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        checkForMainThreadException();
3184e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(35, receivedSmoothScrollToPosition.get());
3185e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(35, receivedScrollToPosition.get());
3186e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3187e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3188e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
31890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void jumpingJackSmoothScroller() throws Throwable {
3190e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        jumpingJackSmoothScrollerTest(true);
3191e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3192e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3193e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    @Test
31940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void jumpingJackSmoothScrollerGoesIdle() throws Throwable {
3195e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        jumpingJackSmoothScrollerTest(false);
3196e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3197e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3198e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable {
3199e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final List<Integer> receivedScrollToPositions = new ArrayList<>();
3200e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final TestAdapter testAdapter = new TestAdapter(200);
3201e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final AtomicBoolean mTargetFound = new AtomicBoolean(false);
3202e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        TestLayoutManager tlm = new TestLayoutManager() {
3203e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            int pendingScrollPosition = -1;
3204e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3205e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
3206e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                detachAndScrapAttachedViews(recycler);
3207e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition;
3208e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                layoutRange(recycler, pos, pos + 10);
3209e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                if (layoutLatch != null) {
3210e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    layoutLatch.countDown();
3211e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                }
3212e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3213e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3214e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3215e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
3216e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                    final int position) {
3217e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                RecyclerView.SmoothScroller ss =
3218e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        new LinearSmoothScroller(recyclerView.getContext()) {
3219e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
3220e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            public PointF computeScrollVectorForPosition(int targetPosition) {
3221e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                return new PointF(0, 1);
3222e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
3223e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3224e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
3225e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            protected void onTargetFound(View targetView, RecyclerView.State state,
3226e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                         Action action) {
3227e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                super.onTargetFound(targetView, state, action);
3228e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                mTargetFound.set(true);
3229e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
3230e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3231e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            @Override
3232e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            protected void updateActionForInterimTarget(Action action) {
3233e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                int limit = succeed ? getTargetPosition() : 100;
3234e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                if (pendingScrollPosition + 2 < limit) {
3235e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    if (pendingScrollPosition != NO_POSITION) {
3236e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                        assertEquals(pendingScrollPosition,
3237e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                getChildViewHolderInt(getChildAt(0))
3238e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                                        .getAdapterPosition());
3239e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    }
3240e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                    action.jumpTo(pendingScrollPosition + 2);
3241e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                                }
3242e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                            }
3243e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                        };
3244e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                ss.setTargetPosition(position);
3245e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                startSmoothScroll(ss);
3246e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3247e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3248e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3249e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void scrollToPosition(int position) {
3250e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                receivedScrollToPositions.add(position);
3251e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                pendingScrollPosition = position;
3252e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                requestLayout();
3253e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3254e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        };
3255e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        final RecyclerView rv = new RecyclerView(getActivity());
3256e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setAdapter(testAdapter);
3257e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        rv.setLayoutManager(tlm);
3258e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3259e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.expectLayouts(1);
3260e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        setRecyclerView(rv);
3261e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        tlm.waitForLayout(2);
3262e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3263e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        runTestOnUiThread(new Runnable() {
3264e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            @Override
3265e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            public void run() {
3266e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar                rv.smoothScrollToPosition(150);
3267e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            }
3268e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        });
3269e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        int limit = 100;
3270e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) {
3271e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            Thread.sleep(200);
3272e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            checkForMainThreadException();
3273e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        }
3274e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        checkForMainThreadException();
3275e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertTrue(limit > 0);
3276e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        for (int i = 1; i < 100; i+=2) {
3277e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar            assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i));
3278e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        }
3279e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3280e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar        assertEquals(succeed, mTargetFound.get());
3281e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
3282e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar    }
3283e1cd8d86d84646768867eeaeb038e1c135ca3e4cYigit Boyar
32840b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private static class TestViewHolder2 extends RecyclerView.ViewHolder {
3285824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
3286824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar        Object mData;
3287824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
32880b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public TestViewHolder2(View itemView) {
32890b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            super(itemView);
32900b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
32910b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    }
3292d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
32930b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar    private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> {
3294824a7db96feacf3b68f56993ed72712bc935153eYigit Boyar
32950b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        List<Item> mItems;
32960b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
32970b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        private TestAdapter2(int count) {
32980b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            mItems = new ArrayList<Item>(count);
32990b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            for (int i = 0; i < count; i++) {
33000b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                mItems.add(new Item(i, "Item " + i));
33010b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            }
33020b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
33030b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
33040b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
33050b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
33060b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar                int viewType) {
33070b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            return new TestViewHolder2(new TextView(parent.getContext()));
33080b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
33090b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
33100b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
33110b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public void onBindViewHolder(TestViewHolder2 holder, int position) {
33120b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            final Item item = mItems.get(position);
33130b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")");
33140b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
33150b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar
33160b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        @Override
33170b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        public int getItemCount() {
33180b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar            return mItems.size();
33190b1059b711009601ff08354e2df6bfc45266e80aYigit Boyar        }
3320d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
3321d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
3322115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    private static interface AdapterRunnable {
33231a2a95faea3d32075b8506f13f6d6f8292db51b6Yigit Boyar
33243d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        void run(TestAdapter adapter) throws Throwable;
3325115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar    }
3326115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar
33273d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    public class LayoutAllLayoutManager extends TestLayoutManager {
33283d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        @Override
33293d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
33303d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            layoutRange(recycler, 0, state.getItemCount());
33313d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar            layoutLatch.countDown();
33323d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar        }
33333d37afbbf7bf547c1e1c541df9be9696da668884Yigit Boyar    }
33347a59e4b36500bcfddd842376d6c3abe0d9f23d84Yigit Boyar}
3335