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