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 19754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertEquals; 20754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertFalse; 21754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertNotNull; 22754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertNotSame; 23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertNull; 24754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertSame; 25754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertTrue; 26754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.fail; 270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 285a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyarimport android.graphics.Rect; 294c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyarimport android.os.Build; 304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.support.annotation.NonNull; 3135232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikasimport android.support.test.filters.LargeTest; 324c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyarimport android.support.test.filters.SdkSuppress; 330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 34f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyarimport android.support.v4.view.ViewCompat; 35b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.util.Log; 36b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport android.view.View; 37504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyarimport android.view.ViewGroup; 38b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 39754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.hamcrest.CoreMatchers; 40754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.hamcrest.MatcherAssert; 41754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.junit.Test; 42754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport org.junit.runner.RunWith; 43754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas 4411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.ArrayList; 458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyarimport java.util.HashMap; 4611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.HashSet; 4711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.List; 4811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Map; 4911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyarimport java.util.Set; 50b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 51d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 52d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 53121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar/** 54121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar * Tests for {@link SimpleItemAnimator} API. 55121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar */ 5635232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikas@LargeTest 570a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class) 58121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyarpublic class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest { 59b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<TestViewHolder> recycledVHs = new ArrayList<>(); 619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 63e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void keepFocusAfterChangeAnimation() throws Throwable { 64e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar setupBasic(10, 0, 5, new TestAdapter(10) { 65e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Override 66e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void onBindViewHolder(TestViewHolder holder, 67e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar int position) { 68e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar super.onBindViewHolder(holder, position); 69e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar holder.itemView.setFocusableInTouchMode(true); 70e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 71e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar }); 72e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar ((SimpleItemAnimator)(mRecyclerView.getItemAnimator())).setSupportsChangeAnimations(true); 73e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 74e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(3); 75e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotNull("test sanity", oldVh); 7642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 77e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Override 78e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar public void run() { 79e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar oldVh.itemView.requestFocus(); 80e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 81e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar }); 82e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertTrue("test sanity", oldVh.itemView.hasFocus()); 83e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mLayoutManager.expectLayouts(2); 84e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mTestAdapter.changeAndNotify(3, 1); 85e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar mLayoutManager.waitForLayout(2); 86e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 87e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3); 88e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotNull("test sanity", newVh); 89e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertNotSame(oldVh, newVh); 90e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertFalse(oldVh.itemView.hasFocus()); 91e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar assertTrue(newVh.itemView.hasFocus()); 92e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar } 93e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar 94e3b89d11cf08a0e9aaa8162757246f286c6df2f8Yigit Boyar @Test 9513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearDontReUseViewHolder() throws Throwable { 9613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(false, false); 9713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 9813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 9913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 10013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearReUseViewHolder() throws Throwable { 10113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(true, false); 10213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 10313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 10413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 10513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearReUseWithScrapViewHolder() throws Throwable { 10613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar changeAndDisappearTest(true, true); 10713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 10813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 10913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void changeAndDisappearTest(final boolean reUse, final boolean useScrap) 11013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar throws Throwable { 11113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final List<RecyclerView.ViewHolder> mRecycled = new ArrayList<>(); 11213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final TestAdapter adapter = new TestAdapter(1) { 11313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 11413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 11513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar super.onViewRecycled(holder); 11613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mRecycled.add(holder); 11713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 11813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 11913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar setupBasic(1, 0, 1, adapter); 12013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0)); 12113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar LoggingItemAnimator animator = new LoggingItemAnimator() { 12213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 12313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, 12413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @NonNull List<Object> payloads) { 12513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar return reUse; 12613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 12713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 12813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mRecyclerView.setItemAnimator(animator); 12913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.expectLayouts(2); 13013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final RecyclerView.ViewHolder[] updatedVH = new RecyclerView.ViewHolder[1]; 13142e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 13213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 13313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar public void run() { 13413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar adapter.notifyItemChanged(0); 13513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 13613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Override 13713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 13813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar RecyclerView.State state) { 13913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (state.isPreLayout()) { 14013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar super.doLayout(recycler, lm, state); 14113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 14213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 14313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar final View view; 14413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (reUse && useScrap) { 14513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar view = recycler.getScrapViewAt(0); 14613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 14713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar view = recycler.getViewForPosition(0); 14813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 14913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar updatedVH[0] = RecyclerView.getChildViewHolderInt(view); 15013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar lm.addDisappearingView(view); 15113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 15213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 15313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }; 15413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 15513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar }); 15613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar mLayoutManager.waitForLayout(2); 15713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 15813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateDisappearanceList), 159dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(reUse)); 16013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateChangeList), 161dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(!reUse)); 16213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(updatedVH[0], animator.mAnimateChangeList), 163dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar CoreMatchers.is(!reUse)); 16413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(animator.contains(updatedVH[0], 165dca8e68e966915b8314095e71538d231a7eee575Yigit Boyar animator.mAnimateDisappearanceList), CoreMatchers.is(reUse)); 16613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar waitForAnimations(10); 16713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.getChildCount(), CoreMatchers.is(0)); 16813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (useScrap || !reUse) { 16913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecycled.contains(vh), CoreMatchers.is(true)); 17013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } else { 17113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(vh), 17213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar CoreMatchers.is(true)); 17313a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 17413a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 17513a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar if (!reUse) { 17613a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecycled.contains(updatedVH[0]), CoreMatchers.is(false)); 17713a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(updatedVH[0]), 17813a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar CoreMatchers.is(true)); 17913a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 18013a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar } 18113a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar 18213a0acc0df34344c0b4fd4b494a64e7dcf195b56Yigit Boyar @Test 1830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detectStableIdError() throws Throwable { 18466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar setIgnoreMainThreadException(true); 185b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar final AtomicBoolean useBadIds = new AtomicBoolean(false); 186b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar TestAdapter adapter = new TestAdapter(10) { 187b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 188b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public long getItemId(int position) { 189b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar if (useBadIds.get() && position == 5) { 190b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position) - 1; 191b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 192b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar return super.getItemId(position); 193b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 194b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 195b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar @Override 196b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar public void onDetachedFromRecyclerView(RecyclerView recyclerView) { 197b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // ignore validation 198b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 199b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar }; 200b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.setHasStableIds(true); 201b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar setupBasic(10, 0, 10, adapter); 202b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.expectLayouts(2); 203b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar useBadIds.set(true); 204b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar adapter.changeAndNotify(4, 2); 205b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar mLayoutManager.waitForLayout(2); 20666826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar assertTrue(getMainThreadException() instanceof IllegalStateException); 20766826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar assertTrue(getMainThreadException().getMessage() 208b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar .contains("Two different ViewHolders have the same stable ID.")); 209b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar // TODO don't use this after moving this class to Junit 4 210b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar try { 211b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar removeRecyclerView(); 212b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } catch (Throwable t){} 213b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar } 214b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 215b2a6ee1e0b6c4343a52b7e176c29d0cfebcd1617Yigit Boyar 2160a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithoutPredictive() throws Throwable { 2189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 2229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 2289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 2299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar fail("pre layout is not expected"); 2309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 2349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 2379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar View targetView = recycler 2389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getViewForPosition(target.getAdapterPosition()); 2399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertSame(targetView, target.itemView); 2409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 2419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 2459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 2489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 2499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 2509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 2529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 2539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 2549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 2559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 2569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 2579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 2589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 2599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 2609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 2619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance 2629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 2639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 2649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 2659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 2679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontLayoutReusedViewWithPredictive() throws Throwable { 2719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 2729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 2749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final TestViewHolder target) throws Throwable { 2759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 2769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 2779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 2789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 2799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 2819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 2829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 2839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 2849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 2889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 7; 2919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePostLayout(recycler, layoutManager, state); 2929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 2939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 2949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 2959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 2969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 2979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 2989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPostLayout(recycler, layoutManager, state); 2999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertNull("test sanity. this view should not be re-laid out in post " 3009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + "layout", target.itemView.getParent()); 3019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 3039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 3049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 3059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 3079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This is a LayoutManager problem if it asked for the view but didn't properly 3119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // lay it out. It will move to disappearance. 3129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 3159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutPredictive() throws Throwable { 3219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.requestSimpleAnimationsInNextLayout(); 3309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 3319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 3329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithoutAnimations() throws Throwable { 3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3619051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3629051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithPredictive() throws Throwable { 3689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 3749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 3759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 3769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 3779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 3789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 3799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 3809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM does not layout the additional item so it does predictive wrong. 3819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // We should still handle it and animate persistence for this item 3829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 3839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 3849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 3859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 3869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 3879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 3889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 3909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 3920a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void reuseHiddenViewWithProperPredictive() throws Throwable { 3949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 3959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 3969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 3979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 3989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 3999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 4009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 4019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 4029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 4039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 4059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 4069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 9; 4079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.beforePreLayout(recycler, lm, state); 4089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 4129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar AnimationLayoutManager layoutManager, 4139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 4149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutItemCount = 8; 4159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.afterPreLayout(recycler, layoutManager, state); 4169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 4189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 4209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.deleteAndNotify(2, 1); 4219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // This LM implements predictive animations properly by requesting target view 4249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // in pre-layout. 4259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 4279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mMoveVHs.contains(target)); 4309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 4319051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4329051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 435ad91601c2d79f3a5b5124c617027e09e89d84a1eAurimas Liutikas // Disable this test on ICS because it causes testing devices to freeze. 436ad91601c2d79f3a5b5124c617027e09e89d84a1eAurimas Liutikas @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) 4370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 4380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseHiddenViewOnInvalidate() throws Throwable { 4399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 4409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 4429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 4439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 4449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 4459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 4469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 4479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 4489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.dispatchDataSetChanged(); 4499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(mRecyclerView.getItemAnimator().isRunning()); 4529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList)); 4549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 4579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 4620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontReuseOnTypeChange() throws Throwable { 4639051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar reuseHiddenViewTest(new ReuseTestCallback() { 4649051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4659051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void postSetup(List<TestViewHolder> recycledList, 4669051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target) throws Throwable { 4679051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // it should move to change scrap and then show up from there 4689051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView 4699051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .getItemAnimator(); 4709051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar itemAnimator.reset(); 4719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(1); 4729051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar target.mBoundItem.mType += 2; 4739051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9; 4749051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1); 4759051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar requestLayoutOnUIThread(mRecyclerView); 4769051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 4779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(itemAnimator.mChangeOldVHs.contains(target)); 4799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList)); 4809051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList)); 4819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList)); 4829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView)); 4839051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertFalse(recycledVHs.contains(target)); 4849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar waitForAnimations(5); 4859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue(recycledVHs.contains(target)); 4869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }); 4889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar interface ReuseTestCallback { 4919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable; 4939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4949051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 4959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 4969051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar protected RecyclerView.ItemAnimator createItemAnimator() { 4979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar return new LoggingItemAnimator(); 4989051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 4999051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 5009051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable { 5019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestAdapter adapter = new TestAdapter(10) { 5029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 5039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar public void onViewRecycled(TestViewHolder holder) { 5049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar super.onViewRecycled(holder); 5059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar recycledVHs.add(holder); 5069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 5079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }; 5089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar setupBasic(10, 0, 10, adapter); 5099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.setItemViewCacheSize(0); 5109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9); 5119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setAddDuration(1000); 5129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setRemoveDuration(1000); 5139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setChangeDuration(1000); 5149051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mRecyclerView.getItemAnimator().setMoveDuration(1000); 5159051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 5169051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.expectLayouts(2); 5179051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(2, 1); 5189051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.waitForLayout(2); 5199051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // test sanity, make sure target is hidden now 5209051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView)); 5219051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar callback.postSetup(recycledVHs, target); 5229051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN 5239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED 5249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION 5259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 5269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 5279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 5280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void detachBeforeAnimations() throws Throwable { 5300ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar setupBasic(10, 0, 5); 5310ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final RecyclerView rv = mRecyclerView; 5320ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar waitForAnimations(2); 5330ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar final DefaultItemAnimator animator = new DefaultItemAnimator() { 5340ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar @Override 5350ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar public void runPendingAnimations() { 5360ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar super.runPendingAnimations(); 5370ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 5380ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar }; 5390ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar rv.setItemAnimator(animator); 5400ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.expectLayouts(2); 5410ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mTestAdapter.deleteAndNotify(3, 4); 5420ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar mLayoutManager.waitForLayout(2); 5430ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar removeRecyclerView(); 5440ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertNull("test sanity check RV should be removed", rv.getParent()); 5450ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size()); 5460ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar assertFalse("there should not be any animations running", animator.isRunning()); 5470ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar } 5480ec96558f829719283bb1a49ff218c3ce1430626Yigit Boyar 5490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 5500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void moveDeleted() throws Throwable { 5515a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar setupBasic(4, 0, 3); 5525a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar waitForAnimations(2); 5535a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final View[] targetChild = new View[1]; 5545a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar final LoggingItemAnimator animator = new LoggingItemAnimator(); 55542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 5565a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5575a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 5585a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.setItemAnimator(animator); 5595a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = mRecyclerView.getChildAt(1); 5605a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5615a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5625a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 5635a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertNotNull("test sanity", targetChild); 5645a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(1); 56542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 5665a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5675a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void run() { 5685a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { 5695a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar @Override 5705a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 5719051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar RecyclerView.State state) { 5725a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar if (view == targetChild[0]) { 5735a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(10, 20, 30, 40); 5745a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } else { 5755a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar outRect.set(0, 0, 0, 0); 5765a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5775a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5785a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5795a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5805a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar }); 5815a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(1); 5825a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 5835a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar // now delete that item. 5845a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.expectLayouts(2); 5855a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]); 5865a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar targetChild[0] = null; 5875a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 5885a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar mLayoutManager.waitForLayout(2); 5895a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertFalse("if deleted view moves, it should not be in move animations", 5905a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar animator.mMoveVHs.contains(targetVH)); 5915a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size()); 5925a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH 5935a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar )); 5945a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar } 5955a9366fba5e26329bc9a988cfd2d43df980f2764Yigit Boyar 596344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev private void runTestImportantForAccessibilityWhileDeteling( 597344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int boundImportantForAccessibility, 598344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final int expectedImportantForAccessibility) throws Throwable { 599344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Adapter binding the item to the initial accessibility option. 600344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // RecyclerView is expected to change it to 'expectedImportantForAccessibility'. 601344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev TestAdapter adapter = new TestAdapter(1) { 602344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 603344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void onBindViewHolder(TestViewHolder holder, int position) { 604344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev super.onBindViewHolder(holder, position); 605344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.setImportantForAccessibility( 606344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev holder.itemView, boundImportantForAccessibility); 607344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 608344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }; 609344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 610344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Set up with 1 item. 611344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev setupBasic(1, 0, 1, adapter); 612344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 613344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final View[] targetChild = new View[1]; 614344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev final LoggingItemAnimator animator = new LoggingItemAnimator(); 615344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev animator.setRemoveDuration(500); 61642e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 617344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 618344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 619344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mRecyclerView.setItemAnimator(animator); 620344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev targetChild[0] = mRecyclerView.getChildAt(0); 621344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 622344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 623344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 624344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 625344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 626344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 627344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertNotNull("test sanity", targetChild[0]); 628344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 629344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // now delete that item. 630344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 631344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.deleteAndNotify(0, 1); 632344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 633344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 634344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 63542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 636344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 637344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 638344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is still a child of mRecyclerView, and is invisible for accessibility. 639344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == mRecyclerView); 640344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 641344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 642344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 643344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 644344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 645344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 646344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev waitForAnimations(2); 647344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 648344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Delete animation is now complete. 64942e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 650344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 651344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 652344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view is in recycled state, and back to the expected accessibility. 653344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue(targetChild[0].getParent() == null); 654344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 655344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 656344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 657344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 658344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 659344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 660344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // Add 1 element, which should use same view. 661344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.expectLayouts(2); 662344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mTestAdapter.addAndNotify(1); 663344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mLayoutManager.waitForLayout(2); 664344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 66542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 666344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev @Override 667344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev public void run() { 668344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev // The view should be reused, and have the expected accessibility. 669344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertTrue( 670344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0)); 671344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev assertEquals( 672344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev expectedImportantForAccessibility, 673344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.getImportantForAccessibility(targetChild[0])); 674344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 675344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev }); 676344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 677344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6794c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyar @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 6800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingAuto() throws Throwable { 681344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 682344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO, 683344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 684344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 685344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6860a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6874c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyar @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 6880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNo() throws Throwable { 689344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 690344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO, 691344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); 692344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 693344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 6940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 6954c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyar @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 6960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable { 697344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 698344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 699344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); 700344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 701344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 7020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 7034c74dbe97fdd0d0ca7848bdc3a6a037b2a8d851bYigit Boyar @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 7040a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void importantForAccessibilityWhileDetelingYes() throws Throwable { 705344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev runTestImportantForAccessibilityWhileDeteling( 706344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES, 707344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 708344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 709344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 7100a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 7110a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void preLayoutPositionCleanup() throws Throwable { 71242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar setupBasic(4, 0, 4); 71342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.expectLayouts(2); 71442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 71542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 71642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 71742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 71842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 71942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 3; 72042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 72142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 72242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar @Override 72342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, 72442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar AnimationLayoutManager layoutManager, 72542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar RecyclerView.State state) { 72642c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutMin = 0; 72742c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutItemCount = 4; 72842c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 72942c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar }; 73042c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mTestAdapter.addAndNotify(0, 1); 73142c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar mLayoutManager.waitForLayout(2); 73242c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 73342c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 73442c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar } 73542c4af4ff383daf001263ae18a9b00b9fbf87487Yigit Boyar 7360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 7370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addRemoveSamePass() throws Throwable { 73893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final List<RecyclerView.ViewHolder> mRecycledViews 73993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 74093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar TestAdapter adapter = new TestAdapter(50) { 74193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 74293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public void onViewRecycled(TestViewHolder holder) { 74393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.onViewRecycled(holder); 74493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.add(holder); 74593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 74693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 74793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar adapter.setHasStableIds(true); 74893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar setupBasic(50, 3, 5, adapter); 74993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemViewCacheSize(0); 75093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> addVH 75193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 75293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> removeVH 75393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 75493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 75593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final ArrayList<RecyclerView.ViewHolder> moveVH 75693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 75793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 75893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar final View[] testView = new View[1]; 75993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 76093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 76193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateAdd(RecyclerView.ViewHolder holder) { 76293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar addVH.add(holder); 76393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 76493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 76593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 76693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 76793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 76893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar removeVH.add(holder); 76993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 77093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 77193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 77293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 77393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, 77493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar int toX, int toY) { 77593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar moveVH.add(holder); 77693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar return true; 77793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 77893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }); 77993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 78093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 78193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 78293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 78393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 78493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 78593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0] = recycler.getViewForPosition(45); 78693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST), 78793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST)); 78893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(), 78993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 10 + testView[0].getMeasuredHeight()); 79093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addView(testView[0], 4); 79193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 79293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 79393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar @Override 79493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar void afterPostLayout(RecyclerView.Recycler recycler, 79593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar AnimationLayoutManager layoutManager, 79693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar RecyclerView.State state) { 79793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar super.afterPostLayout(recycler, layoutManager, state); 79893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(), 79993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 50 + testView[0].getMeasuredHeight()); 80093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar layoutManager.addDisappearingView(testView[0], 4); 80193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 80293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar }; 80393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3; 80493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5; 80593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mRecycledViews.clear(); 80693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.expectLayouts(2); 80793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mTestAdapter.deleteAndNotify(3, 1); 80893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar mLayoutManager.waitForLayout(2); 80993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 81093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : addVH) { 81193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate add", testView[0], vh.itemView); 81293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 81393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : moveVH) { 81493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate move", testView[0], vh.itemView); 81593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 81693d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : removeVH) { 81793d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView); 81893d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 81993d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar boolean found = false; 82093d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar for (RecyclerView.ViewHolder vh : mRecycledViews) { 82193d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar found |= vh.itemView == testView[0]; 82293d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 82393d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar assertTrue("added-removed view should be recycled", found); 82493d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar } 82593d88283955af6643f2ea0f3cc6cbc34ea49f181Yigit Boyar 8260a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void tmpRemoveMe() throws Throwable { 828121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar changeAnimTest(false, false, true, false); 829121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 830121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 8310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 8320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void changeAnimations() throws Throwable { 8337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final boolean[] booleans = {true, false}; 8347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean supportsChange : booleans) { 8357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean changeType : booleans) { 8367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean hasStableIds : booleans) { 8377c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen for (boolean deleteSomeItems : booleans) { 8387c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems); 8397c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8407c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen removeRecyclerView(); 8417c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8427c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8437c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8447c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 845121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar 8467c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType, 8479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable { 8487c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int changedIndex = 3; 8497c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final int defaultType = 1; 8507c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType); 8517c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim + 8527c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", change view type:" + changeType + 8537c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen ", has stable ids:" + hasStableIds + 854121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar ", delete some items:" + deleteSomeItems; 8557c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestAdapter testAdapter = new TestAdapter(10) { 8567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8577c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public int getItemViewType(int position) { 8587c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return position == changedIndex ? changedIndexNewType.get() : defaultType; 8597c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8607c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public TestViewHolder onCreateViewHolder(ViewGroup parent, 8637c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int viewType) { 8647c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 8657c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 8667c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onCreateVH" + vh.toString()); 8677c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8687c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen return vh; 8697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8707c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8717c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8727c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void onBindViewHolder(TestViewHolder holder, 8737c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen int position) { 8747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.onBindViewHolder(holder, position); 8757c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (DEBUG) { 8767c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString()); 8777c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8797c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 8807c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen testAdapter.setHasStableIds(hasStableIds); 8817c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 8829051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 883121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 8847c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8857c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen final RecyclerView.ViewHolder toBeChangedVH = 886115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar mRecyclerView.findViewHolderForLayoutPosition(changedIndex); 8877c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 8887c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8897c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPreLayout(RecyclerView.Recycler recycler, 8907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, 8917c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen RecyclerView.State state) { 892115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 893115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 894121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar assertTrue(logPrefix + " changed view holder should have correct flag" 895121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar , vh.isUpdated()); 8967c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 8977c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 8987c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 8997c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen void afterPostLayout(RecyclerView.Recycler recycler, 9007c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen AnimationLayoutManager layoutManager, RecyclerView.State state) { 901115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition( 902115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar changedIndex); 9037c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (supportsChangeAnim) { 9047c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertNotSame(logPrefix + "a new VH should be given if change is supported", 9057c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen toBeChangedVH, vh); 9067c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else if (!changeType && hasStableIds) { 9077c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen assertSame(logPrefix + "if change animations are not supported but we have " 9087c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen + "stable ids, same view holder should be returned", toBeChangedVH, vh); 9097c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9107c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen super.beforePostLayout(recycler, layoutManager, state); 9117c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9127c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }; 9137c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.expectLayouts(1); 9147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (changeType) { 9157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen changedIndexNewType.set(defaultType + 1); 9167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (deleteSomeItems) { 91842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 9197c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen @Override 9207c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen public void run() { 9217c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen try { 9227c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.deleteAndNotify(changedIndex + 2, 1); 9237c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mTestAdapter.notifyItemChanged(3); 9247c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } catch (Throwable throwable) { 9257c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen throwable.printStackTrace(); 9267c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9287c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9297c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen }); 9307c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } else { 931121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.changeAndNotify(3, 1); 9327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9347c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen mLayoutManager.waitForLayout(2); 9357c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen } 9367c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen 9374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar private void testChangeWithPayload(final boolean supportsChangeAnim, 9384143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar final boolean canReUse, Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind) 9399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar throws Throwable { 94021b345f101abc385496f42d250e580d21f1287b6Dake Gu final List<Object> expectedPayloads = new ArrayList<Object>(); 94121b345f101abc385496f42d250e580d21f1287b6Dake Gu final int changedIndex = 3; 94221b345f101abc385496f42d250e580d21f1287b6Dake Gu TestAdapter testAdapter = new TestAdapter(10) { 94321b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 94421b345f101abc385496f42d250e580d21f1287b6Dake Gu public int getItemViewType(int position) { 94521b345f101abc385496f42d250e580d21f1287b6Dake Gu return 1; 94621b345f101abc385496f42d250e580d21f1287b6Dake Gu } 94721b345f101abc385496f42d250e580d21f1287b6Dake Gu 94821b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 94921b345f101abc385496f42d250e580d21f1287b6Dake Gu public TestViewHolder onCreateViewHolder(ViewGroup parent, 95021b345f101abc385496f42d250e580d21f1287b6Dake Gu int viewType) { 95121b345f101abc385496f42d250e580d21f1287b6Dake Gu TestViewHolder vh = super.onCreateViewHolder(parent, viewType); 95221b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 95321b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onCreateVH" + vh.toString()); 95421b345f101abc385496f42d250e580d21f1287b6Dake Gu } 95521b345f101abc385496f42d250e580d21f1287b6Dake Gu return vh; 95621b345f101abc385496f42d250e580d21f1287b6Dake Gu } 95721b345f101abc385496f42d250e580d21f1287b6Dake Gu 95821b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 95921b345f101abc385496f42d250e580d21f1287b6Dake Gu public void onBindViewHolder(TestViewHolder holder, 96021b345f101abc385496f42d250e580d21f1287b6Dake Gu int position, List<Object> payloads) { 96121b345f101abc385496f42d250e580d21f1287b6Dake Gu super.onBindViewHolder(holder, position); 96221b345f101abc385496f42d250e580d21f1287b6Dake Gu if (DEBUG) { 96321b345f101abc385496f42d250e580d21f1287b6Dake Gu Log.d(TAG, " onBind to " + position + "" + holder.toString()); 96421b345f101abc385496f42d250e580d21f1287b6Dake Gu } 965f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar assertEquals(expectedPayloads, payloads); 96621b345f101abc385496f42d250e580d21f1287b6Dake Gu } 96721b345f101abc385496f42d250e580d21f1287b6Dake Gu }; 96821b345f101abc385496f42d250e580d21f1287b6Dake Gu testAdapter.setHasStableIds(false); 96921b345f101abc385496f42d250e580d21f1287b6Dake Gu setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter); 970f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar mRecyclerView.setItemAnimator(new DefaultItemAnimator() { 971f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @Override 972f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, 973f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar @NonNull List<Object> payloads) { 974f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads); 975f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 976f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 9779051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations( 978121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar supportsChangeAnim); 97921b345f101abc385496f42d250e580d21f1287b6Dake Gu 98021b345f101abc385496f42d250e580d21f1287b6Dake Gu int numTests = notifyPayloads.length; 9819051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < numTests; i++) { 98221b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.expectLayouts(1); 98321b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.clear(); 98421b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) { 98521b345f101abc385496f42d250e580d21f1287b6Dake Gu expectedPayloads.add(expectedPayloadsInOnBind[i][j]); 98621b345f101abc385496f42d250e580d21f1287b6Dake Gu } 98721b345f101abc385496f42d250e580d21f1287b6Dake Gu final Object[] payloadsToSend = notifyPayloads[i]; 98842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 98921b345f101abc385496f42d250e580d21f1287b6Dake Gu @Override 99021b345f101abc385496f42d250e580d21f1287b6Dake Gu public void run() { 99121b345f101abc385496f42d250e580d21f1287b6Dake Gu for (int j = 0; j < payloadsToSend.length; j++) { 99221b345f101abc385496f42d250e580d21f1287b6Dake Gu mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]); 99321b345f101abc385496f42d250e580d21f1287b6Dake Gu } 99421b345f101abc385496f42d250e580d21f1287b6Dake Gu } 99521b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 99621b345f101abc385496f42d250e580d21f1287b6Dake Gu mLayoutManager.waitForLayout(2); 9979051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar checkForMainThreadException(); 99821b345f101abc385496f42d250e580d21f1287b6Dake Gu } 99921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 100021b345f101abc385496f42d250e580d21f1287b6Dake Gu 10010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10020a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayload() throws Throwable { 100321b345f101abc385496f42d250e580d21f1287b6Dake Gu // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 1004f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, true, 1005f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 1006f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 1007f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null, "cdf"}, 1008f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", null}, 1009f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{null, "abc"}, 1010f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 1011f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }, 1012f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[][]{ 1013f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc"}, 1014f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 1015f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 1016f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[0], 1017f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar new Object[]{"abc", "cdf"} 1018f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar }); 1019f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar } 1020f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar 10210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable { 1023f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar // for crossfading change animation, will receive EMPTY payload in onBindViewHolder 1024f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(true, false, 102521b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 10289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 10299051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 10309051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 103121b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 103221b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10339051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10349051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10359051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10369051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10379051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0] 103821b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 103921b345f101abc385496f42d250e580d21f1287b6Dake Gu } 104021b345f101abc385496f42d250e580d21f1287b6Dake Gu 10410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void noChangeAnimationWithPayload() throws Throwable { 104321b345f101abc385496f42d250e580d21f1287b6Dake Gu // for Change Animation disabled, payload should match the payloads unless 104421b345f101abc385496f42d250e580d21f1287b6Dake Gu // null payload is fired. 1045f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar testChangeWithPayload(false, true, 104621b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null, "cdf"}, 10499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", null}, 10509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{null, "abc"}, 10519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 105221b345f101abc385496f42d250e580d21f1287b6Dake Gu }, 105321b345f101abc385496f42d250e580d21f1287b6Dake Gu new Object[][]{ 10549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc"}, 10559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[0], 10589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new Object[]{"abc", "cdf"} 105921b345f101abc385496f42d250e580d21f1287b6Dake Gu }); 106021b345f101abc385496f42d250e580d21f1287b6Dake Gu } 106121b345f101abc385496f42d250e580d21f1287b6Dake Gu 10620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 10630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recycleDuringAnimations() throws Throwable { 1064504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final AtomicInteger childCount = new AtomicInteger(0); 1065504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final TestAdapter adapter = new TestAdapter(1000) { 1066504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1067504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public TestViewHolder onCreateViewHolder(ViewGroup parent, 1068504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar int viewType) { 1069504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 1070504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return super.onCreateViewHolder(parent, viewType); 1071504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1072504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }; 1073504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar setupBasic(1000, 10, 20, adapter); 1074504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10; 1075504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20; 1076504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1077504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 1078504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1079504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 1080504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar super.putRecycledView(scrap); 1081504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.decrementAndGet(); 1082504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1083504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1084504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar @Override 1085504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar public RecyclerView.ViewHolder getRecycledView(int viewType) { 1086504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType); 1087504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (recycledView != null) { 1088504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar childCount.incrementAndGet(); 1089504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1090504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar return recycledView; 1091504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1092504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar }); 1093504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 1094504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar // now keep adding children to trigger more children being created etc. 10959051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar for (int i = 0; i < 100; i++) { 1096504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar adapter.addAndNotify(15, 1); 1097504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar Thread.sleep(50); 1098504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1099504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar getInstrumentation().waitForIdleSync(); 1100504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar waitForAnimations(2); 1101504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar assertEquals("Children count should add up", childCount.get(), 1102504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size()); 1103504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar } 1104504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar 11050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChanged() throws Throwable { 1107b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar setupBasic(10, 3, 4); 1108b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar int layoutCount = mLayoutManager.mTotalLayoutCount; 1109b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(1); 111042e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1111b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar @Override 1112b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar public void run() { 1113b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar try { 1114b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.deleteAndNotify(4, 1); 1115cadd54707a7aaa4cfa9c8b8051c6185e8717f22eChet Haase mTestAdapter.dispatchDataSetChanged(); 1116b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } catch (Throwable throwable) { 1117b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar throwable.printStackTrace(); 1118b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1119b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 1120b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1121b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar }); 1122b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 1123b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar getInstrumentation().waitForIdleSync(); 1124b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar assertEquals("on notify data set changed, predictive animations should not run", 1125b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar layoutCount + 1, mLayoutManager.mTotalLayoutCount); 1126b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.expectLayouts(2); 1127b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mTestAdapter.addAndNotify(4, 2); 1128b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar // make sure animations recover 1129b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar mLayoutManager.waitForLayout(2); 1130b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar } 1131b7b44e5454dc409934bcc5609b81d1715c984d40Yigit Boyar 11320a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11330a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void stableIdNotifyDataSetChanged() throws Throwable { 1134e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final int itemCount = 20; 1135e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar List<Item> initialSet = new ArrayList<Item>(); 1136e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final TestAdapter adapter = new TestAdapter(itemCount) { 1137e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar @Override 1138e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public long getItemId(int position) { 1139e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return mItems.get(position).mId; 1140e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1141e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar }; 1142e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar adapter.setHasStableIds(true); 1143e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar initialSet.addAll(adapter.mItems); 1144e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() { 11459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 11469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter testAdapter) throws Throwable { 11479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item5 = adapter.mItems.get(5); 11489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar Item item6 = adapter.mItems.get(6); 11499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item5.mAdapterIndex = 6; 11509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar item6.mAdapterIndex = 5; 11519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.remove(5); 11529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.mItems.add(6, item5); 11539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.dispatchDataSetChanged(); 11549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar //hacky, we support only 1 layout pass 11559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mLayoutManager.layoutLatch.countDown(); 11569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 11579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6), 1158e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8), 1159e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar PositionConstraint.scrap(9, -1, 9)); 1160e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar // now mix items. 1161e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 1162e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar 1163d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 11640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 11650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void getItemForDeletedView() throws Throwable { 11668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(false); 11678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar getItemForDeletedViewTest(true); 116811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 116911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 11708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void getItemForDeletedViewTest(boolean stableIds) throws Throwable { 117111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemViewTypeQueries = new HashSet<Integer>(); 117211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final Set<Integer> itemIdQueries = new HashSet<Integer>(); 117311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar TestAdapter adapter = new TestAdapter(10) { 117411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 117511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public int getItemViewType(int position) { 117611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.add(position); 117711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return super.getItemViewType(position); 117811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 117911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 118011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar @Override 118111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar public long getItemId(int position) { 118211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.add(position); 118311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar return mItems.get(position).mId; 118411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 118511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar }; 118611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.setHasStableIds(stableIds); 118711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar setupBasic(10, 0, 10, adapter); 118811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemViewType for all items should be called", 10, 118911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.size()); 119011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 119111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should be called when adapter has stable ids", 10, 119211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 119311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } else { 119411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertEquals("getItemId should not be called when adapter does not have stable ids", 0, 119511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.size()); 119611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 119711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.clear(); 119811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.clear(); 119911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.expectLayouts(2); 120011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar // delete last two 120111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteStart = 8; 120211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar final int deleteCount = adapter.getItemCount() - deleteStart; 120311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar adapter.deleteAndNotify(deleteStart, deleteCount); 120411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar mLayoutManager.waitForLayout(2); 120511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = 0; i < deleteStart; i++) { 120611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemViewType for existing item " + i + " should be called", 120711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 120811b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 120911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertTrue("getItemId for existing item " + i 12109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar + " should be called when adapter has stable ids", 121111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 121211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 121311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 121411b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar for (int i = deleteStart; i < deleteStart + deleteCount; i++) { 121511b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called", 121611b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemViewTypeQueries.contains(i)); 121711b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar if (adapter.hasStableIds()) { 12188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called", 121911b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar itemIdQueries.contains(i)); 122011b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 122111b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 122211b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar } 122311b7cfea15306c0d6e4ed7da09f7698df01695dfYigit Boyar 12240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12250a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisibleMultiStep() throws Throwable { 12268ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(1000, 1, 7); 12278ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 12288ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 12298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 12308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 12318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 12328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 12338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1}); 123490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar checkForMainThreadException(); 12358ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount -= 2; 12368ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 12388ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 12398ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 12408ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12418ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12428ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12438ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addManyMultiStep() throws Throwable { 12468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10, 1, 7); 12478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 12488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 12498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(1); 12508ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // try to trigger race conditions 12518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar int targetItemCount = mTestAdapter.getItemCount(); 12528ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < 100; i++) { 1253e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12548ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(0, 1); 1255e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12568ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.addAndNotify(7, 1); 12578ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar targetItemCount += 2; 12588ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1259e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12608ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // wait until main thread runnables are consumed 12618ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar while (targetItemCount != mTestAdapter.getItemCount()) { 12628ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Thread.sleep(100); 1263e09e0b4ea04b6b6b0ef6c62979e8abdead0bf378Yigit Boyar checkForMainThreadException(); 12648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 12690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicDelete() throws Throwable { 12708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 12718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() { 12728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void postDispatchLayout() { 12748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar // verify this only in first layout 12758ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar assertEquals("deleted views should still be children of RV", 12768ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.getChildCount() + mDeletedViewCount 12778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar , mRecyclerView.getChildCount()); 12788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 12818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void afterPreLayout(RecyclerView.Recycler recycler, 12828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar AnimationLayoutManager layoutManager, 12838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 12848ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.afterPreLayout(recycler, layoutManager, state); 12858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutItemCount = 3; 12868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutMin = 0; 12878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 12898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.mLayoutItemCount = 10; 12908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.setExpectedItemCounts(10, 3); 12918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.setOnLayoutCallbacks(callbacks); 12928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.expectLayouts(2); 12948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(0, 7); 12958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.waitForLayout(2); 12968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar callbacks.reset();// when animations end another layout will happen 12978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 12988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 12998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 13000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeDuringScrolling() throws Throwable { 1302d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar setupBasic(10); 1303d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 1304d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 1305d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1306d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 1307d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1308d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 1309d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 1310d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 1311d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onLayoutChildren(recycler, lm, state); 1312d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1313d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1314d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1315d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 1316d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar onScrollItemCount.set(state.getItemCount()); 1317d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar super.onScroll(dx, recycler, state); 1318d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1319d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 132042e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1321d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar @Override 1322d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar public void run() { 1323d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.remove(5); 1324d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.notifyItemRangeRemoved(5, 1); 1325d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mRecyclerView.scrollBy(0, 100); 1326d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 1327d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 1328d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 1329d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 1330d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 1331d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1332d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar }); 1333d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar } 1334d3f1c99a290de13631f9635e06444f75344967d2Yigit Boyar 13350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void notifyDataSetChangedDuringScroll() throws Throwable { 133717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar setupBasic(10); 133817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onLayoutItemCount = new AtomicInteger(0); 133917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar final AtomicInteger onScrollItemCount = new AtomicInteger(0); 134017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 134117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() { 134217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 134317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar void onLayoutChildren(RecyclerView.Recycler recycler, 134417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 134517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onLayoutItemCount.set(state.getItemCount()); 134617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onLayoutChildren(recycler, lm, state); 134717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 134817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 134917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 135017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 135117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar onScrollItemCount.set(state.getItemCount()); 135217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar super.onScroll(dx, recycler, state); 135317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 135417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 135542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 135617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar @Override 135717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar public void run() { 135817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.remove(5); 135917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.notifyDataSetChanged(); 136017d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mRecyclerView.scrollBy(0, 100); 136117d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertTrue("scrolling while there are pending adapter updates should " 136217d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0); 136317d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar assertEquals("scroll by should be called w/ updated adapter count", 136417d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar mTestAdapter.mItems.size(), onScrollItemCount.get()); 136517d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 136617d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 136717d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar }); 136817d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar } 136917d560c4a247dbfb795a2ea838c819cda77e5fa7Yigit Boyar 13700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisibleAndVisible() throws Throwable { 1372b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1373b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1374b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 13752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible 1376b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1377b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1378b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13800a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addInvisible() throws Throwable { 1381b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 1382b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1383b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12); 13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0 1385b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1386b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1387b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13880a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 13890a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void basicAdd() throws Throwable { 1390b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10); 1391b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 1392b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(10, 13); 1393b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.addAndNotify(2, 3); 1394b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1395b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1396b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 13976e51229d1d8dfb7ce1c38c658814ebf8d2ff0706Aurimas Liutikas // Run this test on Jelly Bean and newer because hasTransientState was introduced in API 16. 13986e51229d1d8dfb7ce1c38c658814ebf8d2ff0706Aurimas Liutikas @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) 13990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void appCancelAnimationInDetach() throws Throwable { 1401a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu final View[] addedView = new View[2]; 1402a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu TestAdapter adapter = new TestAdapter(1) { 1403a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1404a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void onViewDetachedFromWindow(TestViewHolder holder) { 1405a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView) 1406f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar && ViewCompat.hasTransientState(holder.itemView)) { 1407fa0f82f629bf95681c14ed559922f77a3030aa18Aurimas Liutikas holder.itemView.animate().cancel(); 1408a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1409a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu super.onViewDetachedFromWindow(holder); 1410a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1411a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1412a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // original 1 item 1413a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setupBasic(1, 0, 1, adapter); 1414cc1bf428e5bdbcc94e58107da4a100b279810a64Yigit Boyar mRecyclerView.getItemAnimator().setAddDuration(10000); 1415a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(2); 1416a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // add 2 items 1417a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu setExpectedItemCounts(1, 3); 1418a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mTestAdapter.addAndNotify(0, 2); 141966826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar mLayoutManager.waitForLayout(2); 1420629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar checkForMainThreadException(); 1421a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // wait till "add animation" starts 1422e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar int limit = 200; 1423a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu while (addedView[0] == null || addedView[1] == null) { 1424629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar Thread.sleep(100); 142542e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1426a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1427a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu public void run() { 1428a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu if (mRecyclerView.getChildCount() == 3) { 1429a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu View view = mRecyclerView.getChildAt(0); 1430f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1431a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[0] = view; 1432a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1433a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu view = mRecyclerView.getChildAt(1); 1434f3e710cfe6ee7027d5ad5b5b55fe00cff4136de8Yigit Boyar if (ViewCompat.hasTransientState(view)) { 1435a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu addedView[1] = view; 1436a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1437a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1438a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1439a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }); 1440e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar assertTrue("add should start on time", --limit > 0); 1441a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1442a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 1443a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu // Layout from item2, exclude the current adding items 1444a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.expectLayouts(1); 1445a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 1446a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu @Override 1447a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu void beforePostLayout(RecyclerView.Recycler recycler, 1448a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu AnimationLayoutManager layoutManager, 1449a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu RecyclerView.State state) { 1450a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutMin = 2; 1451a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutItemCount = 1; 1452a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1453a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu }; 1454a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu requestLayoutOnUIThread(mRecyclerView); 1455a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu mLayoutManager.waitForLayout(2); 1456a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu } 1457a75ca911e26945e0b326e7b70dd12378ace80270Dake Gu 14580a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14590a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeFrozen() throws Throwable { 1460ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu setupBasic(10, 1, 7); 1461ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertTrue(mRecyclerView.getChildCount() == 7); 1462ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1463ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.expectLayouts(2); 1464ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 1465ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8; 1466ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(true); 1467ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mTestAdapter.addAndNotify(0, 1); 1468ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1469ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2); 1470ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals(7, mRecyclerView.getChildCount()); 1471ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 1472ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu freezeLayout(false); 1473ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu mLayoutManager.waitForLayout(2); 1474ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu assertEquals("RV should get updated after waken from frozen", 1475ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 8, mRecyclerView.getChildCount()); 1476ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu } 1477ef3e37fe088c7d8e614bbc4ed58d6c0d3fa807a1Dake Gu 14780a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14790a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void removeScrapInvalidate() throws Throwable { 1480888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar setupBasic(10); 1481888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar TestRecyclerView testRecyclerView = getTestRecyclerView(); 1482888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.expectLayouts(1); 1483888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.expectDraw(1); 148442e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 1485888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar @Override 1486888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar public void run() { 1487888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.mItems.clear(); 1488888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mTestAdapter.notifyDataSetChanged(); 1489888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1490888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar }); 1491888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar mLayoutManager.waitForLayout(2); 1492888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar testRecyclerView.waitForDraw(2); 1493888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar } 1494888c70abaa77e15458c366b8d27835d176dcc546Yigit Boyar 14950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 14960a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteVisibleAndInvisible() throws Throwable { 1497b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(11, 3, 5); //layout items 3 4 5 6 7 1498b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 14998ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list 1500b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setExpectedItemCounts(9, 8); 1501b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9 1502b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1503b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1504b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 15050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15060a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void findPositionOffset() throws Throwable { 15078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar setupBasic(10); 150890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 150990ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar @Override 151090ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, 151190ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 151290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar super.beforePreLayout(recycler, lm, state); 151390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar // [0,2,4] 151490ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0)); 151590ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2)); 151690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4)); 151790ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar } 151890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar }; 151942e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 15208ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 15218ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void run() { 1522121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar try { 1523121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 1 1524121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(1, 1); 1525121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar // delete 3 1526121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar mTestAdapter.deleteAndNotify(2, 1); 1527121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } catch (Throwable throwable) { 1528121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar throwable.printStackTrace(); 1529121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 15308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }); 153290ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar mLayoutManager.waitForLayout(2); 15338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1535b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setLayoutRange(int start, int count) { 1536b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start; 1537b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count; 1538b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1539b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1540b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar private void setExpectedItemCounts(int preLayout, int postLayout) { 1541b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout); 1542b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1543b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 15440a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15450a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteInvisible() throws Throwable { 1546b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar setupBasic(10, 1, 7); 15478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1; 15488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7; 1549b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(1); 1550b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8); 15518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8 1552b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1553b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1554b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 1555e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar private CollectPositionResult findByPos(RecyclerView recyclerView, 1556e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int position) { 1557e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar View view = recycler.getViewForPosition(position, true); 1558e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view); 1559e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar if (vh.wasReturnedFromScrap()) { 1560e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar vh.clearReturnedFromScrapFlag(); //keep data consistent. 1561e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromScrap(vh); 1562e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } else { 1563e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar return CollectPositionResult.fromAdapter(vh); 15648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1567e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView, 1568e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) { 15698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positionToAdapterMapping 15708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar = new HashMap<Integer, CollectPositionResult>(); 15718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int position : positions) { 15728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (position < 0) { 15738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar continue; 15748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1575e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionToAdapterMapping.put(position, 1576e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar findByPos(recyclerView, recycler, state, position)); 15778ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15788ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar return positionToAdapterMapping; 15798ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 15808ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 15810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15820a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete2() throws Throwable { 15838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 15849051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 15859051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 15869051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 b 3 4 15879051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 15889051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre w/ adap: 0 1 2 b 3 4 15899051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 15909051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 15919051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2}); 15929051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 15939051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1), 15948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(3, 3, 3) 15958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 15968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1597d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 15980a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 15990a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addDelete1() throws Throwable { 16008ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(5, 0, 5, new AdapterOps() { 16019051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 3 4 16029051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 1 2 a b 3 4 16039051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 2 a b 3 4 16049051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a b 3 4 16059051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // 0 c d 2 a 4 16069051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // c d 2 a 4 16079051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar // pre: 0 1 2 3 4 16089051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 16099051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 16109051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1}, 16119051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1}); 16129051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 16139051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1), 16148ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1), 16158ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0), 16168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapter(1), PositionConstraint.adapter(3) 16178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16198ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 16210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addSameIndexTwice() throws Throwable { 16228ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 16239051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 16249051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 16259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1}, 16269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{11, 1}); 16279051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 16289051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3), 16298ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7), 16308ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12), 16318ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(8, 8, 13) 16328ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16338ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16348ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 16360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void deleteTwice() throws Throwable { 16378ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar positionStatesTest(12, 2, 7, new AdapterOps() { 16389051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar @Override 16399051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void onRun(TestAdapter adapter) throws Throwable { 16409051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1}, 16419051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar new int[]{0, 1});// delete item ids 0,2,9,1 16429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 16439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0), 16448ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2), 16458ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5), 16468ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7) 16478ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ); 16488ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16498ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 1650b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 16518ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 1652e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar int firstLayoutItemCount, AdapterOps adapterChanges, 1653e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1654e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null, 16559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar adapterChanges, constraints); 1656e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar } 16579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 1658e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar public void positionStatesTest(int itemCount, int firstLayoutStartIndex, 16599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges, 1660e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar final PositionConstraint... constraints) throws Throwable { 1661e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter); 1662b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.expectLayouts(2); 16638ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 16648ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 16658ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 16668ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 16678ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePreLayout(recycler, lm, state); 16688ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar //harmless 16698ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 16708ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 16718ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 16728ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPreLayoutPos; 16738ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16748ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1675e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1676121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1677121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 16789051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar positionLog.append(entry.getKey()).append(":").append(entry.getValue()) 16799051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar .append("\n"); 1680121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 16818ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 16828ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPreLayoutPos != -1) { 16838ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPreLayoutPos), 1684121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 16858ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16868ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16878ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16888ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar 16898ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar @Override 16908ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm, 16918ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar RecyclerView.State state) { 16928ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar super.beforePostLayout(recycler, lm, state); 16938ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar lm.detachAndScrapAttachedViews(recycler); 16948ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar final int[] ids = new int[constraints.length]; 16958ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (int i = 0; i < constraints.length; i++) { 16968ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar ids[i] = constraints[i].mPostLayoutPos; 16978ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 16988ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar Map<Integer, CollectPositionResult> positions 1699e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar = collectPositions(lm.mRecyclerView, recycler, state, ids); 1700121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar StringBuilder positionLog = new StringBuilder("\nPosition logs:\n"); 1701121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) { 1702121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar positionLog.append(entry.getKey()).append(":") 1703121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar .append(entry.getValue()).append("\n"); 1704121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar } 17058ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 17068ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar if (constraint.mPostLayoutPos >= 0) { 17078ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.validate(state, positions.get(constraint.mPostLayoutPos), 1708121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar lm.getLog() + positionLog); 17098ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 17108ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 17118ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 17128ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar }; 17138ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar adapterChanges.run(mTestAdapter); 1714b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar mLayoutManager.waitForLayout(2); 1715e0c347f627f8a78d3e5e3e5eaac9c3ae26208689Yigit Boyar checkForMainThreadException(); 17168ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar for (PositionConstraint constraint : constraints) { 17178ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar constraint.assertValidate(); 17188ae76f91527ce850f155ce960fb9068bcd5d49f9Yigit Boyar } 1719b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar } 1720b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar 17210a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 17220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void addThenRecycleRemovedView() throws Throwable { 17236a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar setupBasic(10); 17246a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final AtomicInteger step = new AtomicInteger(0); 17259051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final List<RecyclerView.ViewHolder> animateRemoveList 17269051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar = new ArrayList<RecyclerView.ViewHolder>(); 17276a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar DefaultItemAnimator animator = new DefaultItemAnimator() { 17286a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17296a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public boolean animateRemove(RecyclerView.ViewHolder holder) { 17306a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.add(holder); 17316a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar return super.animateRemove(holder); 17326a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17336a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 17346a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setItemAnimator(animator); 17356a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>(); 17366a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() { 17376a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17386a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar public void putRecycledView(RecyclerView.ViewHolder scrap) { 17396a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar pooledViews.add(scrap); 17406a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.putRecycledView(scrap); 17416a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17426a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }); 17436a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1]; 17446a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() { 17456a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar @Override 17466a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar void doLayout(RecyclerView.Recycler recycler, 17476a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar AnimationLayoutManager lm, RecyclerView.State state) { 17486a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar switch (step.get()) { 17496a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar case 1: 17506a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar super.doLayout(recycler, lm, state); 17516a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar if (state.isPreLayout()) { 17526a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar View view = mLayoutManager.getChildAt(1); 17536a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar RecyclerView.ViewHolder holder = 17546a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mRecyclerView.getChildViewHolderInt(view); 17556a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar targetVh[0] = holder; 17566a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity", holder.isRemoved()); 17576a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.removeAndRecycleView(view, recycler); 17586a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17596a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar break; 17606a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17616a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 17626a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar }; 17636a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar step.set(1); 17646a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.clear(); 17656a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.expectLayouts(2); 17666a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mTestAdapter.deleteAndNotify(1, 1); 17676a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar mLayoutManager.waitForLayout(2); 17686a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0])); 17696a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar assertTrue("since LM force recycled a view, animate disappearance should not be called", 17706a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar animateRemoveList.isEmpty()); 17716a6748f8ec1d1f2824cf5c7c6ee8ade8cad0a63aYigit Boyar } 1772d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase} 1773