RecyclerViewAnimationsTest.java revision 0a017072206f93474ccd2706e7983c2ff778b904
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 Haasepackage android.support.v7.widget; 18d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Test; 200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runner.RunWith; 210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 225a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyarimport android.graphics.Rect; 239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyarimport android.os.Debug; 24f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.support.annotation.NonNull; 250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 26f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyarimport android.support.v4.view.ViewCompat; 27f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest; 28b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log; 29b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View; 30504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup; 31b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 3211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList; 338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap; 3411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet; 3511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List; 3611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map; 3711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set; 38b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 39d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*; 41d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 42121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/** 43121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Tests for {@link SimpleItemAnimator} API. 44121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */ 45f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class) 47121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest { 48b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<TestViewHolder> recycledVHs = new ArrayList<>(); 509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detectStableIdError() throws Throwable { 53b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar final AtomicBoolean useBadIds = new AtomicBoolean(false); 54b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 55b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 56b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public long getItemId(int position) { 57b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar if (useBadIds.get() && position == 5) { 58b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position) - 1; 59b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 60b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position); 61b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 62b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 63b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 64b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public void onDetachedFromRecyclerView(RecyclerView recyclerView) { 65b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // ignore validation 66b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 67b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar }; 68b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.setHasStableIds(true); 69b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar setupBasic(10, 0, 10, adapter); 70b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.expectLayouts(2); 71b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar useBadIds.set(true); 72b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.changeAndNotify(4, 2); 73b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.waitForLayout(2); 74b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar assertTrue(mainThreadException instanceof IllegalStateException); 75b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar assertTrue(mainThreadException.getMessage() 76b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar .contains("Two different ViewHolders have the same stable ID.")); 77b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // TODO don't use this after moving this class to Junit 4 78b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar try { 79b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar removeRecyclerView(); 80b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } catch (Throwable t){} 81b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mainThreadException = null; 82b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 83b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 84b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithoutPredictive() throws Throwable { 879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar fail("pre layout is not expected"); 999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 1039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 1049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 1059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 1069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar View targetView = recycler 1079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getViewForPosition(target.getAdapterPosition()); 1089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertSame(targetView, target.itemView); 1099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 1109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 1149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 1159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 1169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 1179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 1189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 1199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 1219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 1229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 1239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 1249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 1259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 1269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 1279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 1289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 1299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 1309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance 1319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 1329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 1339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 1349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 1369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithPredictive() throws Throwable { 1409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 1419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 1439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 1449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 1459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 1469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 1479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 1489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 1509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 1519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 1529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 1539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 1579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 1589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 1599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 1609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 1619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 1659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 1669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 1679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 1689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 1699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 1709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 1729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 1739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 1749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 1759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 1769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 1779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 1789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 1799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 1809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance. 1819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 1829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 1839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 1849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 1869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 1879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutPredictive() throws Throwable { 1909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 1919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 1929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 1939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 1949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 1959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 1969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 1979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 1989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 1999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 2009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 2019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 2089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 2109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutAnimations() throws Throwable { 2149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 2189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 2229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 2239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 2249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 2319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 2339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithPredictive() throws Throwable { 2379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 2419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 2429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 2469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 2479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM does not layout the additional item so it does predictive wrong. 2509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // We should still handle it and animate persistence for this item 2519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 2569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 2579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 2599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithProperPredictive() throws Throwable { 2639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 2679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 2689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 2749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 2759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 2769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 2779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 2819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 8; 2849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPreLayout(recycler, layoutManager, state); 2859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 2879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 2899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 2909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM implements predictive animations properly by requesting target view 2939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // in pre-layout. 2949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 2999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseHiddenViewOnInvalidate() throws Throwable { 3069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.dispatchDataSetChanged(); 3169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(mRecyclerView.getItemAnimator().isRunning()); 3199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 3249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseOnTypeChange() throws Throwable { 3309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar target.mBoundItem.mType += 2; 3409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 3419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1); 3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 3439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mChangeOldVHs.contains(target)); 3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView)); 3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar interface ReuseTestCallback { 3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable; 3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar protected RecyclerView.ItemAnimator createItemAnimator() { 3649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar return new LoggingItemAnimator(); 3659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable { 3689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestAdapter adapter = new TestAdapter(10) { 3699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void onViewRecycled(TestViewHolder holder) { 3719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.onViewRecycled(holder); 3729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar recycledVHs.add(holder); 3739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 3759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar setupBasic(10, 0, 10, adapter); 3769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.setItemViewCacheSize(0); 3779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9); 3789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setAddDuration(1000); 3799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setRemoveDuration(1000); 3809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setChangeDuration(1000); 3819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setMoveDuration(1000); 3829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 3839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 3849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(2, 1); 3859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // test sanity, make sure target is hidden now 3879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView)); 3889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar callback.postSetup(recycledVHs, target); 3899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN 3909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED 3919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION 3929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachBeforeAnimations() throws Throwable { 3970ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar setupBasic(10, 0, 5); 3980ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final RecyclerView rv = mRecyclerView; 3990ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar waitForAnimations(2); 4000ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator() { 4010ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar @Override 4020ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar public void runPendingAnimations() { 4030ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar super.runPendingAnimations(); 4040ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 4050ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar }; 4060ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar rv.setItemAnimator(animator); 4070ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.expectLayouts(2); 4080ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mTestAdapter.deleteAndNotify(3, 4); 4090ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.waitForLayout(2); 4100ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar removeRecyclerView(); 4110ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertNull("test sanity check RV should be removed", rv.getParent()); 4120ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size()); 4130ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertFalse("there should not be any animations running", animator.isRunning()); 4140ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 4150ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar 4160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 4170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void moveDeleted() throws Throwable { 4185a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar setupBasic(4, 0, 3); 4195a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar waitForAnimations(2); 4205a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final View[] targetChild = new View[1]; 4215a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final LoggingItemAnimator animator = new LoggingItemAnimator(); 4225a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar runTestOnUiThread(new Runnable() { 4235a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 4245a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 4255a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.setItemAnimator(animator); 4265a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = mRecyclerView.getChildAt(1); 4275a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 4285a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 4295a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 4305a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertNotNull("test sanity", targetChild); 4315a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(1); 4325a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar runTestOnUiThread(new Runnable() { 4335a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 4345a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 4355a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { 4365a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 4375a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 4389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 4395a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar if (view == targetChild[0]) { 4405a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(10, 20, 30, 40); 4415a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } else { 4425a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(0, 0, 0, 0); 4435a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 4445a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 4455a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 4465a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 4475a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 4485a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(1); 4495a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 4505a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar // now delete that item. 4515a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(2); 4525a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]); 4535a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = null; 4545a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 4555a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(2); 4565a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertFalse("if deleted view moves, it should not be in move animations", 4575a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar animator.mMoveVHs.contains(targetVH)); 4585a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size()); 4595a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH 4605a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar )); 4615a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 4625a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 463344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev private void runTestImportantForAccessibilityWhileDeteling( 464344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int boundImportantForAccessibility, 465344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int expectedImportantForAccessibility) throws Throwable { 466344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Adapter binding the item to the initial accessibility option. 467344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // RecyclerView is expected to change it to 'expectedImportantForAccessibility'. 468344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev TestAdapter adapter = new TestAdapter(1) { 469344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 470344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void onBindViewHolder(TestViewHolder holder, int position) { 471344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev super.onBindViewHolder(holder, position); 472344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.setImportantForAccessibility( 473344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev holder.itemView, boundImportantForAccessibility); 474344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 475344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }; 476344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 477344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Set up with 1 item. 478344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev setupBasic(1, 0, 1, adapter); 479344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 480344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final View[] targetChild = new View[1]; 481344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final LoggingItemAnimator animator = new LoggingItemAnimator(); 482344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev animator.setRemoveDuration(500); 483344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 484344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 485344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 486344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mRecyclerView.setItemAnimator(animator); 487344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev targetChild[0] = mRecyclerView.getChildAt(0); 488344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 489344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 490344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 491344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 492344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 493344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 494344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertNotNull("test sanity", targetChild[0]); 495344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 496344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // now delete that item. 497344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 498344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.deleteAndNotify(0, 1); 499344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 500344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 501344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 502344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 503344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 504344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 505344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is still a child of mRecyclerView, and is invisible for accessibility. 506344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == mRecyclerView); 507344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 508344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 509344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 510344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 511344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 512344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 513344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 514344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 515344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Delete animation is now complete. 516344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 517344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 518344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 519344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is in recycled state, and back to the expected accessibility. 520344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == null); 521344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 522344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 523344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 524344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 525344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 526344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 527344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Add 1 element, which should use same view. 528344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 529344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.addAndNotify(1); 530344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 531344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 532344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 533344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 534344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 535344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view should be reused, and have the expected accessibility. 536344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue( 537344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0)); 538344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 539344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 540344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 541344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 542344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 543344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 544344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 5450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingAuto() throws Throwable { 547344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 548344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO, 549344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 550344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 551344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 5520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNo() throws Throwable { 554344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 555344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO, 556344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); 557344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 558344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 5590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable { 561344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 562344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 563344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); 564344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 565344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 5660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingYes() throws Throwable { 568344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 569344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES, 570344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 571344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 572344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 5730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void preLayoutPositionCleanup() throws Throwable { 57542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar setupBasic(4, 0, 4); 57642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.expectLayouts(2); 57742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 57842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 57942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 58042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 58142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 58242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 3; 58342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 58442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 58542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 58642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 58742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager layoutManager, 58842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state) { 58942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 59042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 4; 59142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 59242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar }; 59342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mTestAdapter.addAndNotify(0, 1); 59442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.waitForLayout(2); 59542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 59642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 59742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 59842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 5990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addRemoveSamePass() throws Throwable { 60193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final List<RecyclerView.ViewHolder> mRecycledViews 60293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 60393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar TestAdapter adapter = new TestAdapter(50) { 60493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 60593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 60693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.onViewRecycled(holder); 60793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.add(holder); 60893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 60993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 61093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar adapter.setHasStableIds(true); 61193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar setupBasic(50, 3, 5, adapter); 61293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemViewCacheSize(0); 61393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> addVH 61493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 61593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> removeVH 61693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 61793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 61893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> moveVH 61993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 62093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 62193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final View[] testView = new View[1]; 62293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 62393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 62493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateAdd(RecyclerView.ViewHolder holder) { 62593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar addVH.add(holder); 62693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 62793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 62893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 62993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 63093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 63193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar removeVH.add(holder); 63293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 63393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 63493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 63593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 63693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, 63793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar int toX, int toY) { 63893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar moveVH.add(holder); 63993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 64093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 64193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }); 64293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 64393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 64493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 64593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 64693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 64793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 64893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0] = recycler.getViewForPosition(45); 64993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST), 65093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST)); 65193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(), 65293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 10 + testView[0].getMeasuredHeight()); 65393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addView(testView[0], 4); 65493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 65593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 65693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 65793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 65893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 65993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 66093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPostLayout(recycler, layoutManager, state); 66193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(), 66293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 50 + testView[0].getMeasuredHeight()); 66393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addDisappearingView(testView[0], 4); 66493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 66593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 66693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3; 66793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5; 66893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.clear(); 66993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.expectLayouts(2); 67093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mTestAdapter.deleteAndNotify(3, 1); 67193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.waitForLayout(2); 67293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 67393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : addVH) { 67493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate add", testView[0], vh.itemView); 67593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 67693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : moveVH) { 67793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate move", testView[0], vh.itemView); 67893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 67993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : removeVH) { 68093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView); 68193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 68293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar boolean found = false; 68393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : mRecycledViews) { 68493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar found |= vh.itemView == testView[0]; 68593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 68693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertTrue("added-removed view should be recycled", found); 68793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 68893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 6890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void tmpRemoveMe() throws Throwable { 691121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar changeAnimTest(false, false, true, false); 692121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 693121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void changeAnimations() throws Throwable { 6967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean[] booleans = {true, false}; 6977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean supportsChange : booleans) { 6987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean changeType : booleans) { 6997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean hasStableIds : booleans) { 7007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean deleteSomeItems : booleans) { 7017c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems); 7027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen removeRecyclerView(); 7047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 708121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 7097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType, 7109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable { 7117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int changedIndex = 3; 7127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int defaultType = 1; 7137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType); 7147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim + 7157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", change view type:" + changeType + 7167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", has stable ids:" + hasStableIds + 717121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ", delete some items:" + deleteSomeItems; 7187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestAdapter testAdapter = new TestAdapter(10) { 7197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public int getItemViewType(int position) { 7217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return position == changedIndex ? changedIndexNewType.get() : defaultType; 7227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public TestViewHolder onCreateViewHolder(ViewGroup parent, 7267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int viewType) { 7277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 7287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 7297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onCreateVH" + vh.toString()); 7307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7317c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return vh; 7327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void onBindViewHolder(TestViewHolder holder, 7367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int position) { 7377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.onBindViewHolder(holder, position); 7387c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 7397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString()); 7407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 7437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen testAdapter.setHasStableIds(hasStableIds); 7447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 7459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 746121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 7477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final RecyclerView.ViewHolder toBeChangedVH = 749115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar mRecyclerView.findViewHolderForLayoutPosition(changedIndex); 7507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 7517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPreLayout(RecyclerView.Recycler recycler, 7537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, 7547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.State state) { 755115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 756115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 757121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar assertTrue(logPrefix + " changed view holder should have correct flag" 758121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar , vh.isUpdated()); 7597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPostLayout(RecyclerView.Recycler recycler, 7637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, RecyclerView.State state) { 764115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 765115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 7667c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 7677c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertNotSame(logPrefix + "a new VH should be given if change is supported", 7687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen toBeChangedVH, vh); 7697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else if (!changeType && hasStableIds) { 7707c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertSame(logPrefix + "if change animations are not supported but we have " 7717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen + "stable ids, same view holder should be returned", toBeChangedVH, vh); 7727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.beforePostLayout(recycler, layoutManager, state); 7747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 7767c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.expectLayouts(1); 7777c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (changeType) { 7787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changedIndexNewType.set(defaultType + 1); 7797c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (deleteSomeItems) { 7817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen runTestOnUiThread(new Runnable() { 7827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 7837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void run() { 7847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen try { 7857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.deleteAndNotify(changedIndex + 2, 1); 7867c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 7877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } catch (Throwable throwable) { 7887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen throwable.printStackTrace(); 7897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }); 7937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 794121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.changeAndNotify(3, 1); 7957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 7977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.waitForLayout(2); 7987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 7997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 800f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar private void testChangeWithPayload(final boolean supportsChangeAnim, final boolean canReUse, 8019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind) 8029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar throws Throwable { 80321b345f101abc385496f42d250e580d21f1287b6Dake Gu final List<Object> expectedPayloads = new ArrayList<Object>(); 80421b345f101abc385496f42d250e580d21f1287b6Dake Gu final int changedIndex = 3; 80521b345f101abc385496f42d250e580d21f1287b6Dake Gu TestAdapter testAdapter = new TestAdapter(10) { 80621b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 80721b345f101abc385496f42d250e580d21f1287b6Dake Gu public int getItemViewType(int position) { 80821b345f101abc385496f42d250e580d21f1287b6Dake Gu return 1; 80921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 81021b345f101abc385496f42d250e580d21f1287b6Dake Gu 81121b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 81221b345f101abc385496f42d250e580d21f1287b6Dake Gu public TestViewHolder onCreateViewHolder(ViewGroup parent, 81321b345f101abc385496f42d250e580d21f1287b6Dake Gu int viewType) { 81421b345f101abc385496f42d250e580d21f1287b6Dake Gu TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 81521b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 81621b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onCreateVH" + vh.toString()); 81721b345f101abc385496f42d250e580d21f1287b6Dake Gu } 81821b345f101abc385496f42d250e580d21f1287b6Dake Gu return vh; 81921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 82021b345f101abc385496f42d250e580d21f1287b6Dake Gu 82121b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 82221b345f101abc385496f42d250e580d21f1287b6Dake Gu public void onBindViewHolder(TestViewHolder holder, 82321b345f101abc385496f42d250e580d21f1287b6Dake Gu int position, List<Object> payloads) { 82421b345f101abc385496f42d250e580d21f1287b6Dake Gu super.onBindViewHolder(holder, position); 82521b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 82621b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onBind to " + position + "" + holder.toString()); 82721b345f101abc385496f42d250e580d21f1287b6Dake Gu } 828f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar assertEquals(expectedPayloads, payloads); 82921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 83021b345f101abc385496f42d250e580d21f1287b6Dake Gu }; 83121b345f101abc385496f42d250e580d21f1287b6Dake Gu testAdapter.setHasStableIds(false); 83221b345f101abc385496f42d250e580d21f1287b6Dake Gu setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 833f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 834f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @Override 835f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, 836f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @NonNull List<Object> payloads) { 837f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads); 838f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 839f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 8409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 841121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 84221b345f101abc385496f42d250e580d21f1287b6Dake Gu 84321b345f101abc385496f42d250e580d21f1287b6Dake Gu int numTests = notifyPayloads.length; 8449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < numTests; i++) { 84521b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.expectLayouts(1); 84621b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.clear(); 84721b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) { 84821b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.add(expectedPayloadsInOnBind[i][j]); 84921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 85021b345f101abc385496f42d250e580d21f1287b6Dake Gu final Object[] payloadsToSend = notifyPayloads[i]; 85121b345f101abc385496f42d250e580d21f1287b6Dake Gu runTestOnUiThread(new Runnable() { 85221b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 85321b345f101abc385496f42d250e580d21f1287b6Dake Gu public void run() { 85421b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < payloadsToSend.length; j++) { 85521b345f101abc385496f42d250e580d21f1287b6Dake Gu mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]); 85621b345f101abc385496f42d250e580d21f1287b6Dake Gu } 85721b345f101abc385496f42d250e580d21f1287b6Dake Gu } 85821b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 85921b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.waitForLayout(2); 8609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 86121b345f101abc385496f42d250e580d21f1287b6Dake Gu } 86221b345f101abc385496f42d250e580d21f1287b6Dake Gu } 86321b345f101abc385496f42d250e580d21f1287b6Dake Gu 8640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayload() throws Throwable { 86621b345f101abc385496f42d250e580d21f1287b6Dake Gu // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 867f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, true, 868f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 869f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 870f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null, "cdf"}, 871f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null}, 872f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{null, "abc"}, 873f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 874f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }, 875f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 876f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 877f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 878f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 879f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 880f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 881f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 882f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 883f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar 8840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable { 886f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 887f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, false, 88821b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 8899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 8909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 8919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 8929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 8939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 89421b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 89521b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 8969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 8979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 8989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 8999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 9009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0] 90121b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 90221b345f101abc385496f42d250e580d21f1287b6Dake Gu } 90321b345f101abc385496f42d250e580d21f1287b6Dake Gu 9040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 9050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noChangeAnimationWithPayload() throws Throwable { 90621b345f101abc385496f42d250e580d21f1287b6Dake Gu // for Change Animation disabled, payload should match the payloads unless 90721b345f101abc385496f42d250e580d21f1287b6Dake Gu // null payload is fired. 908f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(false, true, 90921b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 9109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 9119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 9129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 9139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 9149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 91521b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 91621b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 9179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 9189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 9199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 9209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 9219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 92221b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 92321b345f101abc385496f42d250e580d21f1287b6Dake Gu } 92421b345f101abc385496f42d250e580d21f1287b6Dake Gu 9250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 9260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleDuringAnimations() throws Throwable { 927504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 928504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(1000) { 929504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 930504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 931504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 932504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 933504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return super.onCreateViewHolder(parent, viewType); 934504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 935504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 936504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar setupBasic(1000, 10, 20, adapter); 937504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10; 938504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20; 939504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 940504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 941504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 942504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 943504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 944504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.decrementAndGet(); 945504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 946504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 947504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 948504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 949504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 950504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 951504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 952504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 953504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 954504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 955504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }); 956504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 957504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 9589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < 100; i++) { 959504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 960504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(50); 961504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 962504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 963504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 964504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 965504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 966504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 967504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 9680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 9690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChanged() throws Throwable { 970b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar setupBasic(10, 3, 4); 971b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar int layoutCount = mLayoutManager.mTotalLayoutCount; 972b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(1); 973b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar runTestOnUiThread(new Runnable() { 974b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar @Override 975b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void run() { 976b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar try { 977b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.deleteAndNotify(4, 1); 978cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase mTestAdapter.dispatchDataSetChanged(); 979b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } catch (Throwable throwable) { 980b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar throwable.printStackTrace(); 981b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 982b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 983b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 984b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar }); 985b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 986b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar getInstrumentation().waitForIdleSync(); 987b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("on notify data set changed, predictive animations should not run", 988b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar layoutCount + 1, mLayoutManager.mTotalLayoutCount); 989b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(2); 990b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.addAndNotify(4, 2); 991b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar // make sure animations recover 992b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 993b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 994b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 9950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 9960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void stableIdNotifyDataSetChanged() throws Throwable { 997e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int itemCount = 20; 998e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar List<Item> initialSet = new ArrayList<Item>(); 999e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(itemCount) { 1000e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 1001e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 1002e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 1003e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1004e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 1005e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 1006e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar initialSet.addAll(adapter.mItems); 1007e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() { 10089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 10099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter testAdapter) throws Throwable { 10109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item5 = adapter.mItems.get(5); 10119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item6 = adapter.mItems.get(6); 10129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item5.mAdapterIndex = 6; 10139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item6.mAdapterIndex = 5; 10149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.remove(5); 10159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.add(6, item5); 10169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.dispatchDataSetChanged(); 10179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar //hacky, we support only 1 layout pass 10189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.layoutLatch.countDown(); 10199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 10209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6), 1021e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8), 1022e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(9, -1, 9)); 1023e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // now mix items. 1024e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1025e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 1026d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 10270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void getItemForDeletedView() throws Throwable { 10298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(false); 10308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(true); 103111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 103211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 10338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void getItemForDeletedViewTest(boolean stableIds) throws Throwable { 103411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemViewTypeQueries = new HashSet<Integer>(); 103511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemIdQueries = new HashSet<Integer>(); 103611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter adapter = new TestAdapter(10) { 103711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 103811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public int getItemViewType(int position) { 103911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.add(position); 104011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return super.getItemViewType(position); 104111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 104211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 104311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 104411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public long getItemId(int position) { 104511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.add(position); 104611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return mItems.get(position).mId; 104711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 104811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar }; 104911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.setHasStableIds(stableIds); 105011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar setupBasic(10, 0, 10, adapter); 105111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemViewType for all items should be called", 10, 105211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.size()); 105311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 105411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should be called when adapter has stable ids", 10, 105511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 105611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 105711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should not be called when adapter does not have stable ids", 0, 105811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 105911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 106011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.clear(); 106111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.clear(); 106211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.expectLayouts(2); 106311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar // delete last two 106411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteStart = 8; 106511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteCount = adapter.getItemCount() - deleteStart; 106611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.deleteAndNotify(deleteStart, deleteCount); 106711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.waitForLayout(2); 106811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = 0; i < deleteStart; i++) { 106911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemViewType for existing item " + i + " should be called", 107011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 107111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 107211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemId for existing item " + i 10739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + " should be called when adapter has stable ids", 107411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 107511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 107611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 107711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = deleteStart; i < deleteStart + deleteCount; i++) { 107811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called", 107911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 108011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 10818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called", 108211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 108311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 108411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 108511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 108611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 10870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisibleMultiStep() throws Throwable { 10898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(1000, 1, 7); 10908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 10918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 10928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 10938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 10948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 10958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 10968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1}); 109790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 10988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount -= 2; 10998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 11018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 11028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 11038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 11058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addManyMultiStep() throws Throwable { 11098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10, 1, 7); 11108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 11118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 11128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 11138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 11148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 11158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 1116e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 11178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(0, 1); 1118e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 11198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(7, 1); 11208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount += 2; 11218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1122e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 11238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 11248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 11258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 1126e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 11278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 11298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicDelete() throws Throwable { 11338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 11348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() { 11358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 11368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void postDispatchLayout() { 11378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // verify this only in first layout 11388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("deleted views should still be children of RV", 11398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount() + mDeletedViewCount 11408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar , mRecyclerView.getChildCount()); 11418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 11448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 11458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AnimationLayoutManager layoutManager, 11468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 11478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 11488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutItemCount = 3; 11498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutMin = 0; 11508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 11528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.mLayoutItemCount = 10; 11538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.setExpectedItemCounts(10, 3); 11548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.setOnLayoutCallbacks(callbacks); 11558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(2); 11578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(0, 7); 11588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 11598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.reset();// when animations end another layout will happen 11608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScrolling() throws Throwable { 1165d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar setupBasic(10); 1166d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 1167d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 1168d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1169d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 1170d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1171d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 1172d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 1173d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 1174d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onLayoutChildren(recycler, lm, state); 1175d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1176d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1177d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1178d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 1179d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onScrollItemCount.set(state.getItemCount()); 1180d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onScroll(dx, recycler, state); 1181d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1182d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 1183d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar runTestOnUiThread(new Runnable() { 1184d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1185d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void run() { 1186d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.remove(5); 1187d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.notifyItemRangeRemoved(5, 1); 1188d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mRecyclerView.scrollBy(0, 100); 1189d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 1190d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 1191d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 1192d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 1193d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1194d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1195d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 1196d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1197d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 11980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedDuringScroll() throws Throwable { 120017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar setupBasic(10); 120117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 120217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 120317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 120417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 120517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 120617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 120717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 120817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 120917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onLayoutChildren(recycler, lm, state); 121017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 121117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 121217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 121317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 121417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onScrollItemCount.set(state.getItemCount()); 121517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onScroll(dx, recycler, state); 121617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 121717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 121817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar runTestOnUiThread(new Runnable() { 121917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 122017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void run() { 122117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.remove(5); 122217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.notifyDataSetChanged(); 122317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mRecyclerView.scrollBy(0, 100); 122417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 122517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 122617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 122717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 122817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 122917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 123017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 123117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 123217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 12330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisibleAndVisible() throws Throwable { 1235b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1236b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1237b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible 1239b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1240b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1241b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 12420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisible() throws Throwable { 1244b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1245b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1246b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0 1248b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1249b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1250b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 12510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicAdd() throws Throwable { 1253b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10); 1254b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1255b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(10, 13); 1256b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.addAndNotify(2, 3); 1257b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1258b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1259b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 12600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void appCancelAnimationInDetach() throws Throwable { 1262a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu final View[] addedView = new View[2]; 1263a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu TestAdapter adapter = new TestAdapter(1) { 1264a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1265a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void onViewDetachedFromWindow(TestViewHolder holder) { 1266a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView) 1267f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar && ViewCompat.hasTransientState(holder.itemView)) { 1268f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar ViewCompat.animate(holder.itemView).cancel(); 1269a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1270a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu super.onViewDetachedFromWindow(holder); 1271a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1272a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1273a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // original 1 item 1274a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setupBasic(1, 0, 1, adapter); 1275cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getItemAnimator().setAddDuration(10000); 1276a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(2); 1277a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // add 2 items 1278a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setExpectedItemCounts(1, 3); 1279a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mTestAdapter.addAndNotify(0, 2); 1280629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar mLayoutManager.waitForLayout(2, false); 1281629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar checkForMainThreadException(); 1282a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // wait till "add animation" starts 1283e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar int limit = 200; 1284a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu while (addedView[0] == null || addedView[1] == null) { 1285629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar Thread.sleep(100); 1286a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu runTestOnUiThread(new Runnable() { 1287a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1288a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void run() { 1289a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (mRecyclerView.getChildCount() == 3) { 1290a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu View view = mRecyclerView.getChildAt(0); 1291f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1292a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[0] = view; 1293a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1294a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu view = mRecyclerView.getChildAt(1); 1295f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1296a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[1] = view; 1297a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1298a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1299a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1300a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }); 1301e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar assertTrue("add should start on time", --limit > 0); 1302a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1303a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 1304a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // Layout from item2, exclude the current adding items 1305a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(1); 1306a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 1307a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1308a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu void beforePostLayout(RecyclerView.Recycler recycler, 1309a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu AnimationLayoutManager layoutManager, 1310a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu RecyclerView.State state) { 1311a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutMin = 2; 1312a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutItemCount = 1; 1313a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1314a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1315a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu requestLayoutOnUIThread(mRecyclerView); 1316a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.waitForLayout(2); 1317a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1318a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 13190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeFrozen() throws Throwable { 1321ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setupBasic(10, 1, 7); 1322ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue(mRecyclerView.getChildCount() == 7); 1323ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1324ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.expectLayouts(2); 1325ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 1326ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 1327ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 1328ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mTestAdapter.addAndNotify(0, 1); 1329ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1330ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2); 1331ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(7, mRecyclerView.getChildCount()); 1332ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1333ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 1334ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.waitForLayout(2); 1335ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("RV should get updated after waken from frozen", 1336ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 8, mRecyclerView.getChildCount()); 1337ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 1338ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 13390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void removeScrapInvalidate() throws Throwable { 1341888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar setupBasic(10); 1342888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar TestRecyclerView testRecyclerView = getTestRecyclerView(); 1343888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.expectLayouts(1); 1344888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.expectDraw(1); 1345888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar runTestOnUiThread(new Runnable() { 1346888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 1347888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void run() { 1348888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.mItems.clear(); 1349888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.notifyDataSetChanged(); 1350888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1351888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar }); 1352888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.waitForLayout(2); 1353888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.waitForDraw(2); 1354888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1355888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 13560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteVisibleAndInvisible() throws Throwable { 1358b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(11, 3, 5); //layout items 3 4 5 6 7 1359b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 13608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list 1361b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(9, 8); 1362b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9 1363b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1364b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1365b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findPositionOffset() throws Throwable { 13688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 136990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 137090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar @Override 137190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 137290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 137390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar super.beforePreLayout(recycler, lm, state); 137490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar // [0,2,4] 137590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0)); 137690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2)); 137790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4)); 137890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar } 137990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }; 13808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar runTestOnUiThread(new Runnable() { 13818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 13828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 1383121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar try { 1384121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 1 1385121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 1386121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 3 1387121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(2, 1); 1388121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } catch (Throwable throwable) { 1389121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar throwable.printStackTrace(); 1390121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 13918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }); 139390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.waitForLayout(2); 13948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1396b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setLayoutRange(int start, int count) { 1397b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start; 1398b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count; 1399b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1400b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1401b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setExpectedItemCounts(int preLayout, int postLayout) { 1402b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout); 1403b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1404b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 14050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisible() throws Throwable { 1407b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 14088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 14098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 1410b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1411b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8); 14128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8 1413b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1414b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1415b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1416e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar private CollectPositionResult findByPos(RecyclerView recyclerView, 1417e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int position) { 1418e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = recycler.getViewForPosition(position, true); 1419e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 1420e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (vh.wasReturnedFromScrap()) { 1421e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar vh.clearReturnedFromScrapFlag(); //keep data consistent. 1422e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromScrap(vh); 1423e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } else { 1424e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromAdapter(vh); 14258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1428e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView, 1429e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) { 14308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positionToAdapterMapping 14318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar = new HashMap<Integer, CollectPositionResult>(); 14328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position : positions) { 14338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (position < 0) { 14348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar continue; 14358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1436e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionToAdapterMapping.put(position, 1437e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar findByPos(recyclerView, recycler, state, position)); 14388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return positionToAdapterMapping; 14408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete2() throws Throwable { 14448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 14459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 14469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 14479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 b 3 4 14489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 14499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre w/ adap: 0 1 2 b 3 4 14509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 14519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 14529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2}); 14539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 14549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1), 14558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(3, 3, 3) 14568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 14578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1458d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 14590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete1() throws Throwable { 14618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 14629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 14639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 14649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 2 a b 3 4 14659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a b 3 4 14669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a 4 14679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // c d 2 a 4 14689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 14699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 14709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 14719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1}, 14729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1}); 14739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 14749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1), 14758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1), 14768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0), 14778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapter(1), PositionConstraint.adapter(3) 14788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 14798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addSameIndexTwice() throws Throwable { 14838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 14849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 14859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 14869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1}, 14879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{11, 1}); 14889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 14899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3), 14908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7), 14918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12), 14928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(8, 8, 13) 14938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 14948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14970a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteTwice() throws Throwable { 14988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 14999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 15009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 15019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1}, 15029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{0, 1});// delete item ids 0,2,9,1 15039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 15049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0), 15058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2), 15068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5), 15078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7) 15088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 15098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1511b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 15128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 1513e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount, AdapterOps adapterChanges, 1514e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1515e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null, 15169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapterChanges, constraints); 1517e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 15189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1519e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 15209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges, 1521e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1522e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter); 1523b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 15248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 15258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 15268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 15278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 15288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePreLayout(recycler, lm, state); 15298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar //harmless 15308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 15318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 15328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 15338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPreLayoutPos; 15348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1536e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1537121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1538121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 15399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar positionLog.append(entry.getKey()).append(":").append(entry.getValue()) 15409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .append("\n"); 1541121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 15428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 15438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPreLayoutPos != -1) { 15448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPreLayoutPos), 1545121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 15468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 15508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 15518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 15528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 15538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePostLayout(recycler, lm, state); 15548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 15558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 15568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 15578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPostLayoutPos; 15588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1560e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1561121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1562121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 1563121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar positionLog.append(entry.getKey()).append(":") 1564121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar .append(entry.getValue()).append("\n"); 1565121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 15668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 15678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPostLayoutPos >= 0) { 15688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPostLayoutPos), 1569121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 15708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 15748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterChanges.run(mTestAdapter); 1575b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1576e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 15778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 15788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.assertValidate(); 15798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1580b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1581b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 15820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addThenRecycleRemovedView() throws Throwable { 15846a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar setupBasic(10); 15856a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final AtomicInteger step = new AtomicInteger(0); 15869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<RecyclerView.ViewHolder> animateRemoveList 15879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 15886a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar DefaultItemAnimator animator = new DefaultItemAnimator() { 15896a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 15906a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 15916a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.add(holder); 15926a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar return super.animateRemove(holder); 15936a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 15946a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 15956a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setItemAnimator(animator); 15966a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>(); 15976a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 15986a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 15996a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 16006a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar pooledViews.add(scrap); 16016a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.putRecycledView(scrap); 16026a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 16036a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }); 16046a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1]; 16056a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 16066a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 16076a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar void doLayout(RecyclerView.Recycler recycler, 16086a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 16096a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar switch (step.get()) { 16106a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar case 1: 16116a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.doLayout(recycler, lm, state); 16126a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar if (state.isPreLayout()) { 16136a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar View view = mLayoutManager.getChildAt(1); 16146a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar RecyclerView.ViewHolder holder = 16156a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.getChildViewHolderInt(view); 16166a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar targetVh[0] = holder; 16176a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity", holder.isRemoved()); 16186a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.removeAndRecycleView(view, recycler); 16196a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 16206a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar break; 16216a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 16226a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 16236a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 16246a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar step.set(1); 16256a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.clear(); 16266a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.expectLayouts(2); 16276a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 16286a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.waitForLayout(2); 16296a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0])); 16306a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("since LM force recycled a view, animate disappearance should not be called", 16316a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.isEmpty()); 16326a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 1633d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase} 1634