1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v7.widget; 18 19import android.support.v4.view.AccessibilityDelegateCompat; 20import android.support.v4.view.accessibility.AccessibilityEventCompat; 21import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 22import android.support.v4.view.accessibility.AccessibilityRecordCompat; 23import android.view.View; 24import android.view.accessibility.AccessibilityEvent; 25 26import java.util.concurrent.atomic.AtomicBoolean; 27 28public class RecyclerViewAccessibilityTest extends BaseRecyclerViewInstrumentationTest { 29 public void testOnInitializeAccessibilityNodeInfo() throws Throwable { 30 for (boolean vBefore : new boolean[]{true, false}) { 31 for (boolean vAfter : new boolean[]{true, false}) { 32 for (boolean hBefore : new boolean[]{true, false}) { 33 for (boolean hAfter : new boolean[]{true, false}) { 34 onInitializeAccessibilityNodeInfoTest(vBefore, hBefore, 35 vAfter, hAfter); 36 removeRecyclerView(); 37 } 38 } 39 } 40 } 41 } 42 public void onInitializeAccessibilityNodeInfoTest(final boolean verticalScrollBefore, 43 final boolean horizontalScrollBefore, final boolean verticalScrollAfter, 44 final boolean horizontalScrollAfter) throws Throwable { 45 final RecyclerView recyclerView = new RecyclerView(getActivity()) { 46 //@Override 47 public boolean canScrollHorizontally(int direction) { 48 return direction < 0 && horizontalScrollBefore || 49 direction > 0 && horizontalScrollAfter; 50 } 51 52 //@Override 53 public boolean canScrollVertically(int direction) { 54 return direction < 0 && verticalScrollBefore || 55 direction > 0 && verticalScrollAfter; 56 } 57 }; 58 final TestAdapter adapter = new TestAdapter(10); 59 final AtomicBoolean hScrolledBack = new AtomicBoolean(false); 60 final AtomicBoolean vScrolledBack = new AtomicBoolean(false); 61 final AtomicBoolean hScrolledFwd = new AtomicBoolean(false); 62 final AtomicBoolean vScrolledFwd = new AtomicBoolean(false); 63 recyclerView.setAdapter(adapter); 64 recyclerView.setLayoutManager(new TestLayoutManager() { 65 66 @Override 67 public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 68 layoutRange(recycler, 0, 5); 69 } 70 71 @Override 72 public RecyclerView.LayoutParams generateDefaultLayoutParams() { 73 return new RecyclerView.LayoutParams(-1, -1); 74 } 75 76 @Override 77 public boolean canScrollVertically() { 78 return verticalScrollAfter || verticalScrollBefore; 79 } 80 81 @Override 82 public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 83 RecyclerView.State state) { 84 if (dx > 0) { 85 hScrolledFwd.set(true); 86 } else if (dx < 0) { 87 hScrolledBack.set(true); 88 } 89 return 0; 90 } 91 92 @Override 93 public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 94 RecyclerView.State state) { 95 if (dy > 0) { 96 vScrolledFwd.set(true); 97 } else if (dy < 0) { 98 vScrolledBack.set(true); 99 } 100 return 0; 101 } 102 103 @Override 104 public boolean canScrollHorizontally() { 105 return horizontalScrollAfter || horizontalScrollBefore; 106 } 107 }); 108 setRecyclerView(recyclerView); 109 final RecyclerViewAccessibilityDelegate delegateCompat = recyclerView 110 .getCompatAccessibilityDelegate(); 111 final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 112 runTestOnUiThread(new Runnable() { 113 @Override 114 public void run() { 115 delegateCompat.onInitializeAccessibilityNodeInfo(recyclerView, info); 116 } 117 }); 118 assertEquals(horizontalScrollAfter || horizontalScrollBefore 119 || verticalScrollAfter || verticalScrollBefore, info.isScrollable()); 120 assertEquals(horizontalScrollBefore || verticalScrollBefore, 121 (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) != 0); 122 assertEquals(horizontalScrollAfter || verticalScrollAfter, 123 (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) != 0); 124 final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info 125 .getCollectionInfo(); 126 assertNotNull(collectionInfo); 127 if (recyclerView.getLayoutManager().canScrollVertically()) { 128 assertEquals(adapter.getItemCount(), collectionInfo.getRowCount()); 129 } 130 if (recyclerView.getLayoutManager().canScrollHorizontally()) { 131 assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount()); 132 } 133 134 final AccessibilityEvent event = AccessibilityEvent.obtain(); 135 runTestOnUiThread(new Runnable() { 136 @Override 137 public void run() { 138 delegateCompat.onInitializeAccessibilityEvent(recyclerView, event); 139 } 140 }); 141 final AccessibilityRecordCompat record = AccessibilityEventCompat 142 .asRecord(event); 143 assertEquals(record.isScrollable(), verticalScrollAfter || horizontalScrollAfter || 144 verticalScrollBefore || horizontalScrollBefore); 145 assertEquals(record.getItemCount(), adapter.getItemCount()); 146 147 getInstrumentation().waitForIdleSync(); 148 for (int i = 0; i < mRecyclerView.getChildCount(); i ++) { 149 final View view = mRecyclerView.getChildAt(i); 150 final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain(); 151 runTestOnUiThread(new Runnable() { 152 @Override 153 public void run() { 154 delegateCompat.getItemDelegate(). 155 onInitializeAccessibilityNodeInfo(view, childInfo); 156 } 157 }); 158 final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo 159 = childInfo.getCollectionItemInfo(); 160 assertNotNull(collectionItemInfo); 161 if (recyclerView.getLayoutManager().canScrollHorizontally()) { 162 assertEquals(i, collectionItemInfo.getColumnIndex()); 163 } else { 164 assertEquals(0, collectionItemInfo.getColumnIndex()); 165 } 166 167 if (recyclerView.getLayoutManager().canScrollVertically()) { 168 assertEquals(i, collectionItemInfo.getRowIndex()); 169 } else { 170 assertEquals(0, collectionItemInfo.getRowIndex()); 171 } 172 } 173 174 runTestOnUiThread(new Runnable() { 175 @Override 176 public void run() { 177 178 } 179 }); 180 hScrolledBack.set(false); 181 vScrolledBack.set(false); 182 hScrolledFwd.set(false); 183 vScrolledBack.set(false); 184 performAccessibilityAction(delegateCompat, recyclerView, 185 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); 186 assertEquals(horizontalScrollBefore, hScrolledBack.get()); 187 assertEquals(verticalScrollBefore, vScrolledBack.get()); 188 assertEquals(false, hScrolledFwd.get()); 189 assertEquals(false, vScrolledFwd.get()); 190 191 hScrolledBack.set(false); 192 vScrolledBack.set(false); 193 hScrolledFwd.set(false); 194 vScrolledBack.set(false); 195 performAccessibilityAction(delegateCompat, recyclerView, 196 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); 197 assertEquals(false, hScrolledBack.get()); 198 assertEquals(false, vScrolledBack.get()); 199 assertEquals(horizontalScrollAfter, hScrolledFwd.get()); 200 assertEquals(verticalScrollAfter, vScrolledFwd.get()); 201 } 202 203 void performAccessibilityAction(final AccessibilityDelegateCompat delegate, 204 final RecyclerView recyclerView, final int action) throws Throwable { 205 runTestOnUiThread(new Runnable() { 206 @Override 207 public void run() { 208 delegate.performAccessibilityAction(recyclerView, action, null); 209 } 210 }); 211 getInstrumentation().waitForIdleSync(); 212 Thread.sleep(250); 213 } 214} 215