LinkAccessibilityHelperTest.java revision d60659421446329c7a7af2a009a51413d5388254
1/* 2 * Copyright (C) 2016 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 com.android.setupwizardlib.test; 18 19import static org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertTrue; 21 22import android.graphics.Rect; 23import android.os.Bundle; 24import android.support.test.InstrumentationRegistry; 25import android.support.test.filters.SmallTest; 26import android.support.test.runner.AndroidJUnit4; 27import android.support.v4.text.BidiFormatter; 28import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 29import android.support.v4.widget.ExploreByTouchHelper; 30import android.text.SpannableStringBuilder; 31import android.util.DisplayMetrics; 32import android.util.TypedValue; 33import android.view.View; 34import android.view.accessibility.AccessibilityEvent; 35import android.widget.TextView; 36 37import com.android.setupwizardlib.span.LinkSpan; 38import com.android.setupwizardlib.util.LinkAccessibilityHelper; 39 40import org.junit.Test; 41import org.junit.runner.RunWith; 42 43import java.util.ArrayList; 44import java.util.Collections; 45import java.util.List; 46 47@RunWith(AndroidJUnit4.class) 48@SmallTest 49public class LinkAccessibilityHelperTest { 50 51 private static final LinkSpan LINK_SPAN = new LinkSpan("foobar"); 52 53 private TextView mTextView; 54 private TestLinkAccessibilityHelper mHelper; 55 56 private DisplayMetrics mDisplayMetrics; 57 58 @Test 59 public void testGetVirtualViewAt() { 60 initTextView(); 61 final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10)); 62 assertEquals("Virtual view ID should be 1", 1, virtualViewId); 63 } 64 65 @Test 66 public void testGetVirtualViewAtHost() { 67 initTextView(); 68 final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100)); 69 assertEquals("Virtual view ID should be INVALID_ID", 70 ExploreByTouchHelper.INVALID_ID, virtualViewId); 71 } 72 73 @Test 74 public void testGetVisibleVirtualViews() { 75 initTextView(); 76 List<Integer> virtualViewIds = new ArrayList<>(); 77 mHelper.getVisibleVirtualViews(virtualViewIds); 78 79 assertEquals("VisibleVirtualViews should be [1]", 80 Collections.singletonList(1), virtualViewIds); 81 } 82 83 @Test 84 public void testOnPopulateEventForVirtualView() { 85 initTextView(); 86 AccessibilityEvent event = AccessibilityEvent.obtain(); 87 mHelper.onPopulateEventForVirtualView(1, event); 88 89 // LinkSpan is set on substring(1, 2) of "Hello world" --> "e" 90 assertEquals("LinkSpan description should be \"e\"", 91 "e", event.getContentDescription().toString()); 92 93 event.recycle(); 94 } 95 96 @Test 97 public void testOnPopulateEventForVirtualViewHost() { 98 initTextView(); 99 AccessibilityEvent event = AccessibilityEvent.obtain(); 100 mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event); 101 102 assertEquals("Host view description should be \"Hello world\"", "Hello world", 103 event.getContentDescription().toString()); 104 105 event.recycle(); 106 } 107 108 @Test 109 public void testOnPopulateNodeForVirtualView() { 110 initTextView(); 111 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 112 mHelper.onPopulateNodeForVirtualView(1, info); 113 114 assertEquals("LinkSpan description should be \"e\"", 115 "e", info.getContentDescription().toString()); 116 assertTrue("LinkSpan should be focusable", info.isFocusable()); 117 assertTrue("LinkSpan should be clickable", info.isClickable()); 118 Rect bounds = new Rect(); 119 info.getBoundsInParent(bounds); 120 assertEquals("LinkSpan bounds should be (10.5dp, 0dp, 18.5dp, 20.5dp)", 121 new Rect(dp2Px(10.5f), dp2Px(0f), dp2Px(18.5f), dp2Px(20.5f)), bounds); 122 123 info.recycle(); 124 } 125 126 @Test 127 public void testNullLayout() { 128 initTextView(); 129 // Setting the padding will cause the layout to be null-ed out. 130 mTextView.setPadding(1, 1, 1, 1); 131 132 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 133 mHelper.onPopulateNodeForVirtualView(0, info); 134 135 Rect bounds = new Rect(); 136 info.getBoundsInParent(bounds); 137 assertEquals("LinkSpan bounds should be (0, 0, 1, 1)", 138 new Rect(0, 0, 1, 1), bounds); 139 140 info.recycle(); 141 } 142 143 @Test 144 public void testRtlLayout() { 145 SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום"); 146 ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); 147 initTextView(ssb); 148 149 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 150 mHelper.onPopulateNodeForVirtualView(1, info); 151 152 assertEquals("LinkSpan description should be \"כ\"", 153 "כ", info.getContentDescription().toString()); 154 Rect bounds = new Rect(); 155 info.getBoundsInParent(bounds); 156 assertEquals("LinkSpan bounds should be (481.5dp, 0dp, 489.5dp, 20.5dp)", 157 new Rect(dp2Px(481.5f), dp2Px(0f), dp2Px(489.5f), dp2Px(20.5f)), bounds); 158 159 info.recycle(); 160 } 161 162 @Test 163 public void testMultilineLink() { 164 SpannableStringBuilder ssb = new SpannableStringBuilder( 165 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " 166 + "Praesent accumsan efficitur eros eu porttitor."); 167 ssb.setSpan(LINK_SPAN, 51, 74, 0 /* flags */); 168 initTextView(ssb); 169 170 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 171 mHelper.onPopulateNodeForVirtualView(51, info); 172 173 assertEquals("LinkSpan description should match the span", 174 "elit. Praesent accumsan", info.getContentDescription().toString()); 175 Rect bounds = new Rect(); 176 info.getBoundsInParent(bounds); 177 assertEquals("LinkSpan bounds should match first line of the span", 178 new Rect(dp2Px(343f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds); 179 180 info.recycle(); 181 } 182 183 @Test 184 public void testRtlMultilineLink() { 185 String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " 186 + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " 187 + "דפים המחשב מיזמים ב."; 188 SpannableStringBuilder ssb = new SpannableStringBuilder(iwLoremIpsum); 189 ssb.setSpan(LINK_SPAN, 50, 100, 0 /* flags */); 190 initTextView(ssb); 191 192 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 193 mHelper.onPopulateNodeForVirtualView(50, info); 194 195 assertEquals("LinkSpan description should match the span", 196 iwLoremIpsum.substring(50, 100), 197 info.getContentDescription().toString()); 198 Rect bounds = new Rect(); 199 info.getBoundsInParent(bounds); 200 assertEquals("LinkSpan bounds should match the first line of the span", 201 new Rect(dp2Px(0f), dp2Px(0f), dp2Px(150f), dp2Px(19.5f)), bounds); 202 203 info.recycle(); 204 } 205 206 @Test 207 public void testBidiMultilineLink() { 208 String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים " 209 + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד " 210 + "דפים המחשב מיזמים ב."; 211 BidiFormatter formatter = BidiFormatter.getInstance(false /* rtlContext */); 212 SpannableStringBuilder ssb = new SpannableStringBuilder(); 213 ssb.append("hello ").append(formatter.unicodeWrap(iwLoremIpsum)).append(" world"); 214 ssb.setSpan(LINK_SPAN, 215 "hello ".length() + 2, // Add two for the characters added by BidiFormatter 216 "hello ".length() + 2 + iwLoremIpsum.length(), 217 0 /* flags */); 218 initTextView(ssb); 219 220 AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); 221 mHelper.onPopulateNodeForVirtualView("hello ".length() + 2, info); 222 223 assertEquals("LinkSpan description should match the span", 224 iwLoremIpsum, 225 info.getContentDescription().toString()); 226 Rect bounds = new Rect(); 227 info.getBoundsInParent(bounds); 228 assertEquals("LinkSpan bounds should match the first line of the span", 229 new Rect(dp2Px(491.5f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds); 230 231 info.recycle(); 232 } 233 234 private void initTextView() { 235 SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); 236 ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */); 237 initTextView(ssb); 238 } 239 240 private void initTextView(CharSequence text) { 241 mTextView = new TextView(InstrumentationRegistry.getContext()); 242 mTextView.setSingleLine(false); 243 mTextView.setText(text); 244 mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); 245 mHelper = new TestLinkAccessibilityHelper(mTextView); 246 247 int measureExactly500dp = View.MeasureSpec.makeMeasureSpec(dp2Px(500), 248 View.MeasureSpec.EXACTLY); 249 mTextView.measure(measureExactly500dp, measureExactly500dp); 250 mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500)); 251 } 252 253 private int dp2Px(float dp) { 254 if (mDisplayMetrics == null) { 255 mDisplayMetrics = 256 InstrumentationRegistry.getContext().getResources().getDisplayMetrics(); 257 } 258 return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics); 259 } 260 261 private static class TestLinkAccessibilityHelper extends LinkAccessibilityHelper { 262 263 TestLinkAccessibilityHelper(TextView view) { 264 super(view); 265 } 266 267 @Override 268 public int getVirtualViewAt(float x, float y) { 269 return super.getVirtualViewAt(x, y); 270 } 271 272 @Override 273 public void getVisibleVirtualViews(List<Integer> virtualViewIds) { 274 super.getVisibleVirtualViews(virtualViewIds); 275 } 276 277 @Override 278 public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 279 super.onPopulateEventForVirtualView(virtualViewId, event); 280 } 281 282 @Override 283 public void onPopulateNodeForVirtualView(int virtualViewId, 284 AccessibilityNodeInfoCompat info) { 285 super.onPopulateNodeForVirtualView(virtualViewId, info); 286 } 287 288 @Override 289 public boolean onPerformActionForVirtualView(int virtualViewId, int action, 290 Bundle arguments) { 291 return super.onPerformActionForVirtualView(virtualViewId, action, arguments); 292 } 293 } 294} 295