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