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 android.graphics.Rect;
20import android.os.Bundle;
21import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
22import android.support.v4.widget.ExploreByTouchHelper;
23import android.test.AndroidTestCase;
24import android.test.suitebuilder.annotation.SmallTest;
25import android.text.SpannableStringBuilder;
26import android.util.DisplayMetrics;
27import android.util.TypedValue;
28import android.view.accessibility.AccessibilityEvent;
29import android.widget.TextView;
30
31import com.android.setupwizardlib.span.LinkSpan;
32import com.android.setupwizardlib.util.LinkAccessibilityHelper;
33
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.List;
37
38public class LinkAccessibilityHelperTest extends AndroidTestCase {
39
40    private TextView mTextView;
41    private TestLinkAccessibilityHelper mHelper;
42    private LinkSpan mSpan;
43
44    private DisplayMetrics mDisplayMetrics;
45
46    @Override
47    protected void setUp() throws Exception {
48        super.setUp();
49        mSpan = new LinkSpan("foobar");
50        SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
51        ssb.setSpan(mSpan, 1, 2, 0 /* flags */);
52
53        mTextView = new TextView(getContext());
54        mTextView.setText(ssb);
55        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
56        mHelper = new TestLinkAccessibilityHelper(mTextView);
57
58        mTextView.measure(dp2Px(500), dp2Px(500));
59        mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500));
60    }
61
62    @SmallTest
63    public void testGetVirtualViewAt() {
64        final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10));
65        assertEquals("Virtual view ID should be 1", 1, virtualViewId);
66    }
67
68    @SmallTest
69    public void testGetVirtualViewAtHost() {
70        final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100));
71        assertEquals("Virtual view ID should be INVALID_ID",
72                ExploreByTouchHelper.INVALID_ID, virtualViewId);
73    }
74
75    @SmallTest
76    public void testGetVisibleVirtualViews() {
77        List<Integer> virtualViewIds = new ArrayList<>();
78        mHelper.getVisibleVirtualViews(virtualViewIds);
79
80        assertEquals("VisibleVirtualViews should be [1]",
81                Collections.singletonList(1), virtualViewIds);
82    }
83
84    @SmallTest
85    public void testOnPopulateEventForVirtualView() {
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    @SmallTest
97    public void testOnPopulateEventForVirtualViewHost() {
98        AccessibilityEvent event = AccessibilityEvent.obtain();
99        mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event);
100
101        assertEquals("Host view description should be \"Hello world\"", "Hello world",
102                event.getContentDescription().toString());
103
104        event.recycle();
105    }
106
107    @SmallTest
108    public void testOnPopulateNodeForVirtualView() {
109        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
110        mHelper.onPopulateNodeForVirtualView(1, info);
111
112        assertEquals("LinkSpan description should be \"e\"",
113                "e", info.getContentDescription().toString());
114        assertTrue("LinkSpan should be focusable", info.isFocusable());
115        assertTrue("LinkSpan should be clickable", info.isClickable());
116        Rect bounds = new Rect();
117        info.getBoundsInParent(bounds);
118        assertEquals("LinkSpan bounds should be (10.5dp, 0dp, 18.5dp, 20.5dp)",
119                new Rect(dp2Px(10.5f), dp2Px(0f), dp2Px(18.5f), dp2Px(20.5f)), bounds);
120
121        info.recycle();
122    }
123
124    @SmallTest
125    public void testNullLayout() {
126        // Setting the padding will cause the layout to be null-ed out.
127        mTextView.setPadding(1, 1, 1, 1);
128
129        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
130        mHelper.onPopulateNodeForVirtualView(0, info);
131
132        Rect bounds = new Rect();
133        info.getBoundsInParent(bounds);
134        assertEquals("LinkSpan bounds should be (0, 0, 1, 1)",
135                new Rect(0, 0, 1, 1), bounds);
136
137        info.recycle();
138    }
139
140    @SmallTest
141    public void testRtlLayout() {
142        // Redo setUp with a Hebrew (RTL) string.
143        mSpan = new LinkSpan("foobar");
144        SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום");
145        ssb.setSpan(mSpan, 1, 2, 0 /* flags */);
146
147        mTextView = new TextView(getContext());
148        mTextView.setText(ssb);
149        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
150        mHelper = new TestLinkAccessibilityHelper(mTextView);
151
152        mTextView.measure(dp2Px(500), dp2Px(500));
153        mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500));
154        // End redo setup
155
156        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
157        mHelper.onPopulateNodeForVirtualView(1, info);
158
159        assertEquals("LinkSpan description should be \"כ\"",
160                "כ", info.getContentDescription().toString());
161        assertTrue("LinkSpan should be focusable", info.isFocusable());
162        assertTrue("LinkSpan should be clickable", info.isClickable());
163        Rect bounds = new Rect();
164        info.getBoundsInParent(bounds);
165        assertEquals("LinkSpan bounds should be (70.5dp, 0dp, 78.5dp, 20.5dp)",
166                new Rect(dp2Px(70.5f), dp2Px(0f), dp2Px(78.5f), dp2Px(20.5f)), bounds);
167
168        info.recycle();
169    }
170
171    private int dp2Px(float dp) {
172        if (mDisplayMetrics == null) {
173            mDisplayMetrics = getContext().getResources().getDisplayMetrics();
174        }
175        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics);
176    }
177
178    private static class TestLinkAccessibilityHelper extends LinkAccessibilityHelper {
179
180        public TestLinkAccessibilityHelper(TextView view) {
181            super(view);
182        }
183
184        @Override
185        public int getVirtualViewAt(float x, float y) {
186            return super.getVirtualViewAt(x, y);
187        }
188
189        @Override
190        public void getVisibleVirtualViews(List<Integer> virtualViewIds) {
191            super.getVisibleVirtualViews(virtualViewIds);
192        }
193
194        @Override
195        public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
196            super.onPopulateEventForVirtualView(virtualViewId, event);
197        }
198
199        @Override
200        public void onPopulateNodeForVirtualView(int virtualViewId,
201                AccessibilityNodeInfoCompat info) {
202            super.onPopulateNodeForVirtualView(virtualViewId, info);
203        }
204
205        @Override
206        public boolean onPerformActionForVirtualView(int virtualViewId, int action,
207                Bundle arguments) {
208            return super.onPerformActionForVirtualView(virtualViewId, action, arguments);
209        }
210    }
211}
212