1a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 3a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * 4a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * you may not use this file except in compliance with the License. 6a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * You may obtain a copy of the License at 7a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * 8a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * 10a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * Unless required by applicable law or agreed to in writing, software 11a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * See the License for the specific language governing permissions and 14a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * limitations under the License. 15a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar */ 16a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget; 18a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 19e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertEquals; 20e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertFalse; 21e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertNotNull; 22e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport static org.junit.Assert.assertTrue; 230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 24f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyarimport android.os.Build; 25754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest; 26a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.View; 27a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent; 28a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 29c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.core.view.AccessibilityDelegateCompat; 30c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat; 31c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas 32e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.Test; 33e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runner.RunWith; 34e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikasimport org.junit.runners.Parameterized; 35e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas 360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.ArrayList; 370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport java.util.List; 38a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport java.util.concurrent.atomic.AtomicBoolean; 39a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 40f1b288ec2104488f4a92e911b0ab80c8f0f3e9d1Yigit Boyar@MediumTest 410a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(Parameterized.class) 42a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarpublic class RecyclerViewAccessibilityTest extends BaseRecyclerViewInstrumentationTest { 43f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar private static final boolean SUPPORTS_COLLECTION_INFO = 44f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 45f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar private final boolean mVerticalScrollBefore; 46f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar private final boolean mHorizontalScrollBefore; 47f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar private final boolean mVerticalScrollAfter; 48f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar private final boolean mHorizontalScrollAfter; 490a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar 500a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public RecyclerViewAccessibilityTest(boolean verticalScrollBefore, 510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean horizontalScrollBefore, boolean verticalScrollAfter, 520a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar boolean horizontalScrollAfter) { 53f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar mVerticalScrollBefore = verticalScrollBefore; 54f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar mHorizontalScrollBefore = horizontalScrollBefore; 55f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar mVerticalScrollAfter = verticalScrollAfter; 56f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar mHorizontalScrollAfter = horizontalScrollAfter; 57da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 58da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 59e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas @Parameterized.Parameters(name = "vBefore={0},vAfter={1},hBefore={2},hAfter={3}") 600a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public static List<Object[]> getParams() { 610a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar List<Object[]> params = new ArrayList<>(); 62a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar for (boolean vBefore : new boolean[]{true, false}) { 63a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar for (boolean vAfter : new boolean[]{true, false}) { 64a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar for (boolean hBefore : new boolean[]{true, false}) { 65a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar for (boolean hAfter : new boolean[]{true, false}) { 660a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar params.add(new Object[]{vBefore, hBefore, vAfter, hAfter}); 67a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 68a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 69a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 70a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 710a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar return params; 72a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 73da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 740a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 750a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void onInitializeAccessibilityNodeInfoTest() throws Throwable { 76a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()) { 77e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 78a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public boolean canScrollHorizontally(int direction) { 79f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar return direction < 0 && mHorizontalScrollBefore || 80f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar direction > 0 && mHorizontalScrollAfter; 81a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 82a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 83e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 84a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public boolean canScrollVertically(int direction) { 85f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar return direction < 0 && mVerticalScrollBefore || 86f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar direction > 0 && mVerticalScrollAfter; 87a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 88a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }; 89a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final TestAdapter adapter = new TestAdapter(10); 90a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AtomicBoolean hScrolledBack = new AtomicBoolean(false); 91a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AtomicBoolean vScrolledBack = new AtomicBoolean(false); 92a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AtomicBoolean hScrolledFwd = new AtomicBoolean(false); 93a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AtomicBoolean vScrolledFwd = new AtomicBoolean(false); 94a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar recyclerView.setAdapter(adapter); 95a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar recyclerView.setLayoutManager(new TestLayoutManager() { 96a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 97a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 98a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 99a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar layoutRange(recycler, 0, 5); 100a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 101a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 102a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 103a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 104a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return new RecyclerView.LayoutParams(-1, -1); 105a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 106a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 107a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 108a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public boolean canScrollVertically() { 109f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar return mVerticalScrollAfter || mVerticalScrollBefore; 110a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 111a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 112a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 113a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 114a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 115a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (dx > 0) { 116a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledFwd.set(true); 117a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else if (dx < 0) { 118a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledBack.set(true); 119a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 0; 121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 126a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (dy > 0) { 127a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledFwd.set(true); 128a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else if (dy < 0) { 129a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledBack.set(true); 130a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 131a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 0; 132a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 133a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 134a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 135a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public boolean canScrollHorizontally() { 136f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar return mHorizontalScrollAfter || mHorizontalScrollBefore; 137a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 138a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 139a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar setRecyclerView(recyclerView); 140a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final RecyclerViewAccessibilityDelegate delegateCompat = recyclerView 141a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .getCompatAccessibilityDelegate(); 142a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 14342e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 144a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 145a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 146a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(recyclerView, info); 147a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 148a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 149f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mHorizontalScrollAfter || mHorizontalScrollBefore 150f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar || mVerticalScrollAfter || mVerticalScrollBefore, info.isScrollable()); 151f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mHorizontalScrollBefore || mVerticalScrollBefore, 152a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) != 0); 153f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mHorizontalScrollAfter || mVerticalScrollAfter, 154a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) != 0); 155f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (SUPPORTS_COLLECTION_INFO) { 156f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info 157f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar .getCollectionInfo(); 158f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertNotNull(collectionInfo); 159f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (recyclerView.getLayoutManager().canScrollVertically()) { 160f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(adapter.getItemCount(), collectionInfo.getRowCount()); 161f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } 162f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (recyclerView.getLayoutManager().canScrollHorizontally()) { 163f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount()); 164f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } 165a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 166a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 167a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityEvent event = AccessibilityEvent.obtain(); 16842e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 169a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 170a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 171a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar delegateCompat.onInitializeAccessibilityEvent(recyclerView, event); 172a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 173a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 17414d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas assertEquals(event.isScrollable(), mVerticalScrollAfter || mHorizontalScrollAfter 17514d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas || mVerticalScrollBefore || mHorizontalScrollBefore); 17614d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas assertEquals(event.getItemCount(), adapter.getItemCount()); 177a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 178a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar getInstrumentation().waitForIdleSync(); 179f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (SUPPORTS_COLLECTION_INFO) { 180f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar for (int i = 0; i < mRecyclerView.getChildCount(); i++) { 181f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar final View view = mRecyclerView.getChildAt(i); 182f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain(); 18342e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 184f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar @Override 185f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar public void run() { 186f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar delegateCompat.getItemDelegate(). 187f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar onInitializeAccessibilityNodeInfo(view, childInfo); 188f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } 189f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar }); 190f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo 191f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar = childInfo.getCollectionItemInfo(); 192f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertNotNull(collectionItemInfo); 193f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (recyclerView.getLayoutManager().canScrollHorizontally()) { 194f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(i, collectionItemInfo.getColumnIndex()); 195f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } else { 196f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(0, collectionItemInfo.getColumnIndex()); 197a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 198a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 199f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar if (recyclerView.getLayoutManager().canScrollVertically()) { 200f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(i, collectionItemInfo.getRowIndex()); 201f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } else { 202f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(0, collectionItemInfo.getRowIndex()); 203f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar } 204a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 205a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 206a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 20742e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 208a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 209a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 210a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 211a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 212a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 213a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledBack.set(false); 214a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledBack.set(false); 215a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledFwd.set(false); 216a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledBack.set(false); 217a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar performAccessibilityAction(delegateCompat, recyclerView, 218a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 219f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mHorizontalScrollBefore, hScrolledBack.get()); 220f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mVerticalScrollBefore, vScrolledBack.get()); 221a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(false, hScrolledFwd.get()); 222a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(false, vScrolledFwd.get()); 223a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 224a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledBack.set(false); 225a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledBack.set(false); 226a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar hScrolledFwd.set(false); 227a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar vScrolledBack.set(false); 228a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar performAccessibilityAction(delegateCompat, recyclerView, 229a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 230a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(false, hScrolledBack.get()); 231a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar assertEquals(false, vScrolledBack.get()); 232f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mHorizontalScrollAfter, hScrolledFwd.get()); 233f4af710ed07f1b8f61d1293005dee7b8f24fa612Yigit Boyar assertEquals(mVerticalScrollAfter, vScrolledFwd.get()); 234a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 235a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 2360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar @Test 2370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar public void ignoreAccessibilityIfAdapterHasChanged() throws Throwable { 238da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final RecyclerView recyclerView = new RecyclerView(getActivity()) { 239da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar //@Override 240e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 241da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public boolean canScrollHorizontally(int direction) { 242da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar return true; 243da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 244da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 245da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar //@Override 246e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 247da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public boolean canScrollVertically(int direction) { 248da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar return true; 249da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 250da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }; 251da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final DumbLayoutManager layoutManager = new DumbLayoutManager(); 252da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final TestAdapter adapter = new TestAdapter(10); 253da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setAdapter(adapter); 254da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar recyclerView.setLayoutManager(layoutManager); 255da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar layoutManager.expectLayouts(1); 256da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar setRecyclerView(recyclerView); 257da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar layoutManager.waitForLayout(1); 258da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 259da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final RecyclerViewAccessibilityDelegate delegateCompat = recyclerView 260da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar .getCompatAccessibilityDelegate(); 261da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 26242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 263da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar @Override 264da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar public void run() { 265da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(recyclerView, info); 266da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 267da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar }); 268da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar assertTrue("test sanity", info.isScrollable()); 269da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final AccessibilityNodeInfoCompat info2 = AccessibilityNodeInfoCompat.obtain(); 27042e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 27166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar @Override 27266826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar public void run() { 27366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar try { 27466826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar adapter.deleteAndNotify(1, 1); 27566826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar } catch (Throwable throwable) { 27666826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar postExceptionToInstrumentation(throwable); 27766826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar } 27866826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar delegateCompat.onInitializeAccessibilityNodeInfo(recyclerView, info2); 27966826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar assertFalse("info should not be filled if data is out of date", 28066826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar info2.isScrollable()); 28166826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar } 28266826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar }); 28366826566020afc8d11f183cf3fe443ac0a022384Yigit Boyar checkForMainThreadException(); 284da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar } 285da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar 286da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar boolean performAccessibilityAction(final AccessibilityDelegateCompat delegate, 2870a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar final RecyclerView recyclerView, final int action) throws Throwable { 288da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar final boolean[] result = new boolean[1]; 28942e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas mActivityRule.runOnUiThread(new Runnable() { 290a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 291a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void run() { 292da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar result[0] = delegate.performAccessibilityAction(recyclerView, action, null); 293a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 294a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar }); 295a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar getInstrumentation().waitForIdleSync(); 296a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar Thread.sleep(250); 297da50fde358bd3ef2edb273b3bf0265cf5e84ec6bYigit Boyar return result[0]; 298a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 299a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar} 300