1a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev/* 2a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Copyright (C) 2015 The Android Open Source Project 3a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 4a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Licensed under the Apache License, Version 2.0 (the "License"); 5a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * you may not use this file except in compliance with the License. 6a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * You may obtain a copy of the License at 7a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 8a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * http://www.apache.org/licenses/LICENSE-2.0 9a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * 10a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * Unless required by applicable law or agreed to in writing, software 11a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * distributed under the License is distributed on an "AS IS" BASIS, 12a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * See the License for the specific language governing permissions and 14a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev * limitations under the License. 15a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev */ 16a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 17a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevpackage android.support.v7.util; 18a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 19754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertEquals; 20754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertTrue; 21754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 22754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.annotation.UiThread; 23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest; 24e310cf31070baf35a7e9eedf9528d3c2927db6c7Aurimas Liutikasimport android.support.test.filters.Suppress; 2542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport android.support.test.rule.ActivityTestRule; 2642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport android.support.v7.widget.TestActivity; 27754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.util.SparseBooleanArray; 28754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.After; 300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Before; 3142e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikasimport org.junit.Rule; 320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Test; 330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runner.RunWith; 340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runners.JUnit4; 350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 36a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.concurrent.CountDownLatch; 37a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheevimport java.util.concurrent.TimeUnit; 38a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 395752abaccbb000adf2e4369ceff6e747da12e2f5Aurimas Liutikas// This test is disabled as it is flaky. 405752abaccbb000adf2e4369ceff6e747da12e2f5Aurimas Liutikas@Suppress 41f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(JUnit4.class) 4342e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikaspublic class AsyncListUtilTest { 4442e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas @Rule 4542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas public ActivityTestRule<TestActivity> mActivityRule = 4642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas new ActivityTestRule<>(TestActivity.class); 47a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 48a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private static final int TILE_SIZE = 10; 49a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 50a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private TestDataCallback mDataCallback; 51a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private TestViewCallback mViewCallback; 52a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 53a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev AsyncListUtil<String> mAsyncListUtil; 54a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Before 5642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas public final void setup() throws Throwable { 57a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback = new TestDataCallback(); 58a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback = new TestViewCallback(); 59a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.expectTiles(0, 10, 20); 60180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 61180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas @Override 62180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas public void run() { 63180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas mAsyncListUtil = new AsyncListUtil<>( 64180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas String.class, TILE_SIZE, mDataCallback, mViewCallback); 65180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas } 66180bb52faf312fa55eb0c2ec22c6d9cff977a323Aurimas Liutikas }); 6742e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mDataCallback.waitForTiles("initial load"); 68de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 69de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev 700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @After 71a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void tearDown() throws Exception { 72a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev /// Wait a little extra to catch spurious messages. 73a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev new CountDownLatch(1).await(500, TimeUnit.MILLISECONDS); 74a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 75a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void withNoPreload() throws Throwable { 78a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(10, "scroll to 10", 30); 79a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(25, "scroll to 25", 40); 80a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(45, "scroll to 45", 50, 60); 81a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(70, "scroll to 70", 70, 80, 90); 82a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 83a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void withPreload() throws Throwable { 86a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.mStartPreload = 5; 87a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.mEndPreload = 15; 88a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(50, "scroll down a lot", 40, 50, 60, 70, 80); 89a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 90a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.mStartPreload = 0; 91a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.mEndPreload = 0; 92a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(60, "scroll down a little, no new tiles loaded"); 93a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(40, "scroll up a little, no new tiles loaded"); 94a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 95a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 96e310cf31070baf35a7e9eedf9528d3c2927db6c7Aurimas Liutikas @Test 970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void tileCaching() throws Throwable { 98a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(25, "next screen", 30, 40); 99a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 100a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(0, "back at top, no new page loads"); 101a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(25, "next screen again, no new page loads"); 102a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 103a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.mCacheSize = 3; 104a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(50, "scroll down more, all pages should load", 50, 60, 70); 105a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(0, "scroll back to top, all pages should reload", 0, 10, 20); 106a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 107a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 1080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dataRefresh() throws Throwable { 110a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.expectDataSetChanged(40); 111a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.expectTiles(0, 10, 20); 112de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev refreshOnUiThread(); 113a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.waitForDataSetChanged("increasing item count"); 114a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.waitForTiles("increasing item count"); 115a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 116a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.expectDataSetChanged(15); 117a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.expectTiles(0, 10); 118de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev refreshOnUiThread(); 119a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.waitForDataSetChanged("decreasing item count"); 120a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.waitForTiles("decreasing item count"); 121a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 122a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 1230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void itemChanged() throws Throwable { 125a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev final int position = 30; 126a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev final int count = 20; 127a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 128de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev assertLoadedItemsOnUiThread("no new items should be loaded", 0, position, count); 129a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 130a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.expectItemRangeChanged(position, count); 131a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev scrollAndExpectTiles(20, "scrolling to missing items", 30, 40); 132a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mViewCallback.waitForItems(); 133a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 134de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev assertLoadedItemsOnUiThread("all new items should be loaded", count, position, count); 135a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 136a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 137de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @UiThread 138a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private int getLoadedItemCount(int startPosition, int itemCount) { 139a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int loaded = 0; 140a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev for (int i = 0; i < itemCount; i++) { 141a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mAsyncListUtil.getItem(startPosition + i) != null) { 142a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev loaded++; 143a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 144a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 145a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return loaded; 146a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 147a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 148a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void scrollAndExpectTiles(int position, String context, int... positions) 149de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev throws Throwable { 150a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.expectTiles(positions); 151de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev scrollOnUiThread(position); 152a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.waitForTiles(context); 153a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 154a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 155a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private static void waitForLatch(String context, CountDownLatch latch) 156a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev throws InterruptedException { 157a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertTrue("timed out waiting for " + context, latch.await(1, TimeUnit.SECONDS)); 158a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 159a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 160de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev private void refreshOnUiThread() throws Throwable { 16142e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 162de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @Override 163de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev public void run() { 164de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev mAsyncListUtil.refresh(); 165de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 166de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev }); 167de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 168de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev 169de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev private void assertLoadedItemsOnUiThread(final String message, 170de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev final int expectedCount, 171de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev final int position, 172de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev final int count) throws Throwable { 17342e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 174de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @Override 175de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev public void run() { 176de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev assertEquals(message, expectedCount, getLoadedItemCount(position, count)); 177de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 178de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev }); 179de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 180de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev 181de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev private void scrollOnUiThread(final int position) throws Throwable { 18242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 183de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @Override 184de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev public void run() { 185de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev mViewCallback.scrollTo(position); 186de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 187de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev }); 188de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev } 189de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev 190a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private class TestDataCallback extends AsyncListUtil.DataCallback<String> { 191a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private int mCacheSize = 10; 192a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 193a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int mDataItemCount = 100; 194a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 195a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev final PositionSetLatch mTilesFilledLatch = new PositionSetLatch("filled"); 196a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 197a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 198a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void fillData(String[] data, int startPosition, int itemCount) { 199a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev synchronized (mTilesFilledLatch) { 200a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertEquals(Math.min(TILE_SIZE, mDataItemCount - startPosition), itemCount); 201a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mTilesFilledLatch.countDown(startPosition); 202a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 203a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev for (int i = 0; i < itemCount; i++) { 204a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev data[i] = "item #" + startPosition; 205a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 206a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 207a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 208a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 209a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public int refreshData() { 210a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return mDataItemCount; 211a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 212a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 213e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 214a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public int getMaxCachedTiles() { 215a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return mCacheSize; 216a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 217a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 218a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void expectTiles(int... positions) { 219a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev synchronized (mTilesFilledLatch) { 220a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mTilesFilledLatch.expect(positions); 221a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 222a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 223a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 224a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void waitForTiles(String context) throws InterruptedException { 225a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev waitForLatch("filled tiles (" + context + ")", mTilesFilledLatch.mLatch); 226a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 227a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 228a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 229a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private class TestViewCallback extends AsyncListUtil.ViewCallback { 230a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public static final int VIEWPORT_SIZE = 25; 231a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private int mStartPreload; 232a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private int mEndPreload; 233a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 234a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int mFirstVisibleItem; 235a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int mLastVisibleItem = VIEWPORT_SIZE - 1; 236a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 237a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private int mExpectedItemCount; 238a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev CountDownLatch mDataRefreshLatch; 239a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 240a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev PositionSetLatch mItemsChangedLatch = new PositionSetLatch("item changed"); 241a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 242a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 243a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void getItemRangeInto(int[] outRange) { 244a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev outRange[0] = mFirstVisibleItem; 245a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev outRange[1] = mLastVisibleItem; 246a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 247a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 248a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 249a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void extendRangeInto(int[] range, int[] outRange, int scrollHint) { 250a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev outRange[0] = range[0] - mStartPreload; 251a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev outRange[1] = range[1] + mEndPreload; 252a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 253a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 254a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 255de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @UiThread 256a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void onDataRefresh() { 257a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mDataRefreshLatch == null) { 258a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return; 259a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 260a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertTrue("unexpected onDataRefresh notification", mDataRefreshLatch.getCount() == 1); 261a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertEquals(mExpectedItemCount, mAsyncListUtil.getItemCount()); 262a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataRefreshLatch.countDown(); 263a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev updateViewport(); 264a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 265a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 266a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev @Override 267a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void onItemLoaded(int position) { 268a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mItemsChangedLatch.countDown(position); 269a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 270a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 271a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void expectDataSetChanged(int expectedItemCount) { 272a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataCallback.mDataItemCount = expectedItemCount; 273a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedItemCount = expectedItemCount; 274a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataRefreshLatch = new CountDownLatch(1); 275a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 276a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 277a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void waitForDataSetChanged(String context) throws InterruptedException { 278a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev waitForLatch("timed out waiting for data set change (" + context + ")", 279a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mDataRefreshLatch); 280a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 281a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 282a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void expectItemRangeChanged(int startPosition, int itemCount) { 283a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mItemsChangedLatch.expectRange(startPosition, itemCount); 284a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 285a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 286a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void waitForItems() throws InterruptedException { 287a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev waitForLatch("onItemChanged", mItemsChangedLatch.mLatch); 288a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 289a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 290de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @UiThread 291a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public void scrollTo(int position) { 292a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLastVisibleItem += position - mFirstVisibleItem; 293a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mFirstVisibleItem = position; 294a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mAsyncListUtil.onRangeChanged(); 295a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 296a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 297de8e2baf9504defe12972fbf60935a1148f1098fVladislav Kaznacheev @UiThread 298a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void updateViewport() { 299a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev int itemCount = mAsyncListUtil.getItemCount(); 300a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mLastVisibleItem < itemCount) { 301a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return; 302a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 303a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLastVisibleItem = itemCount - 1; 304a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mFirstVisibleItem = Math.max(0, mLastVisibleItem - VIEWPORT_SIZE + 1); 305a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 306a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 307a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 308a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private static class PositionSetLatch { 309a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev public CountDownLatch mLatch = new CountDownLatch(0); 310a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 311a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev final private SparseBooleanArray mExpectedPositions = new SparseBooleanArray(); 312a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev final private String mKind; 313a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 314a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev PositionSetLatch(String kind) { 315a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev this.mKind = kind; 316a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 317a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 318a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev void expect(int ... positions) { 319a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedPositions.clear(); 320a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev for (int position : positions) { 321a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedPositions.put(position, true); 322a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 323a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev createLatch(); 324a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 325a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 326a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev void expectRange(int position, int count) { 327a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedPositions.clear(); 328a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev for (int i = 0; i < count; i++) { 329a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedPositions.put(position + i, true); 330a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 331a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev createLatch(); 332a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 333a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 334a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev void countDown(int position) { 335a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mLatch == null) { 336a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev return; 337a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 338a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev assertTrue("unexpected " + mKind + " @" + position, mExpectedPositions.get(position)); 339a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mExpectedPositions.delete(position); 340a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mExpectedPositions.size() == 0) { 341a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLatch.countDown(); 342a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 343a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 344a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev 345a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev private void createLatch() { 346a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLatch = new CountDownLatch(1); 347a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev if (mExpectedPositions.size() == 0) { 348a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev mLatch.countDown(); 349a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 350a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 351a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev } 352a1470623b0f7c52c9e3985012bf9daeb692d7bccVladislav Kaznacheev} 353