1edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 3edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * 4edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * you may not use this file except in compliance with the License. 6edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * You may obtain a copy of the License at 7edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * 8edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * 10edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * See the License for the specific language governing permissions and 14edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * limitations under the License. 15edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar */ 16edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget; 18edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 198052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertEquals; 208052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertFalse; 21270dbafc72ebe758c904300983a81336ede8b823Chris Craikimport static org.junit.Assert.assertNotEquals; 228052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertNotNull; 238052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertNotSame; 248052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertNull; 258052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertSame; 268052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport static org.junit.Assert.assertTrue; 27166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craikimport static org.junit.Assert.fail; 280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 29ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyarimport android.content.Context; 30da85cbdb44e810c9c9ade11f65fdf36a795061efAurimas Liutikasimport android.os.Build; 31c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport android.os.Parcel; 32c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport android.os.Parcelable; 33429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyarimport android.os.SystemClock; 340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.InstrumentationRegistry; 35754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.SmallTest; 360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4; 37ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyarimport android.util.AttributeSet; 38ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyarimport android.util.SparseArray; 39bf3e1bfa77a11365778fade25697acde1a70800aChris Craikimport android.view.LayoutInflater; 40429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyarimport android.view.MotionEvent; 41edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.view.View; 42edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.view.ViewGroup; 43231e669441b388f220c6a9a0ae46b5c2f1b4d938susnataimport android.view.animation.Interpolator; 44231e669441b388f220c6a9a0ae46b5c2f1b4d938susnataimport android.view.animation.LinearInterpolator; 451e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craikimport android.widget.FrameLayout; 4650f048ddcd71fbb313f0673336920113cad28ee8Evan Roskyimport android.widget.LinearLayout; 47edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.widget.TextView; 48edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 49c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.NonNull; 50c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.recyclerview.test.R; 51c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas 528052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport org.junit.Before; 538052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport org.junit.Test; 548052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikasimport org.junit.runner.RunWith; 558052423a9ffce385de32ae76fa962e6316f03677Aurimas Liutikas 568123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craikimport java.lang.ref.WeakReference; 5771c54eb5572a3e93409024640b8af5740620085cYigit Boyarimport java.util.ArrayList; 5871c54eb5572a3e93409024640b8af5740620085cYigit Boyarimport java.util.List; 59c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport java.util.UUID; 60c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 61f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@SmallTest 620a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class) 630a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarpublic class RecyclerViewBasicTest { 64edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 65edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView mRecyclerView; 66edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 670a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Before 680a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void setUp() throws Exception { 690a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar mRecyclerView = new RecyclerView(getContext()); 700a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar } 710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 720a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar private Context getContext() { 73bf3e1bfa77a11365778fade25697acde1a70800aChris Craik return InstrumentationRegistry.getTargetContext(); 74edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 75edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 760a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 770a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void measureWithoutLayoutManager() { 78abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 79edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 80edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 81edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar private void measure() { 82edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240); 83edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 84edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 85edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar private void layout() { 86edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.layout(0, 0, 320, 320); 87edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 88edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 89abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar private void focusSearch() { 90abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.focusSearch(1); 91edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 92edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 930a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void layoutWithoutAdapter() throws InterruptedException { 95edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockLayoutManager layoutManager = new MockLayoutManager(); 96edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setLayoutManager(layoutManager); 97abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 98edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertEquals("layout manager should not be called if there is no adapter attached", 99edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 0, layoutManager.mLayoutCount); 100edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 101edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 1026bc164c64d7f4cea6a1f155439269fd189a77d3bYigit Boyar public void setScrollContainer() { 1036bc164c64d7f4cea6a1f155439269fd189a77d3bYigit Boyar assertEquals("RecyclerView should announce itself as scroll container for the IME to " 1046bc164c64d7f4cea6a1f155439269fd189a77d3bYigit Boyar + "handle it properly", true, mRecyclerView.isScrollContainer()); 1056bc164c64d7f4cea6a1f155439269fd189a77d3bYigit Boyar } 1066bc164c64d7f4cea6a1f155439269fd189a77d3bYigit Boyar 1070a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1080a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void layoutWithoutLayoutManager() throws InterruptedException { 109abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 110abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 111abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 112abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 113abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1140a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1150a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void focusWithoutLayoutManager() throws InterruptedException { 116abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 117abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 118abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 119abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar focusSearch(); 120abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 121abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollWithoutLayoutManager() throws InterruptedException { 124abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 125abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 126abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 127abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.scrollBy(10, 10); 128abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 129abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1300a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1310a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollWithoutLayoutManager() throws InterruptedException { 132abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 133abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 134abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 135abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.smoothScrollBy(10, 10); 136abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 137abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1380a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1390a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void scrollToPositionWithoutLayoutManager() throws InterruptedException { 140abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 141abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 142abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 143abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.scrollToPosition(5); 144abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 145abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1460a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void smoothScrollToPositionWithoutLayoutManager() throws InterruptedException { 148abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 149abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar measure(); 150abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar layout(); 151abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar mRecyclerView.smoothScrollToPosition(5); 152abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar } 153abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar 1540a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1550a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void interceptTouchWithoutLayoutManager() { 156429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 157429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar measure(); 158429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar layout(); 159429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar assertFalse(mRecyclerView.onInterceptTouchEvent( 160429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar MotionEvent.obtain(SystemClock.uptimeMillis(), 161429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0))); 162429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar } 163429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar 1640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void onTouchWithoutLayoutManager() { 166429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar mRecyclerView.setAdapter(new MockAdapter(20)); 167429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar measure(); 168429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar layout(); 169429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar assertFalse(mRecyclerView.onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), 170429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0))); 171429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar } 172429a9029d941a91972cd7601aa7e6d3718872c65Yigit Boyar 1730a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void layoutSimple() throws InterruptedException { 175edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockLayoutManager layoutManager = new MockLayoutManager(); 176edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setLayoutManager(layoutManager); 177edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(new MockAdapter(3)); 178edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar layout(); 179edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertEquals("when both layout manager and activity is set, recycler view should call" 180edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar + " layout manager's layout method", 1, layoutManager.mLayoutCount); 181edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 182edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 1830a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 1840a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void observingAdapters() { 185edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockAdapter adapterOld = new MockAdapter(1); 186edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(adapterOld); 187edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertTrue("attached adapter should have observables", adapterOld.hasObservers()); 188edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 189edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockAdapter adapterNew = new MockAdapter(2); 190edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(adapterNew); 191edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertFalse("detached adapter should lose observable", adapterOld.hasObservers()); 192edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertTrue("new adapter should have observers", adapterNew.hasObservers()); 193edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 194edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(null); 195edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertNull("adapter should be removed successfully", mRecyclerView.getAdapter()); 196edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertFalse("when adapter is removed, observables should be removed too", 197edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar adapterNew.hasObservers()); 198edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 199edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 2000a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2010a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void adapterChangeCallbacks() { 202edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockLayoutManager layoutManager = new MockLayoutManager(); 203edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setLayoutManager(layoutManager); 204edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockAdapter adapterOld = new MockAdapter(1); 205edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(adapterOld); 206edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar layoutManager.assertPrevNextAdapters(null, adapterOld); 207edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 208edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar MockAdapter adapterNew = new MockAdapter(2); 209edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(adapterNew); 210edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar layoutManager.assertPrevNextAdapters("switching adapters should trigger correct callbacks" 211edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar , adapterOld, adapterNew); 212edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 213edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mRecyclerView.setAdapter(null); 214edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar layoutManager.assertPrevNextAdapters( 215edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar "Setting adapter null should trigger correct callbacks", 216edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar adapterNew, null); 217edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 218edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 2190a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2200a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recyclerOffsetsOnMove() { 22171c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockLayoutManager layoutManager = new MockLayoutManager(); 22271c54eb5572a3e93409024640b8af5740620085cYigit Boyar final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>(); 22371c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.setLayoutManager(layoutManager); 22471c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockAdapter adapter = new MockAdapter(100) { 22571c54eb5572a3e93409024640b8af5740620085cYigit Boyar @Override 2268a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { 22771c54eb5572a3e93409024640b8af5740620085cYigit Boyar super.onViewRecycled(holder); 22871c54eb5572a3e93409024640b8af5740620085cYigit Boyar recycledVhs.add(holder); 22971c54eb5572a3e93409024640b8af5740620085cYigit Boyar } 23071c54eb5572a3e93409024640b8af5740620085cYigit Boyar }; 23171c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockViewHolder mvh = new MockViewHolder(new TextView(getContext())); 23271c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.setAdapter(adapter); 23371c54eb5572a3e93409024640b8af5740620085cYigit Boyar adapter.bindViewHolder(mvh, 20); 23471c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.mRecycler.mCachedViews.add(mvh); 23571c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.offsetPositionRecordsForRemove(10, 9, false); 23671c54eb5572a3e93409024640b8af5740620085cYigit Boyar 23771c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.offsetPositionRecordsForRemove(11, 1, false); 23871c54eb5572a3e93409024640b8af5740620085cYigit Boyar assertEquals(1, recycledVhs.size()); 23971c54eb5572a3e93409024640b8af5740620085cYigit Boyar assertSame(mvh, recycledVhs.get(0)); 24071c54eb5572a3e93409024640b8af5740620085cYigit Boyar } 24171c54eb5572a3e93409024640b8af5740620085cYigit Boyar 2420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void recyclerOffsetsOnAdd() { 24471c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockLayoutManager layoutManager = new MockLayoutManager(); 24571c54eb5572a3e93409024640b8af5740620085cYigit Boyar final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>(); 24671c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.setLayoutManager(layoutManager); 24771c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockAdapter adapter = new MockAdapter(100) { 24871c54eb5572a3e93409024640b8af5740620085cYigit Boyar @Override 2498a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { 25071c54eb5572a3e93409024640b8af5740620085cYigit Boyar super.onViewRecycled(holder); 25171c54eb5572a3e93409024640b8af5740620085cYigit Boyar recycledVhs.add(holder); 25271c54eb5572a3e93409024640b8af5740620085cYigit Boyar } 25371c54eb5572a3e93409024640b8af5740620085cYigit Boyar }; 25471c54eb5572a3e93409024640b8af5740620085cYigit Boyar MockViewHolder mvh = new MockViewHolder(new TextView(getContext())); 25571c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.setAdapter(adapter); 25671c54eb5572a3e93409024640b8af5740620085cYigit Boyar adapter.bindViewHolder(mvh, 20); 25771c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.mRecycler.mCachedViews.add(mvh); 25871c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.offsetPositionRecordsForRemove(10, 9, false); 25971c54eb5572a3e93409024640b8af5740620085cYigit Boyar 26071c54eb5572a3e93409024640b8af5740620085cYigit Boyar mRecyclerView.offsetPositionRecordsForInsert(15, 10); 26171c54eb5572a3e93409024640b8af5740620085cYigit Boyar assertEquals(11, mvh.mPosition); 26271c54eb5572a3e93409024640b8af5740620085cYigit Boyar } 26371c54eb5572a3e93409024640b8af5740620085cYigit Boyar 2640a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2650a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void savedStateWithStatelessLayoutManager() throws InterruptedException { 266c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mRecyclerView.setLayoutManager(new MockLayoutManager() { 267c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 268c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public Parcelable onSaveInstanceState() { 269c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar return null; 270c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 271c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar }); 272c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mRecyclerView.setAdapter(new MockAdapter(3)); 273c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar Parcel parcel = Parcel.obtain(); 274c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar String parcelSuffix = UUID.randomUUID().toString(); 275c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar Parcelable savedState = mRecyclerView.onSaveInstanceState(); 276c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar savedState.writeToParcel(parcel, 0); 277c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.writeString(parcelSuffix); 278c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 279c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar // reset position for reading 280c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.setDataPosition(0); 2810a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView restored = new RecyclerView(getContext()); 282c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar restored.setLayoutManager(new MockLayoutManager()); 283c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mRecyclerView.setAdapter(new MockAdapter(3)); 284c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar // restore 285c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel); 286c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar restored.onRestoreInstanceState(savedState); 287c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 288c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertEquals("Parcel reading should not go out of bounds", parcelSuffix, 289c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.readString()); 290c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail()); 291c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 292c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 293c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 2940a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2950a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void savedState() throws InterruptedException { 296c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar MockLayoutManager mlm = new MockLayoutManager(); 297c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mRecyclerView.setLayoutManager(mlm); 298c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mRecyclerView.setAdapter(new MockAdapter(3)); 299c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar layout(); 300c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar Parcelable savedState = mRecyclerView.onSaveInstanceState(); 301c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar // we append a suffix to the parcelable to test out of bounds 302c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar String parcelSuffix = UUID.randomUUID().toString(); 303c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar Parcel parcel = Parcel.obtain(); 304c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar savedState.writeToParcel(parcel, 0); 305c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.writeString(parcelSuffix); 306c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 307c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar // reset for reading 308c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.setDataPosition(0); 309c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar // re-create 310c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel); 311c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 3120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar RecyclerView restored = new RecyclerView(getContext()); 313c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar MockLayoutManager mlmRestored = new MockLayoutManager(); 314c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar restored.setLayoutManager(mlmRestored); 315c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar restored.setAdapter(new MockAdapter(3)); 316c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar restored.onRestoreInstanceState(savedState); 317c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 318c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertEquals("Parcel reading should not go out of bounds", parcelSuffix, 319c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar parcel.readString()); 320c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail()); 321c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertEquals("uuid in layout manager should be preserved properly", mlm.mUuid, 322c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mlmRestored.mUuid); 323c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar assertNotSame("stateless parameter should not be preserved", mlm.mLayoutCount, 324c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mlmRestored.mLayoutCount); 325c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar layout(); 326c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 327c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 3280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 3290a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void dontSaveChildrenState() throws InterruptedException { 330ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar MockLayoutManager mlm = new MockLayoutManager() { 331ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar @Override 332ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 333ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar super.onLayoutChildren(recycler, state); 334ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar View view = recycler.getViewForPosition(0); 335ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar addView(view); 336ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar measureChildWithMargins(view, 0, 0); 337ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 338ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 339ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar }; 340ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar mRecyclerView.setLayoutManager(mlm); 341ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar mRecyclerView.setAdapter(new MockAdapter(3) { 3428a11e6829c522aa1efcc903afa4c01d337082eabChris Craik @NonNull 343ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar @Override 3448a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public RecyclerView.ViewHolder onCreateViewHolder( 3458a11e6829c522aa1efcc903afa4c01d337082eabChris Craik @NonNull ViewGroup parent, int viewType) { 346ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar final LoggingView itemView = new LoggingView(parent.getContext()); 3470a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar //noinspection ResourceType 348ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar itemView.setId(3); 349ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar return new MockViewHolder(itemView); 350ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 351ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar }); 352ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar measure(); 353ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar layout(); 354ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar View view = mRecyclerView.getChildAt(0); 355ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar assertNotNull("test sanity", view); 356ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar LoggingView loggingView = (LoggingView) view; 357ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar SparseArray<Parcelable> container = new SparseArray<Parcelable>(); 358ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar mRecyclerView.saveHierarchyState(container); 359ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar assertEquals("children's save state method should not be called", 0, 360ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar loggingView.getOnSavedInstanceCnt()); 361ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 362ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 363231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata @Test 364231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata public void smoothScrollWithCustomInterpolator() { 365231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata mRecyclerView.setLayoutManager(new MockLayoutManager()); 366231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata mRecyclerView.setAdapter(new MockAdapter(20)); 367231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata Interpolator interpolator = new LinearInterpolator(); 368231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata mRecyclerView.smoothScrollBy(0, 100, interpolator); 369231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata assertSame(interpolator, mRecyclerView.mViewFlinger.mInterpolator); 370231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata 371231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata mRecyclerView.smoothScrollBy(0, -100); 372231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata assertSame(RecyclerView.sQuinticInterpolator, mRecyclerView.mViewFlinger.mInterpolator); 373231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata } 374231e669441b388f220c6a9a0ae46b5c2f1b4d938susnata 375ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik @Test 376bf3e1bfa77a11365778fade25697acde1a70800aChris Craik public void createAttachedException() { 377bf3e1bfa77a11365778fade25697acde1a70800aChris Craik mRecyclerView.setAdapter(new RecyclerView.Adapter() { 378bf3e1bfa77a11365778fade25697acde1a70800aChris Craik @NonNull 379bf3e1bfa77a11365778fade25697acde1a70800aChris Craik @Override 380bf3e1bfa77a11365778fade25697acde1a70800aChris Craik public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 381bf3e1bfa77a11365778fade25697acde1a70800aChris Craik int viewType) { 382bf3e1bfa77a11365778fade25697acde1a70800aChris Craik View view = LayoutInflater.from(parent.getContext()) 383bf3e1bfa77a11365778fade25697acde1a70800aChris Craik .inflate(R.layout.item_view, parent, true) 384bf3e1bfa77a11365778fade25697acde1a70800aChris Craik .findViewById(R.id.item_view); // find child, since parent is returned 385bf3e1bfa77a11365778fade25697acde1a70800aChris Craik return new RecyclerView.ViewHolder(view) {}; 386bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } 387bf3e1bfa77a11365778fade25697acde1a70800aChris Craik 388bf3e1bfa77a11365778fade25697acde1a70800aChris Craik @Override 389bf3e1bfa77a11365778fade25697acde1a70800aChris Craik public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 390bf3e1bfa77a11365778fade25697acde1a70800aChris Craik fail("shouldn't get here, should throw during create"); 391bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } 392bf3e1bfa77a11365778fade25697acde1a70800aChris Craik 393bf3e1bfa77a11365778fade25697acde1a70800aChris Craik @Override 394bf3e1bfa77a11365778fade25697acde1a70800aChris Craik public int getItemCount() { 395bf3e1bfa77a11365778fade25697acde1a70800aChris Craik return 1; 396bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } 397bf3e1bfa77a11365778fade25697acde1a70800aChris Craik }); 398bf3e1bfa77a11365778fade25697acde1a70800aChris Craik mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 399bf3e1bfa77a11365778fade25697acde1a70800aChris Craik 400bf3e1bfa77a11365778fade25697acde1a70800aChris Craik try { 401bf3e1bfa77a11365778fade25697acde1a70800aChris Craik measure(); 402bf3e1bfa77a11365778fade25697acde1a70800aChris Craik //layout(); 403bf3e1bfa77a11365778fade25697acde1a70800aChris Craik fail("IllegalStateException expected"); 404bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } catch (IllegalStateException e) { 405bf3e1bfa77a11365778fade25697acde1a70800aChris Craik // expected 406bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } 407bf3e1bfa77a11365778fade25697acde1a70800aChris Craik } 408bf3e1bfa77a11365778fade25697acde1a70800aChris Craik 409bf3e1bfa77a11365778fade25697acde1a70800aChris Craik @Test 410ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik public void prefetchChangesCacheSize() { 411945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik mRecyclerView.setAdapter(new MockAdapter(20)); 412ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik MockLayoutManager mlm = new MockLayoutManager() { 413ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik @Override 4141e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state, 4153104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik RecyclerView.LayoutManager.LayoutPrefetchRegistry prefetchManager) { 416945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik prefetchManager.addPosition(0, 0); 417945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik prefetchManager.addPosition(1, 0); 418945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik prefetchManager.addPosition(2, 0); 419ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik } 420ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik }; 421945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik 422ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik RecyclerView.Recycler recycler = mRecyclerView.mRecycler; 423ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax); 424ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik mRecyclerView.setLayoutManager(mlm); 425945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax); 426945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik 427945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 4281797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik // layout, so prefetches can occur 4291797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik mRecyclerView.measure(View.MeasureSpec.EXACTLY | 100, View.MeasureSpec.EXACTLY | 100); 4301797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik mRecyclerView.layout(0, 0, 100, 100); 4311797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik 4321797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik // prefetch gets 3 items, so expands cache by 3 4331e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik mRecyclerView.mPrefetchRegistry.collectPrefetchPositionsFromView(mRecyclerView, false); 4341797d0dedfc9c06a83efb9090f19e3ffd14b2677Chris Craik assertEquals(3, mRecyclerView.mPrefetchRegistry.mCount); 435945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax); 436945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik 437945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik // Reset to default by removing layout 438945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik mRecyclerView.setLayoutManager(null); 439945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax); 440945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik 441945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik // And restore by restoring layout 442945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik mRecyclerView.setLayoutManager(mlm); 443945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax); 444945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik } 445ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik } 446ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik 447270dbafc72ebe758c904300983a81336ede8b823Chris Craik @Test 448270dbafc72ebe758c904300983a81336ede8b823Chris Craik public void getNanoTime() { 449270dbafc72ebe758c904300983a81336ede8b823Chris Craik if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 450270dbafc72ebe758c904300983a81336ede8b823Chris Craik // check that it looks vaguely time-ish 451270dbafc72ebe758c904300983a81336ede8b823Chris Craik long time = mRecyclerView.getNanoTime(); 452270dbafc72ebe758c904300983a81336ede8b823Chris Craik assertNotEquals(0, time); 453270dbafc72ebe758c904300983a81336ede8b823Chris Craik assertNotEquals(time, mRecyclerView.getNanoTime()); 454270dbafc72ebe758c904300983a81336ede8b823Chris Craik } else { 455270dbafc72ebe758c904300983a81336ede8b823Chris Craik // expect to avoid cost of system.nanoTime on older platforms that don't do prefetch 456270dbafc72ebe758c904300983a81336ede8b823Chris Craik assertEquals(0, mRecyclerView.getNanoTime()); 457270dbafc72ebe758c904300983a81336ede8b823Chris Craik } 458270dbafc72ebe758c904300983a81336ede8b823Chris Craik } 459270dbafc72ebe758c904300983a81336ede8b823Chris Craik 4601e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik @Test 4611e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik public void findNestedRecyclerView() { 4621e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView recyclerView = new RecyclerView(getContext()); 4631e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(recyclerView)); 4641e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4651e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik ViewGroup parent = new FrameLayout(getContext()); 4661e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertEquals(null, RecyclerView.findNestedRecyclerView(parent)); 4671e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik parent.addView(recyclerView); 4681e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(parent)); 4691e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4701e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik ViewGroup grandParent = new FrameLayout(getContext()); 4711e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertEquals(null, RecyclerView.findNestedRecyclerView(grandParent)); 4721e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik grandParent.addView(parent); 4731e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(grandParent)); 4741e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik } 4751e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4761e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik @Test 4771e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik public void clearNestedRecyclerViewIfNotNested() { 4781e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView recyclerView = new RecyclerView(getContext()); 4791e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik ViewGroup parent = new FrameLayout(getContext()); 4801e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik parent.addView(recyclerView); 4811e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik ViewGroup grandParent = new FrameLayout(getContext()); 4821e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik grandParent.addView(parent); 4831e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4841e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik // verify trivial noop case 4851e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(recyclerView) {}; 4868123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craik holder.mNestedRecyclerView = new WeakReference<>(recyclerView); 4871e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView.clearNestedRecyclerViewIfNotNested(holder); 4888123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craik assertEquals(recyclerView, holder.mNestedRecyclerView.get()); 4891e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4901e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik // verify clear case 4911e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik holder = new RecyclerView.ViewHolder(new View(getContext())) {}; 4928123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craik holder.mNestedRecyclerView = new WeakReference<>(recyclerView); 4931e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView.clearNestedRecyclerViewIfNotNested(holder); 4941e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik assertNull(holder.mNestedRecyclerView); 4951e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 4961e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik // verify more deeply nested case 4971e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik holder = new RecyclerView.ViewHolder(grandParent) {}; 4988123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craik holder.mNestedRecyclerView = new WeakReference<>(recyclerView); 4991e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik RecyclerView.clearNestedRecyclerViewIfNotNested(holder); 5008123166eaf758eacc6ba5854c9b29d99f21388d6Chris Craik assertEquals(recyclerView, holder.mNestedRecyclerView.get()); 5011e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik } 5021e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik 503166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik @Test 504166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik public void exceptionContainsClasses() { 50531a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik RecyclerView first = new RecyclerView(getContext()); 50631a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik first.setLayoutManager(new LinearLayoutManager(getContext())); 50731a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik first.setAdapter(new MockAdapter(10)); 508166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik 50931a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik RecyclerView second = new RecyclerView(getContext()); 510166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik try { 51131a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik second.setLayoutManager(first.getLayoutManager()); 512166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik fail("exception expected"); 51331a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik } catch (IllegalArgumentException e) { 51431a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik // Note: exception contains first RV 51531a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik String m = e.getMessage(); 51631a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik assertTrue("must contain RV class", m.contains(RecyclerView.class.getName())); 51731a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik assertTrue("must contain Adapter class", m.contains(MockAdapter.class.getName())); 51831a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik assertTrue("must contain LM class", m.contains(LinearLayoutManager.class.getName())); 51931a68d5eadcea9ebc14e797f1f65d628b206ec50Chris Craik assertTrue("must contain ctx class", m.contains(getContext().getClass().getName())); 520166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik } 521166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik } 522166d5f1c4f2757966ff0ef167b6a2813e015b6a7Chris Craik 52350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky @Test 52450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky public void focusOrderTest() { 52550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky FocusOrderAdapter focusAdapter = new FocusOrderAdapter(getContext()); 52650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mRecyclerView.setAdapter(focusAdapter); 52750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 52850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky measure(); 52950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky layout(); 530396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard 531396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard boolean isIcsOrLower = Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1; 532396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard 533396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard // On API 15 and lower, focus forward get's translated to focus down. 534396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard View expected = isIcsOrLower ? focusAdapter.mBottomRight : focusAdapter.mBottomLeft; 535396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard assertEquals(expected, focusAdapter.mTopRight.focusSearch(View.FOCUS_FORWARD)); 536396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard 537396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard // On API 15 and lower, focus forward get's translated to focus down, which in this case 538396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard // runs out of the RecyclerView, thus returning null. 539396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard expected = isIcsOrLower ? null : focusAdapter.mBottomRight; 540396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard assertSame(expected, focusAdapter.mBottomLeft.focusSearch(View.FOCUS_FORWARD)); 541396f5b41fbfdd23adf2a99d3f4c8ddb0c907c41ashepshapard 54250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky // we don't want looping within RecyclerView 54350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky assertNull(focusAdapter.mBottomRight.focusSearch(View.FOCUS_FORWARD)); 54450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky assertNull(focusAdapter.mTopLeft.focusSearch(View.FOCUS_BACKWARD)); 54550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 54650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 547c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard @Test 548c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard public void setAdapter_callsCorrectLmMethods() throws Throwable { 549c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockLayoutManager mockLayoutManager = new MockLayoutManager(); 550c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockAdapter mockAdapter = new MockAdapter(1); 551c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.setLayoutManager(mockLayoutManager); 552c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 553c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.setAdapter(mockAdapter); 554c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard layout(); 555c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 556c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(1, mockLayoutManager.mAdapterChangedCount); 557c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(0, mockLayoutManager.mItemsChangedCount); 558c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard } 559c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 560c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard @Test 561c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard public void swapAdapter_callsCorrectLmMethods() throws Throwable { 562c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockLayoutManager mockLayoutManager = new MockLayoutManager(); 563c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockAdapter mockAdapter = new MockAdapter(1); 564c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.setLayoutManager(mockLayoutManager); 565c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 566c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.swapAdapter(mockAdapter, true); 567c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard layout(); 568c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 569c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(1, mockLayoutManager.mAdapterChangedCount); 570c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(1, mockLayoutManager.mItemsChangedCount); 571c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard } 572c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 573c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard @Test 574c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard public void notifyDataSetChanged_callsCorrectLmMethods() throws Throwable { 575c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockLayoutManager mockLayoutManager = new MockLayoutManager(); 576c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard MockAdapter mockAdapter = new MockAdapter(1); 577c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.setLayoutManager(mockLayoutManager); 578c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mRecyclerView.setAdapter(mockAdapter); 579c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mockLayoutManager.mAdapterChangedCount = 0; 580c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mockLayoutManager.mItemsChangedCount = 0; 581c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 582c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mockAdapter.notifyDataSetChanged(); 583c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard layout(); 584c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 585c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(0, mockLayoutManager.mAdapterChangedCount); 586c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard assertEquals(1, mockLayoutManager.mItemsChangedCount); 587c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard } 588c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 589c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar static class MockLayoutManager extends RecyclerView.LayoutManager { 590edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 591edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar int mLayoutCount = 0; 592edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 593edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar int mAdapterChangedCount = 0; 594c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard int mItemsChangedCount = 0; 595edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 596edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView.Adapter mPrevAdapter; 597edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 598edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView.Adapter mNextAdapter; 599edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 600c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar String mUuid = UUID.randomUUID().toString(); 601c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 602edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 603edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public void onAdapterChanged(RecyclerView.Adapter oldAdapter, 604edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView.Adapter newAdapter) { 605edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar super.onAdapterChanged(oldAdapter, newAdapter); 606edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mPrevAdapter = oldAdapter; 607edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mNextAdapter = newAdapter; 608edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mAdapterChangedCount++; 609edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 610edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 611edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 612c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard public void onItemsChanged(RecyclerView recyclerView) { 613c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard mItemsChangedCount++; 614c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard } 615c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard 616c6257630a384dd28b8670011806d8f4f2fcd5840shepshapard @Override 617d4a794983364c7b1801638abc7f332abee12b6e6Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 618edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar mLayoutCount += 1; 619edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 620edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 621edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 622c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public Parcelable onSaveInstanceState() { 623c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar LayoutManagerSavedState lss = new LayoutManagerSavedState(); 624c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar lss.mUuid = mUuid; 625c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar return lss; 626c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 627c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 628c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 629c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public void onRestoreInstanceState(Parcelable state) { 630c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar super.onRestoreInstanceState(state); 631c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar if (state instanceof LayoutManagerSavedState) { 632c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mUuid = ((LayoutManagerSavedState) state).mUuid; 633c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 634c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 635c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 636c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 637edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 638edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 639edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 640edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 641edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 642edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public void assertPrevNextAdapters(String message, RecyclerView.Adapter prevAdapter, 643edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView.Adapter nextAdapter) { 644edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertSame(message, prevAdapter, mPrevAdapter); 645edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertSame(message, nextAdapter, mNextAdapter); 646edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 647edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 648edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public void assertPrevNextAdapters(RecyclerView.Adapter prevAdapter, 649edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar RecyclerView.Adapter nextAdapter) { 650edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar assertPrevNextAdapters("Adapters from onAdapterChanged callback should match", 651edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar prevAdapter, nextAdapter); 652edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 653bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 654bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 655bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 656bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView.State state) { 657bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar return dx; 658bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 659bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 660bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 661bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 662bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar RecyclerView.State state) { 663bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar return dy; 664bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 665bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 666bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 667bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public boolean canScrollHorizontally() { 668bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar return true; 669bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 670bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar 671bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar @Override 672bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar public boolean canScrollVertically() { 673bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar return true; 674bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar } 675edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 676edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 677c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar static class LayoutManagerSavedState implements Parcelable { 678c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 679c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar String mUuid; 680c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 681c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public LayoutManagerSavedState(Parcel in) { 682c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar mUuid = in.readString(); 683c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 684c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 685c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public LayoutManagerSavedState() { 686c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 687c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 688c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 689c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 690c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public int describeContents() { 691c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar return 0; 692c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 693c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 694c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 695c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public void writeToParcel(Parcel dest, int flags) { 696c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar dest.writeString(mUuid); 697c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 698c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 699c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public static final Parcelable.Creator<LayoutManagerSavedState> CREATOR 700c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar = new Parcelable.Creator<LayoutManagerSavedState>() { 701c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 702c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public LayoutManagerSavedState createFromParcel(Parcel in) { 703c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar return new LayoutManagerSavedState(in); 704c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 705c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 706c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar @Override 707c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar public LayoutManagerSavedState[] newArray(int size) { 708c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar return new LayoutManagerSavedState[size]; 709c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 710c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar }; 711c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar } 712c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar 713c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar static class MockAdapter extends RecyclerView.Adapter { 714edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 715edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar private int mCount = 0; 716edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 717d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 718c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar MockAdapter(int count) { 719edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar this.mCount = count; 720edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 721edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 7228a11e6829c522aa1efcc903afa4c01d337082eabChris Craik @NonNull 723edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 7248a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 725edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar return new MockViewHolder(new TextView(parent.getContext())); 726edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 727edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 728edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 7298a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 730edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 731edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 732edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 733edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar @Override 734edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public int getItemCount() { 735edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar return mCount; 736edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 737d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 738d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase void removeItems(int start, int count) { 739d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase mCount -= count; 740d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase notifyItemRangeRemoved(start, count); 741d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 742d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase 743d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase void addItems(int start, int count) { 744d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase mCount += count; 745d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase notifyItemRangeInserted(start, count); 746d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase } 747edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 748edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar 749c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar static class MockViewHolder extends RecyclerView.ViewHolder { 750115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar public Object mItem; 751edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar public MockViewHolder(View itemView) { 752edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar super(itemView); 753edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 754edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar } 755ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 756ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar static class LoggingView extends TextView { 757ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar private int mOnSavedInstanceCnt = 0; 758ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 759ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public LoggingView(Context context) { 760ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar super(context); 761ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 762ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 763ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public LoggingView(Context context, AttributeSet attrs) { 764ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar super(context, attrs); 765ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 766ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 767ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public LoggingView(Context context, AttributeSet attrs, int defStyleAttr) { 768ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar super(context, attrs, defStyleAttr); 769ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 770ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 771ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar @Override 772ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public Parcelable onSaveInstanceState() { 773ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar mOnSavedInstanceCnt ++; 774ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar return super.onSaveInstanceState(); 775ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 776ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar 777ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar public int getOnSavedInstanceCnt() { 778ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar return mOnSavedInstanceCnt; 779ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 780ca570ddc976f20eae6dcc40bed9f6dee0e749353Yigit Boyar } 78150f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 78250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky static class FocusOrderAdapter extends RecyclerView.Adapter { 78350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky TextView mTopLeft; 78450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky TextView mTopRight; 78550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky TextView mBottomLeft; 78650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky TextView mBottomRight; 78750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 78850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky FocusOrderAdapter(Context context) { 78950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mTopLeft = new TextView(context); 79050f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mTopRight = new TextView(context); 79150f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mBottomLeft = new TextView(context); 79250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mBottomRight = new TextView(context); 79350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky for (TextView tv : new TextView[]{mTopLeft, mTopRight, mBottomLeft, mBottomRight}) { 79450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky tv.setFocusableInTouchMode(true); 79550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky tv.setLayoutParams(new LinearLayout.LayoutParams(100, 100)); 79650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 79750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky // create a scenario where the "first" focusable is to the right of the last one 79850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mTopLeft.setFocusable(false); 79950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mTopRight.getLayoutParams().width = 101; 80050f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky mTopLeft.getLayoutParams().width = 101; 80150f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 80250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 80350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky @Override 8048a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 80550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky LinearLayout holder = new LinearLayout(parent.getContext()); 80650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky holder.setOrientation(LinearLayout.HORIZONTAL); 80750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky return new MockViewHolder(holder); 80850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 80950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 81050f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky @Override 8118a11e6829c522aa1efcc903afa4c01d337082eabChris Craik public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { 81250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky LinearLayout l = (LinearLayout) holder.itemView; 81350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky l.removeAllViews(); 81450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky if (position == 0) { 81550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky l.addView(mTopLeft); 81650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky l.addView(mTopRight); 81750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } else { 81850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky l.addView(mBottomLeft); 81950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky l.addView(mBottomRight); 82050f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 82150f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 82250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 82350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky @Override 82450f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky public int getItemCount() { 82550f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky return 2; 82650f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 82750f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 82850f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky void removeItems(int start, int count) { 82950f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 83050f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky 83150f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky void addItems(int start, int count) { 83250f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 83350f048ddcd71fbb313f0673336920113cad28ee8Evan Rosky } 834bf3e1bfa77a11365778fade25697acde1a70800aChris Craik} 835