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 1913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyarimport org.hamcrest.CoreMatchers; 2013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyarimport org.hamcrest.MatcherAssert; 210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.Test; 220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport org.junit.runner.RunWith; 230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 245a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyarimport android.graphics.Rect; 254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.annotation.NonNull; 260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 27f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyarimport android.support.v4.view.ViewCompat; 28f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyarimport android.test.suitebuilder.annotation.MediumTest; 29b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log; 30b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View; 31504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup; 32b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 3311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList; 348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap; 3511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet; 3611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List; 3711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map; 3811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set; 39b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 40d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport static org.junit.Assert.*; 42d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 43121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/** 44121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Tests for {@link SimpleItemAnimator} API. 45121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */ 46f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class) 48121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest { 49b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<TestViewHolder> recycledVHs = new ArrayList<>(); 519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 53e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void keepFocusAfterChangeAnimation() throws Throwable { 54e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar setupBasic(10, 0, 5, new TestAdapter(10) { 55e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Override 56e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 57e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar int position) { 58e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar super.onBindViewHolder(holder, position); 59e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar holder.itemView.setFocusableInTouchMode(true); 60e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 61e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar }); 62e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar ((SimpleItemAnimator)(mRecyclerView.getItemAnimator())).setSupportsChangeAnimations(true); 63e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 64e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(3); 65e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotNull("test sanity", oldVh); 66e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar runTestOnUiThread(new Runnable() { 67e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Override 68e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void run() { 69e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar oldVh.itemView.requestFocus(); 70e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 71e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar }); 72e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertTrue("test sanity", oldVh.itemView.hasFocus()); 73e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mLayoutManager.expectLayouts(2); 74e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mTestAdapter.changeAndNotify(3, 1); 75e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mLayoutManager.waitForLayout(2); 76e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 77e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3); 78e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotNull("test sanity", newVh); 79e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotSame(oldVh, newVh); 80e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertFalse(oldVh.itemView.hasFocus()); 81e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertTrue(newVh.itemView.hasFocus()); 82e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 83e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 84e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Test 8513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearDontReUseViewHolder() throws Throwable { 8613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(false, false); 8713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 8813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 8913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 9013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearReUseViewHolder() throws Throwable { 9113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(true, false); 9213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 9313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 9413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 9513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearReUseWithScrapViewHolder() throws Throwable { 9613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(true, true); 9713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 9813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 9913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearTest(final boolean reUse, final boolean useScrap) 10013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar throws Throwable { 10113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final List<RecyclerView.ViewHolder> mRecycled = new ArrayList<>(); 10213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final TestAdapter adapter = new TestAdapter(1) { 10313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 10413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 10513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar super.onViewRecycled(holder); 10613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mRecycled.add(holder); 10713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 10813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 10913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar setupBasic(1, 0, 1, adapter); 11013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0)); 11113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar LoggingItemAnimator animator = new LoggingItemAnimator() { 11213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 11313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, 11413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @NonNull List<Object> payloads) { 11513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar return reUse; 11613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 11713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 11813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mRecyclerView.setItemAnimator(animator); 11913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.expectLayouts(2); 12013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final RecyclerView.ViewHolder[] updatedVH = new RecyclerView.ViewHolder[1]; 12113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar runTestOnUiThread(new Runnable() { 12213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 12313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void run() { 12413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar adapter.notifyItemChanged(0); 12513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 12613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 12713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 12813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar RecyclerView.State state) { 12913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (state.isPreLayout()) { 13013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar super.doLayout(recycler, lm, state); 13113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 13213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 13313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final View view; 13413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (reUse && useScrap) { 13513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar view = recycler.getScrapViewAt(0); 13613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 13713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar view = recycler.getViewForPosition(0); 13813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 13913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar updatedVH[0] = RecyclerView.getChildViewHolderInt(view); 14013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar lm.addDisappearingView(view); 14113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 14213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 14313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 14413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 14513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }); 14613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.waitForLayout(2); 14713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 14813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateDisappearanceList), 149dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(reUse)); 15013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateChangeList), 151dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(!reUse)); 15213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(updatedVH[0], animator.mAnimateChangeList), 153dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(!reUse)); 15413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(updatedVH[0], 155dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar animator.mAnimateDisappearanceList), CoreMatchers.is(reUse)); 15613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar waitForAnimations(10); 15713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.getChildCount(), CoreMatchers.is(0)); 15813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (useScrap || !reUse) { 15913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecycled.contains(vh), CoreMatchers.is(true)); 16013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 16113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(vh), 16213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar CoreMatchers.is(true)); 16313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 16413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 16513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (!reUse) { 16613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecycled.contains(updatedVH[0]), CoreMatchers.is(false)); 16713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(updatedVH[0]), 16813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar CoreMatchers.is(true)); 16913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 17013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 17113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 17213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 1730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detectStableIdError() throws Throwable { 17466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 175b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar final AtomicBoolean useBadIds = new AtomicBoolean(false); 176b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 177b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 178b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public long getItemId(int position) { 179b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar if (useBadIds.get() && position == 5) { 180b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position) - 1; 181b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 182b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position); 183b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 184b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 185b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 186b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public void onDetachedFromRecyclerView(RecyclerView recyclerView) { 187b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // ignore validation 188b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 189b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar }; 190b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.setHasStableIds(true); 191b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar setupBasic(10, 0, 10, adapter); 192b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.expectLayouts(2); 193b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar useBadIds.set(true); 194b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.changeAndNotify(4, 2); 195b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.waitForLayout(2); 19666826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar assertTrue(getMainThreadException() instanceof IllegalStateException); 19766826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar assertTrue(getMainThreadException().getMessage() 198b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar .contains("Two different ViewHolders have the same stable ID.")); 199b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // TODO don't use this after moving this class to Junit 4 200b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar try { 201b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar removeRecyclerView(); 202b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } catch (Throwable t){} 203b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 204b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 205b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 2060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithoutPredictive() throws Throwable { 2089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 2129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 2189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 2199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar fail("pre layout is not expected"); 2209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 2249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 2279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar View targetView = recycler 2289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getViewForPosition(target.getAdapterPosition()); 2299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertSame(targetView, target.itemView); 2309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 2319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 2359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 2389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 2399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 2409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 2429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 2439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 2449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 2459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 2479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 2519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance 2529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 2559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 2579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithPredictive() throws Throwable { 2619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 2659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 2719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 2729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 2739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 2749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 2789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 2819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 2829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 2869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 2899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 2909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 2919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 2939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 2949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 2959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 2979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 3019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance. 3029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 3059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutPredictive() throws Throwable { 3119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 3209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 3219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 3229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutAnimations() throws Throwable { 3359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 3449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3560a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithPredictive() throws Throwable { 3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 3679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 3689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM does not layout the additional item so it does predictive wrong. 3719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // We should still handle it and animate persistence for this item 3729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 3779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithProperPredictive() throws Throwable { 3849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 3939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 3959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 3969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 3979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 3989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 4029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 4039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 4049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 8; 4059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPreLayout(recycler, layoutManager, state); 4069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 4089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 4109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 4119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM implements predictive animations properly by requesting target view 4149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // in pre-layout. 4159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 4179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 4209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 4219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 4260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseHiddenViewOnInvalidate() throws Throwable { 4279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 4289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 4309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 4319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 4329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 4339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 4349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 4359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 4369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.dispatchDataSetChanged(); 4379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(mRecyclerView.getItemAnimator().isRunning()); 4409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 4429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 4459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 4500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseOnTypeChange() throws Throwable { 4519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 4529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 4549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 4559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 4569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 4579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 4589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 4599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 4609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar target.mBoundItem.mType += 2; 4619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 4629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1); 4639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 4649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mChangeOldVHs.contains(target)); 4679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView)); 4719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 4729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 4749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar interface ReuseTestCallback { 4799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable; 4819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar protected RecyclerView.ItemAnimator createItemAnimator() { 4859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar return new LoggingItemAnimator(); 4869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable { 4899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestAdapter adapter = new TestAdapter(10) { 4909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void onViewRecycled(TestViewHolder holder) { 4929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.onViewRecycled(holder); 4939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar recycledVHs.add(holder); 4949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 4969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar setupBasic(10, 0, 10, adapter); 4979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.setItemViewCacheSize(0); 4989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9); 4999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setAddDuration(1000); 5009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setRemoveDuration(1000); 5019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setChangeDuration(1000); 5029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setMoveDuration(1000); 5039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 5049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 5059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(2, 1); 5069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 5079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // test sanity, make sure target is hidden now 5089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView)); 5099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar callback.postSetup(recycledVHs, target); 5109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN 5119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED 5129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION 5139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 5149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 5159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 5160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachBeforeAnimations() throws Throwable { 5180ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar setupBasic(10, 0, 5); 5190ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final RecyclerView rv = mRecyclerView; 5200ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar waitForAnimations(2); 5210ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator() { 5220ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar @Override 5230ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar public void runPendingAnimations() { 5240ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar super.runPendingAnimations(); 5250ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 5260ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar }; 5270ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar rv.setItemAnimator(animator); 5280ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.expectLayouts(2); 5290ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mTestAdapter.deleteAndNotify(3, 4); 5300ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.waitForLayout(2); 5310ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar removeRecyclerView(); 5320ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertNull("test sanity check RV should be removed", rv.getParent()); 5330ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size()); 5340ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertFalse("there should not be any animations running", animator.isRunning()); 5350ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 5360ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar 5370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void moveDeleted() throws Throwable { 5395a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar setupBasic(4, 0, 3); 5405a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar waitForAnimations(2); 5415a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final View[] targetChild = new View[1]; 5425a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final LoggingItemAnimator animator = new LoggingItemAnimator(); 5435a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar runTestOnUiThread(new Runnable() { 5445a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5455a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 5465a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.setItemAnimator(animator); 5475a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = mRecyclerView.getChildAt(1); 5485a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5495a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5505a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 5515a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertNotNull("test sanity", targetChild); 5525a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(1); 5535a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar runTestOnUiThread(new Runnable() { 5545a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5555a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 5565a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { 5575a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5585a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 5599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 5605a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar if (view == targetChild[0]) { 5615a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(10, 20, 30, 40); 5625a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } else { 5635a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(0, 0, 0, 0); 5645a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5655a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5665a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5675a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5685a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5695a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(1); 5705a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 5715a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar // now delete that item. 5725a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(2); 5735a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]); 5745a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = null; 5755a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 5765a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(2); 5775a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertFalse("if deleted view moves, it should not be in move animations", 5785a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar animator.mMoveVHs.contains(targetVH)); 5795a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size()); 5805a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH 5815a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar )); 5825a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5835a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 584344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev private void runTestImportantForAccessibilityWhileDeteling( 585344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int boundImportantForAccessibility, 586344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int expectedImportantForAccessibility) throws Throwable { 587344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Adapter binding the item to the initial accessibility option. 588344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // RecyclerView is expected to change it to 'expectedImportantForAccessibility'. 589344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev TestAdapter adapter = new TestAdapter(1) { 590344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 591344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void onBindViewHolder(TestViewHolder holder, int position) { 592344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev super.onBindViewHolder(holder, position); 593344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.setImportantForAccessibility( 594344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev holder.itemView, boundImportantForAccessibility); 595344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 596344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }; 597344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 598344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Set up with 1 item. 599344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev setupBasic(1, 0, 1, adapter); 600344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 601344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final View[] targetChild = new View[1]; 602344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final LoggingItemAnimator animator = new LoggingItemAnimator(); 603344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev animator.setRemoveDuration(500); 604344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 605344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 606344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 607344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mRecyclerView.setItemAnimator(animator); 608344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev targetChild[0] = mRecyclerView.getChildAt(0); 609344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 610344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 611344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 612344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 613344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 614344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 615344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertNotNull("test sanity", targetChild[0]); 616344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 617344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // now delete that item. 618344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 619344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.deleteAndNotify(0, 1); 620344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 621344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 622344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 623344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 624344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 625344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 626344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is still a child of mRecyclerView, and is invisible for accessibility. 627344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == mRecyclerView); 628344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 629344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 630344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 631344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 632344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 633344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 634344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 635344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 636344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Delete animation is now complete. 637344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 638344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 639344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 640344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is in recycled state, and back to the expected accessibility. 641344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == null); 642344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 643344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 644344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 645344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 646344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 647344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 648344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Add 1 element, which should use same view. 649344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 650344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.addAndNotify(1); 651344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 652344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 653344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestOnUiThread(new Runnable() { 654344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 655344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 656344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view should be reused, and have the expected accessibility. 657344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue( 658344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0)); 659344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 660344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 661344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 662344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 663344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 664344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 665344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingAuto() throws Throwable { 668344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 669344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO, 670344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 671344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 672344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNo() throws Throwable { 675344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 676344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO, 677344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); 678344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 679344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable { 682344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 683344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 684344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); 685344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 686344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingYes() throws Throwable { 689344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 690344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES, 691344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 692344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 693344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void preLayoutPositionCleanup() throws Throwable { 69642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar setupBasic(4, 0, 4); 69742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.expectLayouts(2); 69842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 69942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 70042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 70142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 70242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 70342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 3; 70442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 70542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 70642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 70742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 70842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager layoutManager, 70942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state) { 71042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 71142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 4; 71242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 71342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar }; 71442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mTestAdapter.addAndNotify(0, 1); 71542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.waitForLayout(2); 71642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 71742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 71842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 71942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 7200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 7210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addRemoveSamePass() throws Throwable { 72293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final List<RecyclerView.ViewHolder> mRecycledViews 72393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 72493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar TestAdapter adapter = new TestAdapter(50) { 72593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 72693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 72793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.onViewRecycled(holder); 72893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.add(holder); 72993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 73093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 73193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar adapter.setHasStableIds(true); 73293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar setupBasic(50, 3, 5, adapter); 73393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemViewCacheSize(0); 73493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> addVH 73593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 73693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> removeVH 73793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 73893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 73993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> moveVH 74093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 74193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 74293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final View[] testView = new View[1]; 74393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 74493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 74593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateAdd(RecyclerView.ViewHolder holder) { 74693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar addVH.add(holder); 74793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 74893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 74993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 75093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 75193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 75293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar removeVH.add(holder); 75393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 75493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 75593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 75693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 75793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, 75893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar int toX, int toY) { 75993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar moveVH.add(holder); 76093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 76193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 76293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }); 76393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 76493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 76593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 76693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 76793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 76893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 76993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0] = recycler.getViewForPosition(45); 77093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST), 77193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST)); 77293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(), 77393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 10 + testView[0].getMeasuredHeight()); 77493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addView(testView[0], 4); 77593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 77693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 77793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 77893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 77993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 78093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 78193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPostLayout(recycler, layoutManager, state); 78293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(), 78393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 50 + testView[0].getMeasuredHeight()); 78493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addDisappearingView(testView[0], 4); 78593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 78693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 78793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3; 78893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5; 78993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.clear(); 79093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.expectLayouts(2); 79193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mTestAdapter.deleteAndNotify(3, 1); 79293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.waitForLayout(2); 79393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 79493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : addVH) { 79593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate add", testView[0], vh.itemView); 79693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 79793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : moveVH) { 79893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate move", testView[0], vh.itemView); 79993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 80093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : removeVH) { 80193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView); 80293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 80393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar boolean found = false; 80493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : mRecycledViews) { 80593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar found |= vh.itemView == testView[0]; 80693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 80793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertTrue("added-removed view should be recycled", found); 80893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 80993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 8100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void tmpRemoveMe() throws Throwable { 812121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar changeAnimTest(false, false, true, false); 813121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 814121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 8150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void changeAnimations() throws Throwable { 8177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean[] booleans = {true, false}; 8187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean supportsChange : booleans) { 8197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean changeType : booleans) { 8207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean hasStableIds : booleans) { 8217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean deleteSomeItems : booleans) { 8227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems); 8237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen removeRecyclerView(); 8257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 829121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 8307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType, 8319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable { 8327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int changedIndex = 3; 8337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int defaultType = 1; 8347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType); 8357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim + 8367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", change view type:" + changeType + 8377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", has stable ids:" + hasStableIds + 838121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ", delete some items:" + deleteSomeItems; 8397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestAdapter testAdapter = new TestAdapter(10) { 8407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public int getItemViewType(int position) { 8427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return position == changedIndex ? changedIndexNewType.get() : defaultType; 8437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8457c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8467c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public TestViewHolder onCreateViewHolder(ViewGroup parent, 8477c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int viewType) { 8487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 8497c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 8507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onCreateVH" + vh.toString()); 8517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return vh; 8537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8547c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8557c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void onBindViewHolder(TestViewHolder holder, 8577c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int position) { 8587c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.onBindViewHolder(holder, position); 8597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 8607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString()); 8617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 8647c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen testAdapter.setHasStableIds(hasStableIds); 8657c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 8669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 867121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 8687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final RecyclerView.ViewHolder toBeChangedVH = 870115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar mRecyclerView.findViewHolderForLayoutPosition(changedIndex); 8717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 8727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPreLayout(RecyclerView.Recycler recycler, 8747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, 8757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.State state) { 876115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 877115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 878121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar assertTrue(logPrefix + " changed view holder should have correct flag" 879121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar , vh.isUpdated()); 8807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8827c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8837c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPostLayout(RecyclerView.Recycler recycler, 8847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, RecyclerView.State state) { 885115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 886115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 8877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 8887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertNotSame(logPrefix + "a new VH should be given if change is supported", 8897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen toBeChangedVH, vh); 8907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else if (!changeType && hasStableIds) { 8917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertSame(logPrefix + "if change animations are not supported but we have " 8927c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen + "stable ids, same view holder should be returned", toBeChangedVH, vh); 8937c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8947c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.beforePostLayout(recycler, layoutManager, state); 8957c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 8977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.expectLayouts(1); 8987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (changeType) { 8997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changedIndexNewType.set(defaultType + 1); 9007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9017c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (deleteSomeItems) { 9027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen runTestOnUiThread(new Runnable() { 9037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 9047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void run() { 9057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen try { 9067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.deleteAndNotify(changedIndex + 2, 1); 9077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 9087c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } catch (Throwable throwable) { 9097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen throwable.printStackTrace(); 9107c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }); 9147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 915121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.changeAndNotify(3, 1); 9167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9187c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.waitForLayout(2); 9197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar private void testChangeWithPayload(final boolean supportsChangeAnim, 9224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final boolean canReUse, Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind) 9239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar throws Throwable { 92421b345f101abc385496f42d250e580d21f1287b6Dake Gu final List<Object> expectedPayloads = new ArrayList<Object>(); 92521b345f101abc385496f42d250e580d21f1287b6Dake Gu final int changedIndex = 3; 92621b345f101abc385496f42d250e580d21f1287b6Dake Gu TestAdapter testAdapter = new TestAdapter(10) { 92721b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 92821b345f101abc385496f42d250e580d21f1287b6Dake Gu public int getItemViewType(int position) { 92921b345f101abc385496f42d250e580d21f1287b6Dake Gu return 1; 93021b345f101abc385496f42d250e580d21f1287b6Dake Gu } 93121b345f101abc385496f42d250e580d21f1287b6Dake Gu 93221b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 93321b345f101abc385496f42d250e580d21f1287b6Dake Gu public TestViewHolder onCreateViewHolder(ViewGroup parent, 93421b345f101abc385496f42d250e580d21f1287b6Dake Gu int viewType) { 93521b345f101abc385496f42d250e580d21f1287b6Dake Gu TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 93621b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 93721b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onCreateVH" + vh.toString()); 93821b345f101abc385496f42d250e580d21f1287b6Dake Gu } 93921b345f101abc385496f42d250e580d21f1287b6Dake Gu return vh; 94021b345f101abc385496f42d250e580d21f1287b6Dake Gu } 94121b345f101abc385496f42d250e580d21f1287b6Dake Gu 94221b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 94321b345f101abc385496f42d250e580d21f1287b6Dake Gu public void onBindViewHolder(TestViewHolder holder, 94421b345f101abc385496f42d250e580d21f1287b6Dake Gu int position, List<Object> payloads) { 94521b345f101abc385496f42d250e580d21f1287b6Dake Gu super.onBindViewHolder(holder, position); 94621b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 94721b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onBind to " + position + "" + holder.toString()); 94821b345f101abc385496f42d250e580d21f1287b6Dake Gu } 949f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar assertEquals(expectedPayloads, payloads); 95021b345f101abc385496f42d250e580d21f1287b6Dake Gu } 95121b345f101abc385496f42d250e580d21f1287b6Dake Gu }; 95221b345f101abc385496f42d250e580d21f1287b6Dake Gu testAdapter.setHasStableIds(false); 95321b345f101abc385496f42d250e580d21f1287b6Dake Gu setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 954f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 955f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @Override 956f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, 957f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @NonNull List<Object> payloads) { 958f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads); 959f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 960f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 9619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 962121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 96321b345f101abc385496f42d250e580d21f1287b6Dake Gu 96421b345f101abc385496f42d250e580d21f1287b6Dake Gu int numTests = notifyPayloads.length; 9659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < numTests; i++) { 96621b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.expectLayouts(1); 96721b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.clear(); 96821b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) { 96921b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.add(expectedPayloadsInOnBind[i][j]); 97021b345f101abc385496f42d250e580d21f1287b6Dake Gu } 97121b345f101abc385496f42d250e580d21f1287b6Dake Gu final Object[] payloadsToSend = notifyPayloads[i]; 97221b345f101abc385496f42d250e580d21f1287b6Dake Gu runTestOnUiThread(new Runnable() { 97321b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 97421b345f101abc385496f42d250e580d21f1287b6Dake Gu public void run() { 97521b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < payloadsToSend.length; j++) { 97621b345f101abc385496f42d250e580d21f1287b6Dake Gu mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]); 97721b345f101abc385496f42d250e580d21f1287b6Dake Gu } 97821b345f101abc385496f42d250e580d21f1287b6Dake Gu } 97921b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 98021b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.waitForLayout(2); 9819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 98221b345f101abc385496f42d250e580d21f1287b6Dake Gu } 98321b345f101abc385496f42d250e580d21f1287b6Dake Gu } 98421b345f101abc385496f42d250e580d21f1287b6Dake Gu 9850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 9860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayload() throws Throwable { 98721b345f101abc385496f42d250e580d21f1287b6Dake Gu // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 988f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, true, 989f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 990f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 991f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null, "cdf"}, 992f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null}, 993f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{null, "abc"}, 994f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 995f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }, 996f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 997f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 998f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 999f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 1000f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 1001f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 1002f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 1003f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 1004f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar 10050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable { 1007f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 1008f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, false, 100921b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 10129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 10139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 10149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 101521b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 101621b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0] 102221b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 102321b345f101abc385496f42d250e580d21f1287b6Dake Gu } 102421b345f101abc385496f42d250e580d21f1287b6Dake Gu 10250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noChangeAnimationWithPayload() throws Throwable { 102721b345f101abc385496f42d250e580d21f1287b6Dake Gu // for Change Animation disabled, payload should match the payloads unless 102821b345f101abc385496f42d250e580d21f1287b6Dake Gu // null payload is fired. 1029f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(false, true, 103021b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 10339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 10349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 10359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 103621b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 103721b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 104321b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 104421b345f101abc385496f42d250e580d21f1287b6Dake Gu } 104521b345f101abc385496f42d250e580d21f1287b6Dake Gu 10460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleDuringAnimations() throws Throwable { 1048504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 1049504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(1000) { 1050504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1051504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 1052504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 1053504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 1054504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return super.onCreateViewHolder(parent, viewType); 1055504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1056504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 1057504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar setupBasic(1000, 10, 20, adapter); 1058504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10; 1059504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20; 1060504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1061504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 1062504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1063504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 1064504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 1065504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.decrementAndGet(); 1066504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1067504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1068504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1069504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 1070504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 1071504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 1072504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 1073504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1074504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 1075504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1076504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }); 1077504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1078504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 10799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < 100; i++) { 1080504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 1081504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(50); 1082504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1083504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 1084504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 1085504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 1086504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 1087504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1088504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 10890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10900a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChanged() throws Throwable { 1091b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar setupBasic(10, 3, 4); 1092b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar int layoutCount = mLayoutManager.mTotalLayoutCount; 1093b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(1); 1094b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar runTestOnUiThread(new Runnable() { 1095b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar @Override 1096b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void run() { 1097b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar try { 1098b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.deleteAndNotify(4, 1); 1099cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase mTestAdapter.dispatchDataSetChanged(); 1100b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } catch (Throwable throwable) { 1101b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar throwable.printStackTrace(); 1102b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1103b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 1104b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1105b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar }); 1106b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 1107b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar getInstrumentation().waitForIdleSync(); 1108b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("on notify data set changed, predictive animations should not run", 1109b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar layoutCount + 1, mLayoutManager.mTotalLayoutCount); 1110b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(2); 1111b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.addAndNotify(4, 2); 1112b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar // make sure animations recover 1113b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 1114b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1115b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 11160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void stableIdNotifyDataSetChanged() throws Throwable { 1118e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int itemCount = 20; 1119e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar List<Item> initialSet = new ArrayList<Item>(); 1120e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(itemCount) { 1121e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 1122e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 1123e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 1124e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1125e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 1126e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 1127e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar initialSet.addAll(adapter.mItems); 1128e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() { 11299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 11309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter testAdapter) throws Throwable { 11319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item5 = adapter.mItems.get(5); 11329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item6 = adapter.mItems.get(6); 11339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item5.mAdapterIndex = 6; 11349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item6.mAdapterIndex = 5; 11359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.remove(5); 11369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.add(6, item5); 11379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.dispatchDataSetChanged(); 11389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar //hacky, we support only 1 layout pass 11399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.layoutLatch.countDown(); 11409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 11419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6), 1142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8), 1143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(9, -1, 9)); 1144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // now mix items. 1145e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1146e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 1147d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 11480a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void getItemForDeletedView() throws Throwable { 11508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(false); 11518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(true); 115211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 115311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 11548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void getItemForDeletedViewTest(boolean stableIds) throws Throwable { 115511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemViewTypeQueries = new HashSet<Integer>(); 115611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemIdQueries = new HashSet<Integer>(); 115711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter adapter = new TestAdapter(10) { 115811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 115911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public int getItemViewType(int position) { 116011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.add(position); 116111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return super.getItemViewType(position); 116211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 116311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 116411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 116511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public long getItemId(int position) { 116611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.add(position); 116711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return mItems.get(position).mId; 116811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 116911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar }; 117011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.setHasStableIds(stableIds); 117111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar setupBasic(10, 0, 10, adapter); 117211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemViewType for all items should be called", 10, 117311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.size()); 117411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 117511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should be called when adapter has stable ids", 10, 117611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 117711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 117811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should not be called when adapter does not have stable ids", 0, 117911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 118011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 118111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.clear(); 118211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.clear(); 118311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.expectLayouts(2); 118411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar // delete last two 118511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteStart = 8; 118611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteCount = adapter.getItemCount() - deleteStart; 118711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.deleteAndNotify(deleteStart, deleteCount); 118811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.waitForLayout(2); 118911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = 0; i < deleteStart; i++) { 119011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemViewType for existing item " + i + " should be called", 119111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 119211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 119311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemId for existing item " + i 11949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + " should be called when adapter has stable ids", 119511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 119611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 119711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 119811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = deleteStart; i < deleteStart + deleteCount; i++) { 119911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called", 120011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 120111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 12028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called", 120311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 120411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 120511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 120611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 120711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 12080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12090a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisibleMultiStep() throws Throwable { 12108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(1000, 1, 7); 12118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 12128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 12138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 12148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 12158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 12168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 12178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1}); 121890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 12198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount -= 2; 12208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 12228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 12238ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 12248ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12258ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addManyMultiStep() throws Throwable { 12308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10, 1, 7); 12318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 12328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 12338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 12348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 12358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 12368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 1237e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(0, 1); 1239e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(7, 1); 12418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount += 2; 12428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1243e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 12458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 12468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 1247e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12530a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicDelete() throws Throwable { 12548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 12558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() { 12568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void postDispatchLayout() { 12588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // verify this only in first layout 12598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("deleted views should still be children of RV", 12608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount() + mDeletedViewCount 12618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar , mRecyclerView.getChildCount()); 12628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 12668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AnimationLayoutManager layoutManager, 12678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 12688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 12698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutItemCount = 3; 12708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutMin = 0; 12718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 12738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.mLayoutItemCount = 10; 12748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.setExpectedItemCounts(10, 3); 12758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.setOnLayoutCallbacks(callbacks); 12768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(2); 12788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(0, 7); 12798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.reset();// when animations end another layout will happen 12818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12850a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScrolling() throws Throwable { 1286d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar setupBasic(10); 1287d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 1288d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 1289d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1290d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 1291d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1292d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 1293d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 1294d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 1295d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onLayoutChildren(recycler, lm, state); 1296d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1297d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1298d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1299d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 1300d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onScrollItemCount.set(state.getItemCount()); 1301d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onScroll(dx, recycler, state); 1302d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1303d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 1304d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar runTestOnUiThread(new Runnable() { 1305d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1306d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void run() { 1307d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.remove(5); 1308d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.notifyItemRangeRemoved(5, 1); 1309d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mRecyclerView.scrollBy(0, 100); 1310d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 1311d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 1312d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 1313d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 1314d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1315d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1316d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 1317d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1318d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 13190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedDuringScroll() throws Throwable { 132117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar setupBasic(10); 132217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 132317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 132417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 132517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 132617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 132717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 132817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 132917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 133017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onLayoutChildren(recycler, lm, state); 133117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 133217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 133317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 133417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 133517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onScrollItemCount.set(state.getItemCount()); 133617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onScroll(dx, recycler, state); 133717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 133817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 133917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar runTestOnUiThread(new Runnable() { 134017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 134117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void run() { 134217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.remove(5); 134317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.notifyDataSetChanged(); 134417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mRecyclerView.scrollBy(0, 100); 134517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 134617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 134717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 134817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 134917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 135017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 135117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 135217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 135317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 13540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisibleAndVisible() throws Throwable { 1356b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1357b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1358b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible 1360b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1361b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1362b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisible() throws Throwable { 1365b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1366b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1367b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 13682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0 1369b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1370b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1371b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicAdd() throws Throwable { 1374b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10); 1375b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1376b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(10, 13); 1377b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.addAndNotify(2, 3); 1378b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1379b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1380b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void appCancelAnimationInDetach() throws Throwable { 1383a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu final View[] addedView = new View[2]; 1384a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu TestAdapter adapter = new TestAdapter(1) { 1385a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1386a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void onViewDetachedFromWindow(TestViewHolder holder) { 1387a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView) 1388f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar && ViewCompat.hasTransientState(holder.itemView)) { 1389f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar ViewCompat.animate(holder.itemView).cancel(); 1390a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1391a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu super.onViewDetachedFromWindow(holder); 1392a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1393a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1394a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // original 1 item 1395a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setupBasic(1, 0, 1, adapter); 1396cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getItemAnimator().setAddDuration(10000); 1397a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(2); 1398a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // add 2 items 1399a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setExpectedItemCounts(1, 3); 1400a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mTestAdapter.addAndNotify(0, 2); 140166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar mLayoutManager.waitForLayout(2); 1402629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar checkForMainThreadException(); 1403a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // wait till "add animation" starts 1404e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar int limit = 200; 1405a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu while (addedView[0] == null || addedView[1] == null) { 1406629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar Thread.sleep(100); 1407a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu runTestOnUiThread(new Runnable() { 1408a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1409a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void run() { 1410a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (mRecyclerView.getChildCount() == 3) { 1411a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu View view = mRecyclerView.getChildAt(0); 1412f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1413a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[0] = view; 1414a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1415a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu view = mRecyclerView.getChildAt(1); 1416f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1417a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[1] = view; 1418a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1419a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1420a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1421a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }); 1422e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar assertTrue("add should start on time", --limit > 0); 1423a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1424a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 1425a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // Layout from item2, exclude the current adding items 1426a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(1); 1427a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 1428a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1429a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu void beforePostLayout(RecyclerView.Recycler recycler, 1430a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu AnimationLayoutManager layoutManager, 1431a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu RecyclerView.State state) { 1432a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutMin = 2; 1433a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutItemCount = 1; 1434a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1435a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1436a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu requestLayoutOnUIThread(mRecyclerView); 1437a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.waitForLayout(2); 1438a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1439a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 14400a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeFrozen() throws Throwable { 1442ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setupBasic(10, 1, 7); 1443ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue(mRecyclerView.getChildCount() == 7); 1444ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1445ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.expectLayouts(2); 1446ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 1447ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 1448ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 1449ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mTestAdapter.addAndNotify(0, 1); 1450ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1451ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2); 1452ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(7, mRecyclerView.getChildCount()); 1453ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1454ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 1455ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.waitForLayout(2); 1456ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("RV should get updated after waken from frozen", 1457ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 8, mRecyclerView.getChildCount()); 1458ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 1459ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 14600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void removeScrapInvalidate() throws Throwable { 1462888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar setupBasic(10); 1463888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar TestRecyclerView testRecyclerView = getTestRecyclerView(); 1464888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.expectLayouts(1); 1465888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.expectDraw(1); 1466888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar runTestOnUiThread(new Runnable() { 1467888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 1468888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void run() { 1469888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.mItems.clear(); 1470888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.notifyDataSetChanged(); 1471888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1472888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar }); 1473888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.waitForLayout(2); 1474888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.waitForDraw(2); 1475888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1476888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 14770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteVisibleAndInvisible() throws Throwable { 1479b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(11, 3, 5); //layout items 3 4 5 6 7 1480b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 14818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list 1482b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(9, 8); 1483b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9 1484b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1485b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1486b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 14870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findPositionOffset() throws Throwable { 14898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 149090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 149190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar @Override 149290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 149390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 149490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar super.beforePreLayout(recycler, lm, state); 149590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar // [0,2,4] 149690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0)); 149790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2)); 149890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4)); 149990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar } 150090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }; 15018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar runTestOnUiThread(new Runnable() { 15028ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 15038ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 1504121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar try { 1505121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 1 1506121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 1507121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 3 1508121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(2, 1); 1509121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } catch (Throwable throwable) { 1510121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar throwable.printStackTrace(); 1511121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 15128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }); 151490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.waitForLayout(2); 15158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1517b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setLayoutRange(int start, int count) { 1518b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start; 1519b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count; 1520b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1521b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1522b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setExpectedItemCounts(int preLayout, int postLayout) { 1523b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout); 1524b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1525b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 15260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisible() throws Throwable { 1528b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 15298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 15308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 1531b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1532b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8); 15338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8 1534b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1535b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1536b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1537e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar private CollectPositionResult findByPos(RecyclerView recyclerView, 1538e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int position) { 1539e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = recycler.getViewForPosition(position, true); 1540e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 1541e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (vh.wasReturnedFromScrap()) { 1542e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar vh.clearReturnedFromScrapFlag(); //keep data consistent. 1543e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromScrap(vh); 1544e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } else { 1545e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromAdapter(vh); 15468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1549e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView, 1550e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) { 15518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positionToAdapterMapping 15528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar = new HashMap<Integer, CollectPositionResult>(); 15538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position : positions) { 15548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (position < 0) { 15558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar continue; 15568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1557e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionToAdapterMapping.put(position, 1558e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar findByPos(recyclerView, recycler, state, position)); 15598ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return positionToAdapterMapping; 15618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 15630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete2() throws Throwable { 15658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 15669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 15679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 15689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 b 3 4 15699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 15709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre w/ adap: 0 1 2 b 3 4 15719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 15729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 15739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2}); 15749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 15759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1), 15768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(3, 3, 3) 15778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 15788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1579d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 15800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete1() throws Throwable { 15828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 15839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 15849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 15859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 2 a b 3 4 15869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a b 3 4 15879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a 4 15889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // c d 2 a 4 15899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 15909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 15919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 15929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1}, 15939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1}); 15949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 15959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1), 15968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1), 15978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0), 15988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapter(1), PositionConstraint.adapter(3) 15998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16018ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 16030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addSameIndexTwice() throws Throwable { 16048ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 16059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 16069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 16079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1}, 16089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{11, 1}); 16099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 16109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3), 16118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7), 16128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12), 16138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(8, 8, 13) 16148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 16180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteTwice() throws Throwable { 16198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 16209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 16219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 16229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1}, 16239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{0, 1});// delete item ids 0,2,9,1 16249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 16259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0), 16268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2), 16278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5), 16288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7) 16298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1632b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 16338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 1634e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount, AdapterOps adapterChanges, 1635e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1636e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null, 16379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapterChanges, constraints); 1638e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 16399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1640e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 16419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges, 1642e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1643e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter); 1644b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 16458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 16468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 16478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 16488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 16498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePreLayout(recycler, lm, state); 16508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar //harmless 16518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 16528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 16538ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 16548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPreLayoutPos; 16558ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1657e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1658121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1659121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 16609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar positionLog.append(entry.getKey()).append(":").append(entry.getValue()) 16619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .append("\n"); 1662121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 16638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 16648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPreLayoutPos != -1) { 16658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPreLayoutPos), 1666121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 16678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 16728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 16738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 16748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePostLayout(recycler, lm, state); 16758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 16768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 16778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 16788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPostLayoutPos; 16798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1681e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1682121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1683121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 1684121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar positionLog.append(entry.getKey()).append(":") 1685121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar .append(entry.getValue()).append("\n"); 1686121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 16878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 16888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPostLayoutPos >= 0) { 16898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPostLayoutPos), 1690121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 16918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 16958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterChanges.run(mTestAdapter); 1696b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1697e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 16988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 16998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.assertValidate(); 17008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1701b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1702b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 17030a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 17040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addThenRecycleRemovedView() throws Throwable { 17056a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar setupBasic(10); 17066a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final AtomicInteger step = new AtomicInteger(0); 17079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<RecyclerView.ViewHolder> animateRemoveList 17089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 17096a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar DefaultItemAnimator animator = new DefaultItemAnimator() { 17106a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17116a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 17126a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.add(holder); 17136a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar return super.animateRemove(holder); 17146a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17156a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 17166a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setItemAnimator(animator); 17176a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>(); 17186a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 17196a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17206a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 17216a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar pooledViews.add(scrap); 17226a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.putRecycledView(scrap); 17236a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17246a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }); 17256a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1]; 17266a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 17276a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17286a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar void doLayout(RecyclerView.Recycler recycler, 17296a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 17306a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar switch (step.get()) { 17316a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar case 1: 17326a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.doLayout(recycler, lm, state); 17336a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar if (state.isPreLayout()) { 17346a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar View view = mLayoutManager.getChildAt(1); 17356a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar RecyclerView.ViewHolder holder = 17366a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.getChildViewHolderInt(view); 17376a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar targetVh[0] = holder; 17386a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity", holder.isRemoved()); 17396a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.removeAndRecycleView(view, recycler); 17406a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17416a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar break; 17426a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17436a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17446a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 17456a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar step.set(1); 17466a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.clear(); 17476a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.expectLayouts(2); 17486a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 17496a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.waitForLayout(2); 17506a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0])); 17516a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("since LM force recycled a view, animate disappearance should not be called", 17526a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.isEmpty()); 17536a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 1754d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase} 1755