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