1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.widget;
18
19import static org.hamcrest.CoreMatchers.is;
20import static org.hamcrest.MatcherAssert.assertThat;
21
22import android.os.Build;
23import android.support.test.filters.SdkSuppress;
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26
27import org.junit.Test;
28import org.junit.runner.RunWith;
29
30import java.util.ArrayList;
31import java.util.concurrent.CountDownLatch;
32import java.util.concurrent.TimeUnit;
33
34@SmallTest
35@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
36@RunWith(AndroidJUnit4.class)
37public class RecyclerViewPrefetchTest extends BaseRecyclerViewInstrumentationTest {
38    private class PrefetchLayoutManager extends TestLayoutManager {
39        CountDownLatch prefetchLatch = new CountDownLatch(1);
40
41        @Override
42        public boolean canScrollVertically() {
43            return true;
44        }
45
46        @Override
47        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
48            super.onLayoutChildren(recycler, state);
49            detachAndScrapAttachedViews(recycler);
50            layoutRange(recycler, 0, 5);
51        }
52
53        @Override
54        public void onLayoutCompleted(RecyclerView.State state) {
55            super.onLayoutCompleted(state);
56            layoutLatch.countDown();
57        }
58
59        @Override
60        public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
61                LayoutPrefetchRegistry layoutPrefetchRegistry) {
62            prefetchLatch.countDown();
63            layoutPrefetchRegistry.addPosition(6, 0);
64        }
65
66        void waitForPrefetch(int time) throws InterruptedException {
67            assertThat(prefetchLatch.await(time, TimeUnit.SECONDS),
68                    is(true));
69            getInstrumentation().runOnMainSync(new Runnable() {
70                @Override
71                public void run() {
72                }
73            });
74        }
75    }
76
77    private ArrayList<RecyclerView.ViewHolder> cachedViews() {
78        return mRecyclerView.mRecycler.mCachedViews;
79    }
80
81    @Test
82    public void prefetchTest() throws Throwable {
83        RecyclerView recyclerView = new RecyclerView(getActivity());
84        recyclerView.setAdapter(new TestAdapter(50));
85        PrefetchLayoutManager layout = new PrefetchLayoutManager();
86        recyclerView.setLayoutManager(layout);
87
88        {
89            layout.expectLayouts(1);
90            setRecyclerView(recyclerView);
91            layout.waitForLayout(10);
92        }
93
94        assertThat(layout.prefetchLatch.getCount(), is(1L)); // shouldn't have fired yet
95        assertThat(cachedViews().size(), is(0));
96        smoothScrollBy(50);
97
98        layout.waitForPrefetch(10);
99        assertThat(cachedViews().size(), is(1));
100        assertThat(cachedViews().get(0).getAdapterPosition(), is(6));
101    }
102}