RecyclerViewAnimationsTest.java revision 93d88283955af6643f2ea0f3cc6cbc34ea49f181
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 19b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.content.Context; 20888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyarimport android.graphics.Canvas; 21b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.AttributeSet; 22b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log; 23b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View; 24504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup; 25b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 2611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList; 278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap; 2811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet; 2911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List; 3011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map; 3111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set; 32888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyarimport java.util.concurrent.CountDownLatch; 33d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.concurrent.TimeUnit; 34d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 35d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 36d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest { 37d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 38668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private static final boolean DEBUG = false; 39b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 40b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private static final String TAG = "RecyclerViewAnimationsTest"; 41b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 42b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar AnimationLayoutManager mLayoutManager; 43b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 44b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar TestAdapter mTestAdapter; 45b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 46b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public RecyclerViewAnimationsTest() { 47b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(DEBUG); 48b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 49b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 50b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 51b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar protected void setUp() throws Exception { 52b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.setUp(); 53b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 54b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 55b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView setupBasic(int itemCount) throws Throwable { 56b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar return setupBasic(itemCount, 0, itemCount); 57b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 58b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 59b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount) 60b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar throws Throwable { 6111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null); 6211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 6311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 6411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount, 6511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter testAdapter) 6611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar throws Throwable { 67888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar final TestRecyclerView recyclerView = new TestRecyclerView(getActivity()); 68b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar recyclerView.setHasFixedSize(true); 6911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (testAdapter == null) { 7011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mTestAdapter = new TestAdapter(itemCount); 7111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 7211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mTestAdapter = testAdapter; 7311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 74b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar recyclerView.setAdapter(mTestAdapter); 75b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager = new AnimationLayoutManager(); 76b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar recyclerView.setLayoutManager(mLayoutManager); 77b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex; 78b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount; 79b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 80b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 81888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar recyclerView.expectDraw(1); 82b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setRecyclerView(recyclerView); 83b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 84888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar recyclerView.waitForDraw(1); 85888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.mOnLayoutCallbacks.reset(); 868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getInstrumentation().waitForIdleSync(); 87b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount()); 888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("all expected children should be laid out", firstLayoutItemCount, 898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount()); 90b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar return recyclerView; 91b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 92b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void testAddRemoveSamePass() throws Throwable { 9493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final List<RecyclerView.ViewHolder> mRecycledViews 9593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 9693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar TestAdapter adapter = new TestAdapter(50) { 9793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 9893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 9993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.onViewRecycled(holder); 10093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.add(holder); 10193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 10293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 10393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar adapter.setHasStableIds(true); 10493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar setupBasic(50, 3, 5, adapter); 10593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemViewCacheSize(0); 10693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> addVH 10793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 10893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> removeVH 10993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 11093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 11193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> moveVH 11293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 11393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 11493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final View[] testView = new View[1]; 11593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 11693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 11793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateAdd(RecyclerView.ViewHolder holder) { 11893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar addVH.add(holder); 11993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 12093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 12193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 12293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 12393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 12493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar removeVH.add(holder); 12593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 12693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 12793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 12893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 12993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, 13093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar int toX, int toY) { 13193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar moveVH.add(holder); 13293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 13393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 13493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }); 13593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 13693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 13793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 13893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 13993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 14093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 14193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0] = recycler.getViewForPosition(45); 14293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST), 14393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST)); 14493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(), 14593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 10 + testView[0].getMeasuredHeight()); 14693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addView(testView[0], 4); 14793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 14893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 14993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 15093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 15193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 15293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 15393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPostLayout(recycler, layoutManager, state); 15493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(), 15593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 50 + testView[0].getMeasuredHeight()); 15693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addDisappearingView(testView[0], 4); 15793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 15893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 15993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3; 16093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5; 16193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.clear(); 16293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.expectLayouts(2); 16393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mTestAdapter.deleteAndNotify(3, 1); 16493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.waitForLayout(2); 16593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 16693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : addVH) { 16793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate add", testView[0], vh.itemView); 16893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 16993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : moveVH) { 17093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate move", testView[0], vh.itemView); 17193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 17293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : removeVH) { 17393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView); 17493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 17593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar boolean found = false; 17693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : mRecycledViews) { 17793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar found |= vh.itemView == testView[0]; 17893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 17993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertTrue("added-removed view should be recycled", found); 18093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 18193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 1827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void testChangeAnimations() throws Throwable { 1837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean[] booleans = {true, false}; 1847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean supportsChange : booleans) { 1857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean changeType : booleans) { 1867c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean hasStableIds : booleans) { 1877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean deleteSomeItems : booleans) { 1887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems); 1897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 1907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen removeRecyclerView(); 1917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 1927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 1937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 1947c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 1957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType, 1967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable { 1977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int changedIndex = 3; 1987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int defaultType = 1; 1997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType); 2007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim + 2017c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", change view type:" + changeType + 2027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", has stable ids:" + hasStableIds + 2037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", force predictive:" + deleteSomeItems; 2047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestAdapter testAdapter = new TestAdapter(10) { 2057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public int getItemViewType(int position) { 2077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return position == changedIndex ? changedIndexNewType.get() : defaultType; 2087c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2107c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public TestViewHolder onCreateViewHolder(ViewGroup parent, 2127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int viewType) { 2137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 2147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 2157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onCreateVH" + vh.toString()); 2167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return vh; 2187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void onBindViewHolder(TestViewHolder holder, 2227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int position) { 2237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.onBindViewHolder(holder, position); 2247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 2257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString()); 2267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 2297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen testAdapter.setHasStableIds(hasStableIds); 2307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 2317c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim); 2327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final RecyclerView.ViewHolder toBeChangedVH = 2347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mRecyclerView.findViewHolderForPosition(changedIndex); 2357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPreLayout(RecyclerView.Recycler recycler, 2387c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, 2397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.State state) { 2407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForPosition(changedIndex); 2417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 2427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertTrue(logPrefix + " changed view holder should have correct flag" 2437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen , vh.isChanged()); 2447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 2457c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertFalse(logPrefix + " changed view holder should have correct flag" 2467c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen , vh.isChanged()); 2477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2497c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPostLayout(RecyclerView.Recycler recycler, 2527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, RecyclerView.State state) { 2537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForPosition(changedIndex); 2547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertFalse(logPrefix + "VH should not be marked as changed", vh.isChanged()); 2557c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 2567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertNotSame(logPrefix + "a new VH should be given if change is supported", 2577c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen toBeChangedVH, vh); 2587c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else if (!changeType && hasStableIds) { 2597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertSame(logPrefix + "if change animations are not supported but we have " 2607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen + "stable ids, same view holder should be returned", toBeChangedVH, vh); 2617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.beforePostLayout(recycler, layoutManager, state); 2637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2647c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 2657c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.expectLayouts(1); 2667c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (changeType) { 2677c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changedIndexNewType.set(defaultType + 1); 2687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (deleteSomeItems) { 2707c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen runTestOnUiThread(new Runnable() { 2717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void run() { 2737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen try { 2747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.deleteAndNotify(changedIndex + 2, 1); 2757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 2767c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } catch (Throwable throwable) { 2777c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen throwable.printStackTrace(); 2787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2797c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }); 2827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 2837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 2847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2867c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.waitForLayout(2); 2877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 289504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void testRecycleDuringAnimations() throws Throwable { 290504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 291504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(1000) { 292504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 293504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 294504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 295504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 296504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return super.onCreateViewHolder(parent, viewType); 297504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 298504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 299504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar setupBasic(1000, 10, 20, adapter); 300504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10; 301504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20; 302504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 303504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 304504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 305504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 306504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 307504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.decrementAndGet(); 308504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 309504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 310504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 311504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 312504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 313504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 314504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 315504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 316504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 317504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 318504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }); 319504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 320504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 321504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar for (int i = 0; i < 100; i ++) { 322504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 323504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(50); 324504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 325504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 326504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 327504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 328504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 329504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 330504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 331b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void testNotifyDataSetChanged() throws Throwable { 332b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar setupBasic(10, 3, 4); 333b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar int layoutCount = mLayoutManager.mTotalLayoutCount; 334b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(1); 335b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar runTestOnUiThread(new Runnable() { 336b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar @Override 337b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void run() { 338b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar try { 339b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.deleteAndNotify(4, 1); 340cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase mTestAdapter.dispatchDataSetChanged(); 341b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } catch (Throwable throwable) { 342b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar throwable.printStackTrace(); 343b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 344b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 345b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 346b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar }); 347b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 348b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar getInstrumentation().waitForIdleSync(); 349b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("on notify data set changed, predictive animations should not run", 350b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar layoutCount + 1, mLayoutManager.mTotalLayoutCount); 351b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(2); 352b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.addAndNotify(4, 2); 353b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar // make sure animations recover 354b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 355b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 356b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 357e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void testStableIdNotifyDataSetChanged() throws Throwable { 358e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int itemCount = 20; 359e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar List<Item> initialSet = new ArrayList<Item>(); 360e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(itemCount) { 361e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 362e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 363e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 364e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 365e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 366e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 367e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar initialSet.addAll(adapter.mItems); 368e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() { 369e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 370e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar void onRun(TestAdapter testAdapter) throws Throwable { 371e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item5 = adapter.mItems.get(5); 372e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item6 = adapter.mItems.get(6); 373e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar item5.mAdapterIndex = 6; 374e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar item6.mAdapterIndex = 5; 375e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.mItems.remove(5); 376e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.mItems.add(6, item5); 377cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 378e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar //hacky, we support only 1 layout pass 379e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar mLayoutManager.layoutLatch.countDown(); 380e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 381e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6), 382e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8), 383e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(9, -1, 9)); 384e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // now mix items. 385e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 386e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 387d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 3888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testGetItemForDeletedView() throws Throwable { 3898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(false); 3908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(true); 39111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 39211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 3938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void getItemForDeletedViewTest(boolean stableIds) throws Throwable { 39411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemViewTypeQueries = new HashSet<Integer>(); 39511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemIdQueries = new HashSet<Integer>(); 39611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter adapter = new TestAdapter(10) { 39711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 39811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public int getItemViewType(int position) { 39911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.add(position); 40011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return super.getItemViewType(position); 40111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 40211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 40311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 40411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public long getItemId(int position) { 40511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.add(position); 40611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return mItems.get(position).mId; 40711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 40811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar }; 40911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.setHasStableIds(stableIds); 41011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar setupBasic(10, 0, 10, adapter); 41111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemViewType for all items should be called", 10, 41211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.size()); 41311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 41411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should be called when adapter has stable ids", 10, 41511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 41611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 41711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should not be called when adapter does not have stable ids", 0, 41811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 41911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 42011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.clear(); 42111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.clear(); 42211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.expectLayouts(2); 42311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar // delete last two 42411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteStart = 8; 42511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteCount = adapter.getItemCount() - deleteStart; 42611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.deleteAndNotify(deleteStart, deleteCount); 42711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.waitForLayout(2); 42811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = 0; i < deleteStart; i++) { 42911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemViewType for existing item " + i + " should be called", 43011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 43111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 43211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemId for existing item " + i 43311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar + " should be called when adapter has stable ids", 43411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 43511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 43611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 43711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = deleteStart; i < deleteStart + deleteCount; i++) { 43811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called", 43911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 44011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 4418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called", 44211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 44311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 44411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 44511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 44611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 4478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testDeleteInvisibleMultiStep() throws Throwable { 4488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(1000, 1, 7); 4498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 4508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 4518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 4528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 4538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 4548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 4558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1}); 4568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount -= 2; 4578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 4598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 4608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 4618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 4638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddManyMultiStep() throws Throwable { 4668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10, 1, 7); 4678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 4688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 4698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 4708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 4718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 4728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 4738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(0, 1); 4748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(7, 1); 4758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount += 2; 4768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 4788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 4798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 4808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 4828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testBasicDelete() throws Throwable { 4858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 4868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() { 4878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 4888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void postDispatchLayout() { 4898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // verify this only in first layout 4908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("deleted views should still be children of RV", 4918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount() + mDeletedViewCount 4928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar , mRecyclerView.getChildCount()); 4938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 4948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 4958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 4968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 4978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AnimationLayoutManager layoutManager, 4988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 4998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 5008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutItemCount = 3; 5018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutMin = 0; 5028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 5048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.mLayoutItemCount = 10; 5058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.setExpectedItemCounts(10, 3); 5068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.setOnLayoutCallbacks(callbacks); 5078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(2); 5098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(0, 7); 5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.reset();// when animations end another layout will happen 5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 515d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void testAdapterChangeDuringScrolling() throws Throwable { 516d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar setupBasic(10); 517d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 518d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 519d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 520d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 521d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 522d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 523d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 524d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 525d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onLayoutChildren(recycler, lm, state); 526d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 527d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 528d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 529d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 530d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onScrollItemCount.set(state.getItemCount()); 531d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onScroll(dx, recycler, state); 532d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 533d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 534d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar runTestOnUiThread(new Runnable() { 535d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 536d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void run() { 537d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.remove(5); 538d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.notifyItemRangeRemoved(5, 1); 539d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mRecyclerView.scrollBy(0, 100); 540d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 541d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 542d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 543d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 544d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 545d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 546d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 547d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 548d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 549b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testAddInvisibleAndVisible() throws Throwable { 550b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 551b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 552b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible 554b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 555b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 556b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 557b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testAddInvisible() throws Throwable { 558b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 559b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 560b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0 562b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 563b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 564b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 565b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testBasicAdd() throws Throwable { 566b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10); 567b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 568b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(10, 13); 569b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.addAndNotify(2, 3); 570b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 571b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 572b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 573888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public TestRecyclerView getTestRecyclerView() { 574888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar return (TestRecyclerView) mRecyclerView; 575888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 576888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 577888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void testRemoveScrapInvalidate() throws Throwable { 578888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar setupBasic(10); 579888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar TestRecyclerView testRecyclerView = getTestRecyclerView(); 580888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.expectLayouts(1); 581888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.expectDraw(1); 582888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar runTestOnUiThread(new Runnable() { 583888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 584888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void run() { 585888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.mItems.clear(); 586888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.notifyDataSetChanged(); 587888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 588888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar }); 589888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.waitForLayout(2); 590888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.waitForDraw(2); 591888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 592888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 593b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testDeleteVisibleAndInvisible() throws Throwable { 594b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(11, 3, 5); //layout items 3 4 5 6 7 595b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 5968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list 597b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(9, 8); 598b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9 599b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 600b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 601b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 6028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testFindPositionOffset() throws Throwable { 6038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 6048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar runTestOnUiThread(new Runnable() { 6058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 6068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 6078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // [0,1,2,3,4] 6088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // delete 1 6098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.notifyItemRangeRemoved(1, 1); 6108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // delete 3 6118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.notifyItemRangeRemoved(2, 1); 6128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mAdapterHelper.preProcess(); 6138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // [0,2,4] 6148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0)); 6158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2)); 6168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4)); 6178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }); 6208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 622b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setLayoutRange(int start, int count) { 623b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start; 624b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count; 625b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 626b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 627b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setExpectedItemCounts(int preLayout, int postLayout) { 628b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout); 629b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 630b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 631b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testDeleteInvisible() throws Throwable { 632b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 6338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 6348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 635b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 636b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8); 6378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8 638b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 639b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 640b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 641e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar private CollectPositionResult findByPos(RecyclerView recyclerView, 642e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int position) { 643e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = recycler.getViewForPosition(position, true); 644e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 645e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (vh.wasReturnedFromScrap()) { 646e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar vh.clearReturnedFromScrapFlag(); //keep data consistent. 647e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromScrap(vh); 648e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } else { 649e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromAdapter(vh); 6508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 653e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView, 654e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) { 6558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positionToAdapterMapping 6568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar = new HashMap<Integer, CollectPositionResult>(); 6578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position : positions) { 6588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (position < 0) { 6598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar continue; 6608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 661e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionToAdapterMapping.put(position, 662e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar findByPos(recyclerView, recycler, state, position)); 6638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return positionToAdapterMapping; 6658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 6668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 6678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddDelete2() throws Throwable { 6688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 6698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 3 4 6708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 a b 3 4 6718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 b 3 4 6728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre: 0 1 2 3 4 6738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre w/ adap: 0 1 2 b 3 4 674d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 6758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 6768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2}); 677b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 6788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1), 6798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(3, 3, 3) 6808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 6818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 682d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 6838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddDelete1() throws Throwable { 6848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 6858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 3 4 6868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 a b 3 4 6878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 2 a b 3 4 6888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 c d 2 a b 3 4 6898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 c d 2 a 4 6908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // c d 2 a 4 6918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre: 0 1 2 3 4 692b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 6938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 6948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1}, 6958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1}); 696d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 6978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1), 6988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1), 6998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0), 7008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapter(1), PositionConstraint.adapter(3) 7018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 7028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddSameIndexTwice() throws Throwable { 7058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 7068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 7088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1}, 7098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{11, 1}); 7108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3), 7128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7), 7138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12), 7148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(8, 8, 13) 7158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 7168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testDeleteTwice() throws Throwable { 7198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 7208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 7228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1}, 7238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{0, 1});// delete item ids 0,2,9,1 7248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0), 7268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2), 7278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5), 7288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7) 7298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 7308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 732b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 7338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 734e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount, AdapterOps adapterChanges, 735e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 736e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null, 737e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapterChanges, constraints); 738e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 739e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 740e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount,TestAdapter adapter, AdapterOps adapterChanges, 741e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 742e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter); 743b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 7448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 7458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 7478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 7488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePreLayout(recycler, lm, state); 7498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar //harmless 7508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 7518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 7528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 7538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPreLayoutPos; 7548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 756e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 7578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 7588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPreLayoutPos != -1) { 7598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPreLayoutPos), 7608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.getLog()); 7618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 7658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 7678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 7688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePostLayout(recycler, lm, state); 7698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 7708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 7718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 7728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPostLayoutPos; 7738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 775e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 7768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 7778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPostLayoutPos >= 0) { 7788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPostLayoutPos), 7798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.getLog()); 7808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 7848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterChanges.run(mTestAdapter); 785b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 786e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 7878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 7888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.assertValidate(); 7898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 790b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 791b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 792b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar class AnimationLayoutManager extends TestLayoutManager { 793b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 7948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private int mTotalLayoutCount = 0; 7958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private String log; 7968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 797b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() { 798b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar }; 799b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 8008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 8018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 802b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 803c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase public boolean supportsPredictiveItemAnimations() { 804b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar return true; 805b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 806b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 8078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String getLog() { 8088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return log; 8098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 811668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) { 8128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar StringBuilder builder = new StringBuilder(); 813668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done); 814668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar builder.append("\nViewHolders:\n"); 8158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) { 8168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append(vh).append("\n"); 8178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append("scrap:\n"); 8198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.getScrapList()) { 8208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append(vh).append("\n"); 8218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 822668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 823668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (state.isPreLayout() && !done) { 8248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar log = "\n" + builder.toString(); 8258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 8268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar log += "\n" + builder.toString(); 8278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return log; 8298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 831b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 832b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void expectLayouts(int count) { 833b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.expectLayouts(count); 834b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.mLayoutCount = 0; 835b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 836b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 837b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) { 838b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks = onLayoutCallbacks; 839b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 840b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 841b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 842b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public final void onLayoutChildren(RecyclerView.Recycler recycler, 843b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 844b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar try { 8458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTotalLayoutCount++; 846668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar prepareLog(recycler, state, false); 847668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (state.isPreLayout()) { 848668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar validateOldPositions(recycler, state); 849668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 850668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar validateClearedOldPositions(recycler, state); 851668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 852b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.onLayoutChildren(recycler, this, state); 853668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar prepareLog(recycler, state, true); 854b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } finally { 855b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar layoutLatch.countDown(); 856d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 857b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 858b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 859668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private void validateClearedOldPositions(RecyclerView.Recycler recycler, 860668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.State state) { 861668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (getTestRecyclerView() == null) { 862668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 863668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 864668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) { 865668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertEquals("there should NOT be an old position in post layout", 866668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.NO_POSITION, viewHolder.mOldPosition); 867668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertEquals("there should NOT be a pre layout position in post layout", 868668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition); 869668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 870668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 871668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 872668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private void validateOldPositions(RecyclerView.Recycler recycler, 873668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.State state) { 874668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (getTestRecyclerView() == null) { 875668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 876668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 877668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) { 878668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) { 879668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertTrue("there should be an old position in pre-layout", 880668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar viewHolder.mOldPosition != RecyclerView.NO_POSITION); 881668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 882668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 883668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 884668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 8858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public int getTotalLayoutCount() { 8868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mTotalLayoutCount; 8878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 889d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 890d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public boolean canScrollVertically() { 891d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar return true; 892d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 893d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 894d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 895d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 896d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar RecyclerView.State state) { 897d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mOnLayoutCallbacks.onScroll(dy, recycler, state); 898d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar return super.scrollVerticallyBy(dy, recycler, state); 899d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 900b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 901b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void onPostDispatchLayout() { 902b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.postDispatchLayout(); 903b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 904b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 905b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 906b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable { 907b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.waitForLayout(timeout, timeUnit); 908b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar checkForMainThreadException(); 909b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 910d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 911d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 912b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar abstract class OnLayoutCallbacks { 913b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 914b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mLayoutMin = Integer.MIN_VALUE; 915b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 916b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mLayoutItemCount = Integer.MAX_VALUE; 917b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 918b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int expectedPreLayoutItemCount = -1; 919b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 920b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int expectedPostLayoutItemCount = -1; 921b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 922b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mDeletedViewCount; 923b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mLayoutCount = 0; 9258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 926b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void setExpectedItemCounts(int preLayout, int postLayout) { 927b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount = preLayout; 928b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount = postLayout; 929b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 930b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 931b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void reset() { 932b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutMin = Integer.MIN_VALUE; 933b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutItemCount = Integer.MAX_VALUE; 934b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount = -1; 935b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount = -1; 9368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutCount = 0; 937b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 938b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 939b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 940b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 941b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mDeletedViewCount = 0; 942b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar for (int i = 0; i < lm.getChildCount(); i++) { 943b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar View v = lm.getChildAt(i); 944b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (lm.getLp(v).isItemRemoved()) { 945b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mDeletedViewCount++; 946b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 947b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 948b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 949b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 950b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 951b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 952b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (DEBUG) { 953b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar Log.d(TAG, "item count " + state.getItemCount()); 954b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 955b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 956b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin; 957b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar final int count = mLayoutItemCount 958b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount; 959c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.layoutRange(recycler, start, start + count); 960b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("correct # of children should be laid out", 961c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar count, lm.getChildCount()); 9628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.assertVisibleItemPositions(); 963b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 964b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 965b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 966b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 967b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 969b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (expectedPreLayoutItemCount != -1) { 970b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("on pre layout, state should return abstracted adapter size", 971b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount, state.getItemCount()); 972b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 973b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar beforePreLayout(recycler, lm, state); 9748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 975b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (expectedPostLayoutItemCount != -1) { 976b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("on post layout, state should return real adapter size", 977b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount, state.getItemCount()); 978b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 979b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar beforePostLayout(recycler, lm, state); 980b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 981b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar doLayout(recycler, lm, state); 9828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 983b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar afterPreLayout(recycler, lm, state); 9848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 985b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar afterPostLayout(recycler, lm, state); 986b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 987b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutCount++; 988b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 989b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 990b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 991b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 992b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 993b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 994b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 995b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 996b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 997b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 998b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 999b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1000b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1001b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1002b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void postDispatchLayout() { 1003b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1004b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1005d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 1006d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1007d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1008b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1009b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1010b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar class TestRecyclerView extends RecyclerView { 101111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 1012888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar CountDownLatch drawLatch; 1013b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1014b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context) { 1015b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context); 1016b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1017b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1018b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context, AttributeSet attrs) { 1019b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context, attrs); 1020b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1021b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1022b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) { 1023b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context, attrs, defStyle); 1024b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1025b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 10268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 10278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void initAdapterManager() { 10288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.initAdapterManager(); 10298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mAdapterHelper.mOnItemProcessedCallback = new Runnable() { 10308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 10318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 10328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validatePostUpdateOp(); 10338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 10358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1037888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void expectDraw(int count) { 1038888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch = new CountDownLatch(count); 1039888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1040888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 1041888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void waitForDraw(long timeout) throws Throwable { 1042888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS); 1043888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar assertEquals("all expected draws should happen at the expected time frame", 1044888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 0, drawLatch.getCount()); 1045888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1046888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 10478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar List<ViewHolder> collectViewHolders() { 10488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar List<ViewHolder> holders = new ArrayList<ViewHolder>(); 10498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int childCount = getChildCount(); 10508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < childCount; i++) { 10518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder holder = getChildViewHolderInt(getChildAt(i)); 10528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (holder != null) { 10538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar holders.add(holder); 10548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return holders; 10578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 10598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 10608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validateViewHolderPositions() { 10618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final Set<Integer> existingOffsets = new HashSet<Integer>(); 1062668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int childCount = getChildCount(); 1063668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar StringBuilder log = new StringBuilder(); 10648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < childCount; i++) { 10658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder vh = getChildViewHolderInt(getChildAt(i)); 1066668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 1067668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar log.append(tvh.mBindedItem).append(vh) 1068668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append(" hidden:") 1069668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append(mChildHelper.mHiddenViews.contains(vh.itemView)) 1070668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append("\n"); 1071668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1072668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int i = 0; i < childCount; i++) { 1073668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ViewHolder vh = getChildViewHolderInt(getChildAt(i)); 1074668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (vh.isInvalid()) { 1075668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar continue; 1076668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1077668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (vh.getPosition() < 0) { 1078668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar LayoutManager lm = getLayoutManager(); 1079668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int j = 0; j < lm.getChildCount(); j ++) { 1080668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertNotSame("removed view holder should not be in LM's child list", 1081668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar vh.itemView, lm.getChildAt(j)); 10828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1083668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) { 10848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (!existingOffsets.add(vh.getPosition())) { 1085668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar throw new IllegalStateException("view holder position conflict for " 1086668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + "existing views " + vh + "\n" + log); 10878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 10928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void validatePostUpdateOp() { 10938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar try { 10948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validateViewHolderPositions(); 10958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (super.mState.isPreLayout()) { 10968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager()); 10978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validateAdapterPosition((AnimationLayoutManager) getLayoutManager()); 10998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } catch (Throwable t) { 11008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar postExceptionToInstrumentation(t); 11018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validateAdapterPosition(AnimationLayoutManager lm) { 11078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (ViewHolder vh : collectViewHolders()) { 11088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) { 11098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("adapter position calculations should match view holder " 1110668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + "pre layout:" + mState.isPreLayout() 1111668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + " positions\n" + vh + "\n" + lm.getLog(), 11128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition); 11138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // ensures pre layout positions are continuous block. This is not necessarily a case 11188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // but valid in test RV 11198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validatePreLayoutSequence(AnimationLayoutManager lm) { 11208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Set<Integer> preLayoutPositions = new HashSet<Integer>(); 11218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (ViewHolder vh : collectViewHolders()) { 11228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertTrue("pre layout positions should be distinct " + lm.getLog(), 11238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar preLayoutPositions.add(vh.mPreLayoutPosition)); 11248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int minPos = Integer.MAX_VALUE; 11268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (Integer pos : preLayoutPositions) { 11278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (pos < minPos) { 11288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar minPos = pos; 11298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 1; i < preLayoutPositions.size(); i++) { 11328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull("next position should exist " + lm.getLog(), 11338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar preLayoutPositions.contains(minPos + i)); 11348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1137888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 1138888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar protected void dispatchDraw(Canvas canvas) { 1139888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar super.dispatchDraw(canvas); 1140888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar if (drawLatch != null) { 1141888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch.countDown(); 1142888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1143888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1144888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 1145b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 1146b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void dispatchLayout() { 1147b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar try { 1148b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.dispatchLayout(); 1149b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (getLayoutManager() instanceof AnimationLayoutManager) { 1150b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout(); 1151b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1152b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } catch (Throwable t) { 1153b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar postExceptionToInstrumentation(t); 1154b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1155b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1156b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1157b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 11588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar abstract class AdapterOps { 11628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final public void run(TestAdapter adapter) throws Throwable { 11648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar onRun(adapter); 11658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar abstract void onRun(TestAdapter testAdapter) throws Throwable; 11688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class CollectPositionResult { 11718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // true if found in scrap 11738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public RecyclerView.ViewHolder scrapResult; 11748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public RecyclerView.ViewHolder adapterResult; 11768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) { 11788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar CollectPositionResult cpr = new CollectPositionResult(); 11798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar cpr.scrapResult = viewHolder; 11808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return cpr; 11818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) { 11848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar CollectPositionResult cpr = new CollectPositionResult(); 11858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar cpr.adapterResult = viewHolder; 11868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return cpr; 11878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class PositionConstraint { 11918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static enum Type { 11938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar scrap, 11948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter, 11958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterScrap /*first pass adapter, second pass scrap*/ 11968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 11978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 11988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Type mType; 11998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mOldPos; // if VH 12018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mPreLayoutPos; 12038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mPostLayoutPos; 12058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mValidateCount = 0; 12078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) { 12098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 12108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.scrap; 12118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = oldPos; 12128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = preLayoutPos; 12138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = postLayoutPos; 12148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 12158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint adapterScrap(int preLayoutPos, int position) { 12188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 12198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.adapterScrap; 12208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = RecyclerView.NO_POSITION; 12218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = preLayoutPos; 12228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = position;// adapter pos does not change 12238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 12248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint adapter(int position) { 12278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 12288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.adapter; 12298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = RecyclerView.NO_POSITION; 12308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = RecyclerView.NO_POSITION; 12318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = position;// adapter pos does not change 12328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 12338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void assertValidate() { 12368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int expectedValidate = 0; 12378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mPreLayoutPos >= 0) { 12388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar expectedValidate ++; 12398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mPostLayoutPos >= 0) { 12418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar expectedValidate ++; 12428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("should run all validates", expectedValidate, mValidateCount); 12448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String toString() { 12488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "Cons{" + 12498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar "t=" + mType.name() + 12508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", old=" + mOldPos + 12518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", pre=" + mPreLayoutPos + 12528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", post=" + mPostLayoutPos + 12538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar '}'; 12548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void validate(RecyclerView.State state, CollectPositionResult result, String log) { 12578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mValidateCount ++; 12588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should not be null\n" + log, result); 12598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.ViewHolder viewHolder; 12608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) { 12618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult); 12628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder = result.scrapResult; 12638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 12648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should come from adapter\n" + log, 12658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result.adapterResult); 12668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": old position should be none when it came from adapter\n" + log, 12678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.NO_POSITION, result.adapterResult.getOldPosition()); 12688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder = result.adapterResult; 12698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 12718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos, 1272e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition : 12738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder.mPreLayoutPosition); 12748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos, 12758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder.getPosition()); 12768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mType == Type.scrap) { 12778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": old position should match\n" + log, mOldPos, 12788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result.scrapResult.getOldPosition()); 1279b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 12808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult 12818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar .isRemoved()) { 1282e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals(this + ": post-layout position should match\n" + log + "\n\n" 1283e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar + viewHolder, mPostLayoutPos, viewHolder.getPosition()); 1284b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1285b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1286b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1287d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase} 1288