RecyclerViewAnimationsTest.java revision a75ca911e26945e0b326e7b70dd12378ace80270
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 930ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar public void testDetachBeforeAnimations() throws Throwable { 940ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar setupBasic(10, 0, 5); 950ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final RecyclerView rv = mRecyclerView; 960ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar waitForAnimations(2); 970ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator() { 980ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar @Override 990ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar public void runPendingAnimations() { 1000ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar super.runPendingAnimations(); 1010ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 1020ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar }; 1030ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar rv.setItemAnimator(animator); 1040ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.expectLayouts(2); 1050ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mTestAdapter.deleteAndNotify(3, 4); 1060ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.waitForLayout(2); 1070ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar removeRecyclerView(); 1080ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertNull("test sanity check RV should be removed", rv.getParent()); 1090ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size()); 1100ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertFalse("there should not be any animations running", animator.isRunning()); 1110ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 1120ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar 11342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar public void testPreLayoutPositionCleanup() throws Throwable { 11442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar setupBasic(4, 0, 4); 11542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.expectLayouts(2); 11642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 11742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 11842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 11942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 12042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 12142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 3; 12242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 12342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 12442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 12542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 12642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager layoutManager, 12742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state) { 12842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 12942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 4; 13042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 13142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar }; 13242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mTestAdapter.addAndNotify(0, 1); 13342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.waitForLayout(2); 13442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 13542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 13642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 13742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 13842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 13993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void testAddRemoveSamePass() throws Throwable { 14093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final List<RecyclerView.ViewHolder> mRecycledViews 14193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 14293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar TestAdapter adapter = new TestAdapter(50) { 14393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 14493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 14593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.onViewRecycled(holder); 14693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.add(holder); 14793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 14893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 14993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar adapter.setHasStableIds(true); 15093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar setupBasic(50, 3, 5, adapter); 15193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemViewCacheSize(0); 15293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> addVH 15393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 15493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> removeVH 15593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 15693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 15793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> moveVH 15893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 15993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 16093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final View[] testView = new View[1]; 16193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 16293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 16393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateAdd(RecyclerView.ViewHolder holder) { 16493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar addVH.add(holder); 16593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 16693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 16793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 16893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 16993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 17093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar removeVH.add(holder); 17193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 17293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 17393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 17493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 17593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, 17693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar int toX, int toY) { 17793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar moveVH.add(holder); 17893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 17993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 18093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }); 18193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 18293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 18393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 18493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 18593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 18693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 18793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0] = recycler.getViewForPosition(45); 18893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST), 18993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST)); 19093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(), 19193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 10 + testView[0].getMeasuredHeight()); 19293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addView(testView[0], 4); 19393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 19493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 19593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 19693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 19793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 19893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 19993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPostLayout(recycler, layoutManager, state); 20093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(), 20193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 50 + testView[0].getMeasuredHeight()); 20293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addDisappearingView(testView[0], 4); 20393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 20493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 20593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3; 20693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5; 20793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.clear(); 20893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.expectLayouts(2); 20993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mTestAdapter.deleteAndNotify(3, 1); 21093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.waitForLayout(2); 21193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 21293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : addVH) { 21393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate add", testView[0], vh.itemView); 21493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 21593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : moveVH) { 21693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate move", testView[0], vh.itemView); 21793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 21893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : removeVH) { 21993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView); 22093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 22193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar boolean found = false; 22293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : mRecycledViews) { 22393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar found |= vh.itemView == testView[0]; 22493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 22593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertTrue("added-removed view should be recycled", found); 22693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 22793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 2287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void testChangeAnimations() throws Throwable { 2297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean[] booleans = {true, false}; 2307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean supportsChange : booleans) { 2317c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean changeType : booleans) { 2327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean hasStableIds : booleans) { 2337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean deleteSomeItems : booleans) { 2347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems); 2357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen removeRecyclerView(); 2377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2387c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType, 2427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable { 2437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int changedIndex = 3; 2447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int defaultType = 1; 2457c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType); 2467c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim + 2477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", change view type:" + changeType + 2487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", has stable ids:" + hasStableIds + 2497c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", force predictive:" + deleteSomeItems; 2507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestAdapter testAdapter = new TestAdapter(10) { 2517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public int getItemViewType(int position) { 2537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return position == changedIndex ? changedIndexNewType.get() : defaultType; 2547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2557c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2577c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public TestViewHolder onCreateViewHolder(ViewGroup parent, 2587c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int viewType) { 2597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 2607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 2617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onCreateVH" + vh.toString()); 2627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return vh; 2647c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2657c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2667c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2677c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void onBindViewHolder(TestViewHolder holder, 2687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int position) { 2697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.onBindViewHolder(holder, position); 2707c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 2717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString()); 2727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 2757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen testAdapter.setHasStableIds(hasStableIds); 2767c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 2777c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim); 2787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2797c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final RecyclerView.ViewHolder toBeChangedVH = 280115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar mRecyclerView.findViewHolderForLayoutPosition(changedIndex); 2817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPreLayout(RecyclerView.Recycler recycler, 2847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, 2857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.State state) { 286115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 287115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 2887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 2897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertTrue(logPrefix + " changed view holder should have correct flag" 2907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen , vh.isChanged()); 2917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 2927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertFalse(logPrefix + " changed view holder should have correct flag" 2937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen , vh.isChanged()); 2947c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 2967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 2977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 2987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPostLayout(RecyclerView.Recycler recycler, 2997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, RecyclerView.State state) { 300115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 301115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 3027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertFalse(logPrefix + "VH should not be marked as changed", vh.isChanged()); 3037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 3047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertNotSame(logPrefix + "a new VH should be given if change is supported", 3057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen toBeChangedVH, vh); 3067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else if (!changeType && hasStableIds) { 3077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertSame(logPrefix + "if change animations are not supported but we have " 3087c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen + "stable ids, same view holder should be returned", toBeChangedVH, vh); 3097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3107c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.beforePostLayout(recycler, layoutManager, state); 3117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 3137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.expectLayouts(1); 3147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (changeType) { 3157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changedIndexNewType.set(defaultType + 1); 3167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (deleteSomeItems) { 3187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen runTestOnUiThread(new Runnable() { 3197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 3207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void run() { 3217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen try { 3227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.deleteAndNotify(changedIndex + 2, 1); 3237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 3247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } catch (Throwable throwable) { 3257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen throwable.printStackTrace(); 3267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 3287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }); 3307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 3317c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 3327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 3347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.waitForLayout(2); 3357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 3367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 337504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void testRecycleDuringAnimations() throws Throwable { 338504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 339504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(1000) { 340504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 341504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 342504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 343504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 344504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return super.onCreateViewHolder(parent, viewType); 345504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 346504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 347504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar setupBasic(1000, 10, 20, adapter); 348504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10; 349504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20; 350504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 351504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 352504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 353504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 354504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 355504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.decrementAndGet(); 356504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 357504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 358504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 359504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 360504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 361504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 362504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 363504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 364504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 365504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 366504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }); 367504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 368504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 369504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar for (int i = 0; i < 100; i ++) { 370504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 371504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(50); 372504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 373504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 374504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 375504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 376504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 377504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 378504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 379b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void testNotifyDataSetChanged() throws Throwable { 380b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar setupBasic(10, 3, 4); 381b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar int layoutCount = mLayoutManager.mTotalLayoutCount; 382b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(1); 383b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar runTestOnUiThread(new Runnable() { 384b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar @Override 385b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void run() { 386b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar try { 387b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.deleteAndNotify(4, 1); 388cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase mTestAdapter.dispatchDataSetChanged(); 389b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } catch (Throwable throwable) { 390b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar throwable.printStackTrace(); 391b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 392b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 393b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 394b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar }); 395b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 396b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar getInstrumentation().waitForIdleSync(); 397b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("on notify data set changed, predictive animations should not run", 398b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar layoutCount + 1, mLayoutManager.mTotalLayoutCount); 399b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(2); 400b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.addAndNotify(4, 2); 401b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar // make sure animations recover 402b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 403b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 404b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 405e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void testStableIdNotifyDataSetChanged() throws Throwable { 406e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int itemCount = 20; 407e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar List<Item> initialSet = new ArrayList<Item>(); 408e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(itemCount) { 409e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 410e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 411e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 412e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 413e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 414e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 415e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar initialSet.addAll(adapter.mItems); 416e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() { 417e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 418e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar void onRun(TestAdapter testAdapter) throws Throwable { 419e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item5 = adapter.mItems.get(5); 420e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar Item item6 = adapter.mItems.get(6); 421e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar item5.mAdapterIndex = 6; 422e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar item6.mAdapterIndex = 5; 423e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.mItems.remove(5); 424e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.mItems.add(6, item5); 425cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase adapter.dispatchDataSetChanged(); 426e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar //hacky, we support only 1 layout pass 427e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar mLayoutManager.layoutLatch.countDown(); 428e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 429e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6), 430e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8), 431e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(9, -1, 9)); 432e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // now mix items. 433e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 434e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 435d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 4368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testGetItemForDeletedView() throws Throwable { 4378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(false); 4388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(true); 43911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 44011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 4418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void getItemForDeletedViewTest(boolean stableIds) throws Throwable { 44211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemViewTypeQueries = new HashSet<Integer>(); 44311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemIdQueries = new HashSet<Integer>(); 44411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter adapter = new TestAdapter(10) { 44511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 44611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public int getItemViewType(int position) { 44711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.add(position); 44811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return super.getItemViewType(position); 44911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 45011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 45111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 45211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public long getItemId(int position) { 45311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.add(position); 45411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return mItems.get(position).mId; 45511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 45611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar }; 45711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.setHasStableIds(stableIds); 45811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar setupBasic(10, 0, 10, adapter); 45911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemViewType for all items should be called", 10, 46011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.size()); 46111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 46211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should be called when adapter has stable ids", 10, 46311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 46411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 46511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should not be called when adapter does not have stable ids", 0, 46611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 46711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 46811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.clear(); 46911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.clear(); 47011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.expectLayouts(2); 47111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar // delete last two 47211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteStart = 8; 47311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteCount = adapter.getItemCount() - deleteStart; 47411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.deleteAndNotify(deleteStart, deleteCount); 47511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.waitForLayout(2); 47611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = 0; i < deleteStart; i++) { 47711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemViewType for existing item " + i + " should be called", 47811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 47911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 48011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemId for existing item " + i 48111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar + " should be called when adapter has stable ids", 48211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 48311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 48411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 48511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = deleteStart; i < deleteStart + deleteCount; i++) { 48611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called", 48711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 48811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 4898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called", 49011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 49111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 49211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 49311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 49411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 4958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testDeleteInvisibleMultiStep() throws Throwable { 4968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(1000, 1, 7); 4978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 4988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 4998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 5008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 5018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 5028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 5038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1}); 50490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 5058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount -= 2; 5068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 5088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 5098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 5108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 5128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddManyMultiStep() throws Throwable { 5158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10, 1, 7); 5168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 5178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 5188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 5198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 5208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 5218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 5228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(0, 1); 5238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(7, 1); 5248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount += 2; 5258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 5278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 5288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 5298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 5318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testBasicDelete() throws Throwable { 5348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 5358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() { 5368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 5378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void postDispatchLayout() { 5388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // verify this only in first layout 5398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("deleted views should still be children of RV", 5408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount() + mDeletedViewCount 5418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar , mRecyclerView.getChildCount()); 5428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 5458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 5468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AnimationLayoutManager layoutManager, 5478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 5488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 5498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutItemCount = 3; 5508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutMin = 0; 5518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 5538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.mLayoutItemCount = 10; 5548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.setExpectedItemCounts(10, 3); 5558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.setOnLayoutCallbacks(callbacks); 5568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(2); 5588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(0, 7); 5598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 5608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.reset();// when animations end another layout will happen 5618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 5628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 5638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 564d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void testAdapterChangeDuringScrolling() throws Throwable { 565d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar setupBasic(10); 566d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 567d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 568d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 569d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 570d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 571d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 572d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 573d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 574d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onLayoutChildren(recycler, lm, state); 575d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 576d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 577d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 578d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 579d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onScrollItemCount.set(state.getItemCount()); 580d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onScroll(dx, recycler, state); 581d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 582d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 583d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar runTestOnUiThread(new Runnable() { 584d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 585d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void run() { 586d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.remove(5); 587d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.notifyItemRangeRemoved(5, 1); 588d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mRecyclerView.scrollBy(0, 100); 589d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 590d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 591d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 592d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 593d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 594d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 595d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 596d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 597d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 59817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void testNotifyDataSetChangedDuringScroll() throws Throwable { 59917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar setupBasic(10); 60017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 60117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 60217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 60317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 60417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 60517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 60617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 60717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 60817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onLayoutChildren(recycler, lm, state); 60917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 61017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 61117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 61217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 61317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onScrollItemCount.set(state.getItemCount()); 61417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onScroll(dx, recycler, state); 61517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 61617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 61717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar runTestOnUiThread(new Runnable() { 61817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 61917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void run() { 62017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.remove(5); 62117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.notifyDataSetChanged(); 62217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mRecyclerView.scrollBy(0, 100); 62317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 62417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 62517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 62617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 62717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 62817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 62917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 63017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 63117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 632b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testAddInvisibleAndVisible() throws Throwable { 633b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 634b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 635b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 6362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible 637b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 638b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 639b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 640b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testAddInvisible() throws Throwable { 641b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 642b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 643b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 6442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0 645b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 646b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 647b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 648b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testBasicAdd() throws Throwable { 649b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10); 650b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 651b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(10, 13); 652b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.addAndNotify(2, 3); 653b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 654b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 655b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 656a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void testAppCancelAnimationInDetach() throws Throwable { 657a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu final View[] addedView = new View[2]; 658a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu TestAdapter adapter = new TestAdapter(1) { 659a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 660a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void onViewDetachedFromWindow(TestViewHolder holder) { 661a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView) 662a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu && holder.itemView.hasTransientState()) { 663a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu holder.itemView.animate().cancel(); 664a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 665a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu super.onViewDetachedFromWindow(holder); 666a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 667a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 668a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // original 1 item 669a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setupBasic(1, 0, 1, adapter); 670a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mRecyclerView.getItemAnimator().setAddDuration(3000); 671a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(2); 672a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 673a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // add 2 items 674a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setExpectedItemCounts(1, 3); 675a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mTestAdapter.addAndNotify(0, 2); 676a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.waitForLayout(2); 677a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 678a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // wait till "add animation" starts 679a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu while (addedView[0] == null || addedView[1] == null) { 680a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu Thread.sleep(20); 681a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu runTestOnUiThread(new Runnable() { 682a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 683a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void run() { 684a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (mRecyclerView.getChildCount() == 3) { 685a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu View view = mRecyclerView.getChildAt(0); 686a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (view.hasTransientState()) { 687a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[0] = view; 688a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 689a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu view = mRecyclerView.getChildAt(1); 690a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (view.hasTransientState()) { 691a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[1] = view; 692a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 693a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 694a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 695a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }); 696a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 697a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 698a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // Layout from item2, exclude the current adding items 699a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(1); 700a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 701a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 702a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu void beforePostLayout(RecyclerView.Recycler recycler, 703a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu AnimationLayoutManager layoutManager, 704a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu RecyclerView.State state) { 705a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutMin = 2; 706a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutItemCount = 1; 707a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 708a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 709a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu requestLayoutOnUIThread(mRecyclerView); 710a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.waitForLayout(2); 711a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 712a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 713888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public TestRecyclerView getTestRecyclerView() { 714888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar return (TestRecyclerView) mRecyclerView; 715888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 716888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 717888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void testRemoveScrapInvalidate() throws Throwable { 718888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar setupBasic(10); 719888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar TestRecyclerView testRecyclerView = getTestRecyclerView(); 720888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.expectLayouts(1); 721888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.expectDraw(1); 722888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar runTestOnUiThread(new Runnable() { 723888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 724888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void run() { 725888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.mItems.clear(); 726888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.notifyDataSetChanged(); 727888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 728888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar }); 729888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.waitForLayout(2); 730888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.waitForDraw(2); 731888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 732888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 733b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testDeleteVisibleAndInvisible() throws Throwable { 734b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(11, 3, 5); //layout items 3 4 5 6 7 735b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 7368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list 737b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(9, 8); 738b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9 739b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 740b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 741b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 7428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testFindPositionOffset() throws Throwable { 7438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 74490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 74590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar @Override 74690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 74790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 74890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar super.beforePreLayout(recycler, lm, state); 74990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar // [0,2,4] 75090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0)); 75190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2)); 75290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4)); 75390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar } 75490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }; 7558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar runTestOnUiThread(new Runnable() { 7568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 7578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 7588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // [0,1,2,3,4] 7598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // delete 1 7608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.notifyItemRangeRemoved(1, 1); 7618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // delete 3 7628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.notifyItemRangeRemoved(2, 1); 7638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }); 76590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.waitForLayout(2); 7668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 768b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setLayoutRange(int start, int count) { 769b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start; 770b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count; 771b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 772b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 773b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setExpectedItemCounts(int preLayout, int postLayout) { 774b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout); 775b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 776b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 777b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void testDeleteInvisible() throws Throwable { 778b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 7798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 7808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 781b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 782b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8); 7838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8 784b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 785b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 786b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 787e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar private CollectPositionResult findByPos(RecyclerView recyclerView, 788e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int position) { 789e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = recycler.getViewForPosition(position, true); 790e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 791e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (vh.wasReturnedFromScrap()) { 792e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar vh.clearReturnedFromScrapFlag(); //keep data consistent. 793e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromScrap(vh); 794e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } else { 795e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromAdapter(vh); 7968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 7988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 799e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView, 800e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) { 8018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positionToAdapterMapping 8028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar = new HashMap<Integer, CollectPositionResult>(); 8038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position : positions) { 8048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (position < 0) { 8058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar continue; 8068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 807e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionToAdapterMapping.put(position, 808e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar findByPos(recyclerView, recycler, state, position)); 8098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return positionToAdapterMapping; 8118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 8138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddDelete2() throws Throwable { 8148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 8158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 3 4 8168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 a b 3 4 8178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 b 3 4 8188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre: 0 1 2 3 4 8198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre w/ adap: 0 1 2 b 3 4 820d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase @Override 8218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 8228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2}); 823b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 8248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1), 8258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(3, 3, 3) 8268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 8278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 828d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 8298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddDelete1() throws Throwable { 8308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 8318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 3 4 8328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 1 2 a b 3 4 8338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 2 a b 3 4 8348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 c d 2 a b 3 4 8358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // 0 c d 2 a 4 8368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // c d 2 a 4 8378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // pre: 0 1 2 3 4 838b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 8398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 8408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1}, 8418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1}); 842d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 8438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1), 8448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1), 8458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0), 8468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapter(1), PositionConstraint.adapter(3) 8478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 8488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 8508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testAddSameIndexTwice() throws Throwable { 8518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 8528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 8538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 8548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1}, 8558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{11, 1}); 8568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3), 8588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7), 8598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12), 8608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(8, 8, 13) 8618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 8628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 8648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void testDeleteTwice() throws Throwable { 8658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 8668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 8678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void onRun(TestAdapter adapter) throws Throwable { 8688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1}, 8698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar new int[]{0, 1});// delete item ids 0,2,9,1 8708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0), 8728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2), 8738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5), 8748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7) 8758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 8768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 8778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 878b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 8798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 880e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount, AdapterOps adapterChanges, 881e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 882e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null, 883e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapterChanges, constraints); 884e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 885e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 886e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount,TestAdapter adapter, AdapterOps adapterChanges, 887e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 888e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter); 889b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 8908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 8918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 8928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 8938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 8948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePreLayout(recycler, lm, state); 8958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar //harmless 8968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 8978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 8988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 8998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPreLayoutPos; 9008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 902e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 9038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 9048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPreLayoutPos != -1) { 9058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPreLayoutPos), 9068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.getLog()); 9078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 9118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 9128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 9138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 9148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePostLayout(recycler, lm, state); 9158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 9168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 9178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 9188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPostLayoutPos; 9198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 921e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 9228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 9238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPostLayoutPos >= 0) { 9248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPostLayoutPos), 9258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.getLog()); 9268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 9308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterChanges.run(mTestAdapter); 931b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 932e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 9338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 9348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.assertValidate(); 9358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 936b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 937b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 938b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar class AnimationLayoutManager extends TestLayoutManager { 939b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private int mTotalLayoutCount = 0; 9418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private String log; 9428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 943b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() { 944b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar }; 945b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 9478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 948b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 949c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase public boolean supportsPredictiveItemAnimations() { 950b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar return true; 951b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 952b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 9538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String getLog() { 9548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return log; 9558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 957668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) { 9588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar StringBuilder builder = new StringBuilder(); 959668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done); 960668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar builder.append("\nViewHolders:\n"); 9618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) { 9628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append(vh).append("\n"); 9638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append("scrap:\n"); 9658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.getScrapList()) { 9668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar builder.append(vh).append("\n"); 9678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 968668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 969668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (state.isPreLayout() && !done) { 9708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar log = "\n" + builder.toString(); 9718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 9728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar log += "\n" + builder.toString(); 9738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return log; 9758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 9768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 977b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 978b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void expectLayouts(int count) { 979b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.expectLayouts(count); 980b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.mLayoutCount = 0; 981b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 982b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 983b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) { 984b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks = onLayoutCallbacks; 985b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 986b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 987b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 988b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public final void onLayoutChildren(RecyclerView.Recycler recycler, 989b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 990b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar try { 9918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTotalLayoutCount++; 992668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar prepareLog(recycler, state, false); 993668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (state.isPreLayout()) { 994668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar validateOldPositions(recycler, state); 995668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 996668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar validateClearedOldPositions(recycler, state); 997668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 998b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.onLayoutChildren(recycler, this, state); 999668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar prepareLog(recycler, state, true); 1000b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } finally { 1001b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar layoutLatch.countDown(); 1002d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 1003b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1004b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1005668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private void validateClearedOldPositions(RecyclerView.Recycler recycler, 1006668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.State state) { 1007668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (getTestRecyclerView() == null) { 1008668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 1009668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1010668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) { 1011668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertEquals("there should NOT be an old position in post layout", 1012668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.NO_POSITION, viewHolder.mOldPosition); 1013668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertEquals("there should NOT be a pre layout position in post layout", 1014668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition); 1015668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1016668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1017668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 1018668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private void validateOldPositions(RecyclerView.Recycler recycler, 1019668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.State state) { 1020668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (getTestRecyclerView() == null) { 1021668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 1022668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1023668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) { 1024668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) { 1025668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertTrue("there should be an old position in pre-layout", 1026668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar viewHolder.mOldPosition != RecyclerView.NO_POSITION); 1027668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1028668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1029668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1030668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 10318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public int getTotalLayoutCount() { 10328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return mTotalLayoutCount; 10338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 10348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1035d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1036d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public boolean canScrollVertically() { 1037d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar return true; 1038d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1039d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1040d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1041d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 1042d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar RecyclerView.State state) { 1043d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mOnLayoutCallbacks.onScroll(dy, recycler, state); 1044d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar return super.scrollVerticallyBy(dy, recycler, state); 1045d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1046b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1047b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void onPostDispatchLayout() { 1048b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mOnLayoutCallbacks.postDispatchLayout(); 1049b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1050b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1051b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 1052b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable { 1053b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.waitForLayout(timeout, timeUnit); 1054b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar checkForMainThreadException(); 1055b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1056d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 1057d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 1058b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar abstract class OnLayoutCallbacks { 1059b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1060b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mLayoutMin = Integer.MIN_VALUE; 1061b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1062b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mLayoutItemCount = Integer.MAX_VALUE; 1063b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1064b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int expectedPreLayoutItemCount = -1; 1065b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1066b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int expectedPostLayoutItemCount = -1; 1067b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1068b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar int mDeletedViewCount; 1069b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 10708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mLayoutCount = 0; 10718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1072b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void setExpectedItemCounts(int preLayout, int postLayout) { 1073b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount = preLayout; 1074b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount = postLayout; 1075b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1076b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1077b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void reset() { 1078b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutMin = Integer.MIN_VALUE; 1079b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutItemCount = Integer.MAX_VALUE; 1080b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount = -1; 1081b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount = -1; 10828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutCount = 0; 1083b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1084b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1085b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 1086b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 1087b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mDeletedViewCount = 0; 1088b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar for (int i = 0; i < lm.getChildCount(); i++) { 1089b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar View v = lm.getChildAt(i); 1090b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (lm.getLp(v).isItemRemoved()) { 1091b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mDeletedViewCount++; 1092b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1093b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1094b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1095b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1096b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 1097b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1098b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (DEBUG) { 1099b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar Log.d(TAG, "item count " + state.getItemCount()); 1100b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1101b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 1102b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin; 1103b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar final int count = mLayoutItemCount 1104b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount; 1105c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar lm.layoutRange(recycler, start, start + count); 1106b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("correct # of children should be laid out", 1107c8b0ff5869e17a656a3a1d7fb306efa5b99fa07fYigit Boyar count, lm.getChildCount()); 11088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.assertVisibleItemPositions(); 1109b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1110b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 111142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) { 111242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) { 111342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertPreLayoutPosition(vh); 111442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 111542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 111642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 111742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) { 111842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar for (int i = 0; i < lm.getChildCount(); i ++) { 111942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar final RecyclerView.ViewHolder vh = mRecyclerView 112042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar .getChildViewHolder(lm.getChildAt(i)); 112142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertPreLayoutPosition(vh); 112242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 112342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 112442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 112542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) { 112642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertEquals("in post layout, there should not be a view holder w/ a pre " 112742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition); 112842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertEquals("in post layout, there should not be a view holder w/ an old " 112942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition); 113042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 113142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 1132b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 1133b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1134b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 11358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 1136b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (expectedPreLayoutItemCount != -1) { 1137b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("on pre layout, state should return abstracted adapter size", 1138b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPreLayoutItemCount, state.getItemCount()); 1139b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1140b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar beforePreLayout(recycler, lm, state); 11418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1142b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (expectedPostLayoutItemCount != -1) { 1143b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar assertEquals("on post layout, state should return real adapter size", 1144b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar expectedPostLayoutItemCount, state.getItemCount()); 1145b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1146b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar beforePostLayout(recycler, lm, state); 1147b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 114842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar if (!state.isPreLayout()) { 114942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertNoPreLayoutPosition(recycler); 115042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 1151b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar doLayout(recycler, lm, state); 11528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 1153b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar afterPreLayout(recycler, lm, state); 11548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 1155b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar afterPostLayout(recycler, lm, state); 115642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar assertNoPreLayoutPosition(lm); 1157b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1158b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutCount++; 1159b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1160b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1161b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 1162b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1163b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1164b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1165b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 1166b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1167b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1168b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1169b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager, 1170b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar RecyclerView.State state) { 1171b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1172b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1173b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void postDispatchLayout() { 1174b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1175b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1176d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 1177d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1178d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1179b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1180b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1181b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar class TestRecyclerView extends RecyclerView { 118211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 1183888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar CountDownLatch drawLatch; 1184b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1185b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context) { 1186b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context); 1187b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1188b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1189b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context, AttributeSet attrs) { 1190b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context, attrs); 1191b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1192b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1193b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) { 1194b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super(context, attrs, defStyle); 1195b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1196b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 11978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 11988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void initAdapterManager() { 11998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.initAdapterManager(); 12008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mAdapterHelper.mOnItemProcessedCallback = new Runnable() { 12018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 12038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validatePostUpdateOp(); 12048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 12068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1208888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void expectDraw(int count) { 1209888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch = new CountDownLatch(count); 1210888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1211888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 1212888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void waitForDraw(long timeout) throws Throwable { 1213888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS); 1214888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar assertEquals("all expected draws should happen at the expected time frame", 1215888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 0, drawLatch.getCount()); 1216888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1217888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 12188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar List<ViewHolder> collectViewHolders() { 12198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar List<ViewHolder> holders = new ArrayList<ViewHolder>(); 12208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int childCount = getChildCount(); 12218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < childCount; i++) { 12228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder holder = getChildViewHolderInt(getChildAt(i)); 12238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (holder != null) { 12248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar holders.add(holder); 12258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return holders; 12288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validateViewHolderPositions() { 12328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final Set<Integer> existingOffsets = new HashSet<Integer>(); 1233668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int childCount = getChildCount(); 1234668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar StringBuilder log = new StringBuilder(); 12358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < childCount; i++) { 12368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ViewHolder vh = getChildViewHolderInt(getChildAt(i)); 1237668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar TestViewHolder tvh = (TestViewHolder) vh; 1238115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar log.append(tvh.mBoundItem).append(vh) 1239668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append(" hidden:") 1240668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append(mChildHelper.mHiddenViews.contains(vh.itemView)) 1241668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar .append("\n"); 1242668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1243668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int i = 0; i < childCount; i++) { 1244668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ViewHolder vh = getChildViewHolderInt(getChildAt(i)); 1245668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (vh.isInvalid()) { 1246668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar continue; 1247668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 1248115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (vh.getLayoutPosition() < 0) { 1249668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar LayoutManager lm = getLayoutManager(); 1250668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int j = 0; j < lm.getChildCount(); j ++) { 1251668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar assertNotSame("removed view holder should not be in LM's child list", 1252668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar vh.itemView, lm.getChildAt(j)); 12538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1254668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) { 1255115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar if (!existingOffsets.add(vh.getLayoutPosition())) { 1256668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar throw new IllegalStateException("view holder position conflict for " 1257668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + "existing views " + vh + "\n" + log); 12588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void validatePostUpdateOp() { 12648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar try { 12658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validateViewHolderPositions(); 12668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (super.mState.isPreLayout()) { 12678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager()); 12688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar validateAdapterPosition((AnimationLayoutManager) getLayoutManager()); 12708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } catch (Throwable t) { 12718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar postExceptionToInstrumentation(t); 12728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validateAdapterPosition(AnimationLayoutManager lm) { 12788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (ViewHolder vh : collectViewHolders()) { 12798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) { 12808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("adapter position calculations should match view holder " 1281668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + "pre layout:" + mState.isPreLayout() 1282668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar + " positions\n" + vh + "\n" + lm.getLog(), 12838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition); 12848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // ensures pre layout positions are continuous block. This is not necessarily a case 12898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // but valid in test RV 12908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar private void validatePreLayoutSequence(AnimationLayoutManager lm) { 12918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Set<Integer> preLayoutPositions = new HashSet<Integer>(); 12928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (ViewHolder vh : collectViewHolders()) { 12938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertTrue("pre layout positions should be distinct " + lm.getLog(), 12948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar preLayoutPositions.add(vh.mPreLayoutPosition)); 12958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int minPos = Integer.MAX_VALUE; 12978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (Integer pos : preLayoutPositions) { 12988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (pos < minPos) { 12998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar minPos = pos; 13008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 1; i < preLayoutPositions.size(); i++) { 13038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull("next position should exist " + lm.getLog(), 13048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar preLayoutPositions.contains(minPos + i)); 13058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1308888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 1309888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar protected void dispatchDraw(Canvas canvas) { 1310888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar super.dispatchDraw(canvas); 1311888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar if (drawLatch != null) { 1312888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar drawLatch.countDown(); 1313888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1314888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1315888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 1316b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar @Override 1317b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar void dispatchLayout() { 1318b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar try { 1319b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar super.dispatchLayout(); 1320b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar if (getLayoutManager() instanceof AnimationLayoutManager) { 1321b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout(); 1322b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1323b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } catch (Throwable t) { 1324b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar postExceptionToInstrumentation(t); 1325b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1326b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1327b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1328b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar abstract class AdapterOps { 13338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final public void run(TestAdapter adapter) throws Throwable { 13358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar onRun(adapter); 13368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar abstract void onRun(TestAdapter testAdapter) throws Throwable; 13398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class CollectPositionResult { 13428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // true if found in scrap 13448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public RecyclerView.ViewHolder scrapResult; 13458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public RecyclerView.ViewHolder adapterResult; 13478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) { 13498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar CollectPositionResult cpr = new CollectPositionResult(); 13508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar cpr.scrapResult = viewHolder; 13518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return cpr; 13528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) { 13558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar CollectPositionResult cpr = new CollectPositionResult(); 13568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar cpr.adapterResult = viewHolder; 13578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return cpr; 13588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar static class PositionConstraint { 13628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static enum Type { 13648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar scrap, 13658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapter, 13668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterScrap /*first pass adapter, second pass scrap*/ 13678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Type mType; 13708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mOldPos; // if VH 13728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mPreLayoutPos; 13748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mPostLayoutPos; 13768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int mValidateCount = 0; 13788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) { 13808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 13818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.scrap; 13828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = oldPos; 13838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = preLayoutPos; 13848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = postLayoutPos; 13858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 13868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint adapterScrap(int preLayoutPos, int position) { 13898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 13908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.adapterScrap; 13918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = RecyclerView.NO_POSITION; 13928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = preLayoutPos; 13938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = position;// adapter pos does not change 13948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 13958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 13968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public static PositionConstraint adapter(int position) { 13988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint constraint = new PositionConstraint(); 13998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mType = Type.adapter; 14008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPreLayoutPos = RecyclerView.NO_POSITION; 14018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mOldPos = RecyclerView.NO_POSITION; 14028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.mPostLayoutPos = position;// adapter pos does not change 14038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return constraint; 14048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void assertValidate() { 14078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int expectedValidate = 0; 14088ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mPreLayoutPos >= 0) { 14098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar expectedValidate ++; 14108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mPostLayoutPos >= 0) { 14128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar expectedValidate ++; 14138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("should run all validates", expectedValidate, mValidateCount); 14158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 14188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public String toString() { 14198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return "Cons{" + 14208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar "t=" + mType.name() + 14218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", old=" + mOldPos + 14228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", pre=" + mPreLayoutPos + 14238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ", post=" + mPostLayoutPos + 14248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar '}'; 14258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 14278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void validate(RecyclerView.State state, CollectPositionResult result, String log) { 14288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mValidateCount ++; 14298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should not be null\n" + log, result); 14308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.ViewHolder viewHolder; 14318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) { 14328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult); 14338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder = result.scrapResult; 14348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else { 14358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertNotNull(this + ": result should come from adapter\n" + log, 14368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result.adapterResult); 14378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": old position should be none when it came from adapter\n" + log, 14388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.NO_POSITION, result.adapterResult.getOldPosition()); 14398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder = result.adapterResult; 14408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 14418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (state.isPreLayout()) { 14428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos, 1443e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition : 14448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar viewHolder.mPreLayoutPosition); 14458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos, 1446115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar viewHolder.getLayoutPosition()); 14478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (mType == Type.scrap) { 14488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals(this + ": old position should match\n" + log, mOldPos, 14498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar result.scrapResult.getOldPosition()); 1450b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 14518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult 14528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar .isRemoved()) { 1453e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar assertEquals(this + ": post-layout position should match\n" + log + "\n\n" 1454115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition()); 1455b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1456b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1457b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1458d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase} 1459