1ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik/*
2ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * Copyright (C) 2016 The Android Open Source Project
3ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik *
4ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * you may not use this file except in compliance with the License.
6ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * You may obtain a copy of the License at
7ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik *
8ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik *
10ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * Unless required by applicable law or agreed to in writing, software
11ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * See the License for the specific language governing permissions and
14ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik * limitations under the License.
15ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik */
16ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
17ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikpackage android.support.v7.widget;
18ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
19e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
20e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static android.support.v7.widget.LinearLayoutManager.VERTICAL;
21e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas
22e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertEquals;
23e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas
24ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport android.os.Build;
25754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest;
26ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport android.support.test.filters.SdkSuppress;
27ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
28ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport org.junit.Test;
29ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport org.junit.runner.RunWith;
30ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport org.junit.runners.Parameterized;
31ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
32ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport java.util.ArrayList;
33ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport java.util.List;
34ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikimport java.util.concurrent.TimeUnit;
35ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
36ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik@RunWith(Parameterized.class)
37ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
38ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craikpublic class LinearLayoutManagerCacheTest extends BaseLinearLayoutManagerTest {
39ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
40ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    final Config mConfig;
41ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    final int mDx;
42ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    final int mDy;
43ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
44ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    public LinearLayoutManagerCacheTest(Config config, int dx, int dy) {
45ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        mConfig = config;
46ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        mDx = dx;
47ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        mDy = dy;
48ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
49ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
50e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas    @Parameterized.Parameters(name = "config:{0},dx:{1},dy:{2}")
51ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    public static List<Object[]> getParams() {
52ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        List<Object[]> result = new ArrayList<>();
53ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        List<Config> configs = createBaseVariations();
54ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        for (Config config : configs) {
55ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            for (int dx : new int[] {-1, 0, 1}) {
56ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                for (int dy : new int[] {-1, 0, 1}) {
57ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    result.add(new Object[]{config, dx, dy});
58ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                }
59ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            }
60ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        }
61ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        return result;
62ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
63ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
64ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    private ArrayList<RecyclerView.ViewHolder> cachedViews() {
65ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        return mRecyclerView.mRecycler.mCachedViews;
66ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
67ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
68ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    @MediumTest
69ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    @Test
70ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    public void cacheAndPrefetch() throws Throwable {
71ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        final Config config = (Config) mConfig.clone();
72ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
73ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        setupByConfig(config, true);
74ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
7542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas        mActivityRule.runOnUiThread(new Runnable() {
76ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            @Override
77ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            public void run() {
78ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                // pretend to have an extra 5s before next frame so prefetch won't abort early
79ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                ((WrappedRecyclerView)mRecyclerView).setDrawingTimeOffset(5000);
80ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
81ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                mRecyclerView.scrollToPosition(100);
82ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            }
83ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        });
84ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
85ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        mRecyclerView.setItemViewCacheSize(0);
86ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        {
87ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            mLayoutManager.expectPrefetch(1);
8842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas            mActivityRule.runOnUiThread(new Runnable() {
89ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                @Override
90ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                public void run() {
91ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    mRecyclerView.mRecycler.recycleAndClearCachedViews();
9207b2e072ee7e8f424eb95abc77695dc2c5a786bbChris Craik                    mRecyclerView.mGapWorker.postFromTraversal(mRecyclerView, mDx, mDy);
93ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
94ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    // Lie about post time, so prefetch executes even if it is delayed
9507b2e072ee7e8f424eb95abc77695dc2c5a786bbChris Craik                    mRecyclerView.mGapWorker.mPostTimeNs += TimeUnit.SECONDS.toNanos(5);
96ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                }
97ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            });
98ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            mLayoutManager.waitForPrefetch(1);
99ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        }
100ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
101ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
10242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas        mActivityRule.runOnUiThread(new Runnable() {
103ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            @Override
104ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            public void run() {
105ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                // validate cache state on UI thread
106ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                if ((config.mOrientation == HORIZONTAL && mDx == 0)
107ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                        || (config.mOrientation == VERTICAL && mDy == 0)) {
108ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    assertEquals(0, cachedViews().size());
109ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                } else {
110ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    boolean reverseScroll = config.mOrientation == HORIZONTAL ? mDx < 0 : mDy < 0;
111ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
112ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();
113ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    assertEquals(1, cachedViews().size());
114ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    int prefetchedPosition = cachedViews().get(0).getAdapterPosition();
115ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    if (mConfig.mReverseLayout == reverseScroll) {
116ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                        // Pos scroll on pos layout, or reverse scroll on reverse layout = toward last
117ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                        assertEquals(lastVisibleItemPosition + 1, prefetchedPosition);
118ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    } else {
119ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                        // Pos scroll on reverse layout, or reverse scroll on pos layout = toward first
120ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                        assertEquals(firstVisibleItemPosition - 1, prefetchedPosition);
121ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                    }
122ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik                }
123ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik            }
124ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        });
125ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
126ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik}
127