InterrogationActivityTest.java revision 79311c4af8b54d3cd47ab37a120c648bfc990511
1/**
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11 * express or implied. See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15package android.accessibilityservice;
16
17import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
18import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
19import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
20import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
21
22import android.graphics.Rect;
23import android.os.SystemClock;
24import android.test.ActivityInstrumentationTestCase2;
25import android.test.suitebuilder.annotation.LargeTest;
26import android.util.Log;
27import android.view.accessibility.AccessibilityEvent;
28import android.view.accessibility.AccessibilityNodeInfo;
29
30import com.android.frameworks.coretests.R;
31import com.android.internal.util.Predicate;
32
33import java.util.ArrayList;
34import java.util.LinkedList;
35import java.util.List;
36import java.util.Queue;
37
38/**
39 * Activity for testing the accessibility APIs for "interrogation" of
40 * the screen content. These APIs allow exploring the screen and
41 * requesting an action to be performed on a given view from an
42 * AccessiiblityService.
43 */
44public class InterrogationActivityTest
45        extends ActivityInstrumentationTestCase2<InterrogationActivity> {
46    private static final boolean DEBUG = false;
47
48    private static String LOG_TAG = "InterrogationActivityTest";
49
50    // Timeout for the accessibility state of an Activity to be fully initialized.
51    private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
52
53    // Handle to a connection to the AccessibilityManagerService
54    private UiTestAutomationBridge mUiTestAutomationBridge;
55
56    public InterrogationActivityTest() {
57        super(InterrogationActivity.class);
58    }
59
60    @Override
61    public void setUp() throws Exception {
62        super.setUp();
63        mUiTestAutomationBridge = new UiTestAutomationBridge();
64        mUiTestAutomationBridge.connect();
65        mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
66                // wait for the first accessibility event
67                @Override
68                public void run() {
69                    // bring up the activity
70                    getActivity();
71                }
72            },
73            new Predicate<AccessibilityEvent>() {
74                @Override
75                public boolean apply(AccessibilityEvent event) {
76                    return (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
77                            && event.getPackageName().equals(getActivity().getPackageName()));
78                }
79            },
80            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
81    }
82
83    @Override
84    public void tearDown() throws Exception {
85        mUiTestAutomationBridge.disconnect();
86        super.tearDown();
87    }
88
89    @LargeTest
90    public void testFindAccessibilityNodeInfoByViewId() throws Exception {
91        final long startTimeMillis = SystemClock.uptimeMillis();
92        try {
93            AccessibilityNodeInfo button = mUiTestAutomationBridge
94                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
95            assertNotNull(button);
96            assertEquals(0, button.getChildCount());
97
98            // bounds
99            Rect bounds = new Rect();
100            button.getBoundsInParent(bounds);
101            assertEquals(0, bounds.left);
102            assertEquals(0, bounds.top);
103            assertEquals(160, bounds.right);
104            assertEquals(100, bounds.bottom);
105
106            // char sequence attributes
107            assertEquals("com.android.frameworks.coretests", button.getPackageName());
108            assertEquals("android.widget.Button", button.getClassName());
109            assertEquals("Button5", button.getText());
110            assertNull(button.getContentDescription());
111
112            // boolean attributes
113            assertTrue(button.isFocusable());
114            assertTrue(button.isClickable());
115            assertTrue(button.isEnabled());
116            assertFalse(button.isFocused());
117            assertTrue(button.isClickable());
118            assertFalse(button.isPassword());
119            assertFalse(button.isSelected());
120            assertFalse(button.isCheckable());
121            assertFalse(button.isChecked());
122
123            // actions
124            assertEquals(ACTION_FOCUS | ACTION_SELECT | ACTION_CLEAR_SELECTION,
125                button.getActions());
126        } finally {
127            if (DEBUG) {
128                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
129                Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewId: "
130                        + elapsedTimeMillis + "ms");
131            }
132        }
133    }
134
135    @LargeTest
136    public void testFindAccessibilityNodeInfoByViewText() throws Exception {
137        final long startTimeMillis = SystemClock.uptimeMillis();
138        try {
139            // find a view by text
140            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
141                .findAccessibilityNodeInfosByTextInActiveWindow("butto");
142            assertEquals(9, buttons.size());
143        } finally {
144            if (DEBUG) {
145                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
146                Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewText: "
147                        + elapsedTimeMillis + "ms");
148            }
149        }
150    }
151
152    @LargeTest
153    public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
154        final long startTimeMillis = SystemClock.uptimeMillis();
155        try {
156            // find a view by text
157            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
158                .findAccessibilityNodeInfosByTextInActiveWindow("contentDescription");
159            assertEquals(1, buttons.size());
160        } finally {
161            if (DEBUG) {
162                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
163                Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewTextContentDescription: "
164                        + elapsedTimeMillis + "ms");
165            }
166        }
167    }
168
169    @LargeTest
170    public void testTraverseAllViews() throws Exception {
171        final long startTimeMillis = SystemClock.uptimeMillis();
172        try {
173            // make list of expected nodes
174            List<String> classNameAndTextList = new ArrayList<String>();
175            classNameAndTextList.add("android.widget.LinearLayout");
176            classNameAndTextList.add("android.widget.LinearLayout");
177            classNameAndTextList.add("android.widget.LinearLayout");
178            classNameAndTextList.add("android.widget.LinearLayout");
179            classNameAndTextList.add("android.widget.ButtonButton1");
180            classNameAndTextList.add("android.widget.ButtonButton2");
181            classNameAndTextList.add("android.widget.ButtonButton3");
182            classNameAndTextList.add("android.widget.ButtonButton4");
183            classNameAndTextList.add("android.widget.ButtonButton5");
184            classNameAndTextList.add("android.widget.ButtonButton6");
185            classNameAndTextList.add("android.widget.ButtonButton7");
186            classNameAndTextList.add("android.widget.ButtonButton8");
187            classNameAndTextList.add("android.widget.ButtonButton9");
188
189            AccessibilityNodeInfo root = mUiTestAutomationBridge
190                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
191            assertNotNull("We must find the existing root.", root);
192
193            Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
194            fringe.add(root);
195
196            // do a BFS traversal and check nodes
197            while (!fringe.isEmpty()) {
198                AccessibilityNodeInfo current = fringe.poll();
199
200                CharSequence className = current.getClassName();
201                CharSequence text = current.getText();
202                String receivedClassNameAndText = className.toString()
203                   + ((text != null) ? text.toString() : "");
204                String expectedClassNameAndText = classNameAndTextList.remove(0);
205
206                assertEquals("Did not get the expected node info",
207                        expectedClassNameAndText, receivedClassNameAndText);
208
209                final int childCount = current.getChildCount();
210                for (int i = 0; i < childCount; i++) {
211                    AccessibilityNodeInfo child = current.getChild(i);
212                    fringe.add(child);
213                }
214            }
215        } finally {
216            if (DEBUG) {
217                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
218                Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms");
219            }
220        }
221    }
222
223    @LargeTest
224    public void testPerformAccessibilityActionFocus() throws Exception {
225        final long startTimeMillis = SystemClock.uptimeMillis();
226        try {
227            // find a view and make sure it is not focused
228            AccessibilityNodeInfo button = mUiTestAutomationBridge
229                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
230            assertFalse(button.isFocused());
231
232            // focus the view
233            assertTrue(button.performAction(ACTION_FOCUS));
234
235            // find the view again and make sure it is focused
236            button = mUiTestAutomationBridge
237                    .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
238            assertTrue(button.isFocused());
239        } finally {
240            if (DEBUG) {
241                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
242                Log.i(LOG_TAG, "testPerformAccessibilityActionFocus: " + elapsedTimeMillis + "ms");
243            }
244        }
245    }
246
247    @LargeTest
248    public void testPerformAccessibilityActionClearFocus() throws Exception {
249        final long startTimeMillis = SystemClock.uptimeMillis();
250        try {
251            // find a view and make sure it is not focused
252            AccessibilityNodeInfo button = mUiTestAutomationBridge
253                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
254            assertFalse(button.isFocused());
255
256            // focus the view
257            assertTrue(button.performAction(ACTION_FOCUS));
258
259            // find the view again and make sure it is focused
260            button = mUiTestAutomationBridge
261                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
262            assertTrue(button.isFocused());
263
264            // unfocus the view
265            assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
266
267            // find the view again and make sure it is not focused
268            button = mUiTestAutomationBridge
269                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
270            assertFalse(button.isFocused());
271        } finally {
272            if (DEBUG) {
273                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
274                Log.i(LOG_TAG, "testPerformAccessibilityActionClearFocus: "
275                        + elapsedTimeMillis + "ms");
276            }
277        }
278    }
279
280    @LargeTest
281    public void testPerformAccessibilityActionSelect() throws Exception {
282        final long startTimeMillis = SystemClock.uptimeMillis();
283        try {
284            // find a view and make sure it is not selected
285            AccessibilityNodeInfo button = mUiTestAutomationBridge
286                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
287            assertFalse(button.isSelected());
288
289            // select the view
290            assertTrue(button.performAction(ACTION_SELECT));
291
292            // find the view again and make sure it is selected
293            button = mUiTestAutomationBridge
294                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
295            assertTrue(button.isSelected());
296        } finally {
297            if (DEBUG) {
298                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
299                Log.i(LOG_TAG, "testPerformAccessibilityActionSelect: " + elapsedTimeMillis + "ms");
300            }
301        }
302    }
303
304    @LargeTest
305    public void testPerformAccessibilityActionClearSelection() throws Exception {
306        final long startTimeMillis = SystemClock.uptimeMillis();
307        try {
308            // find a view and make sure it is not selected
309            AccessibilityNodeInfo button = mUiTestAutomationBridge
310                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
311            assertFalse(button.isSelected());
312
313            // select the view
314            assertTrue(button.performAction(ACTION_SELECT));
315
316            // find the view again and make sure it is selected
317            button = mUiTestAutomationBridge
318                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
319            assertTrue(button.isSelected());
320
321            // unselect the view
322            assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
323
324            // find the view again and make sure it is not selected
325            button = mUiTestAutomationBridge
326                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
327            assertFalse(button.isSelected());
328        } finally {
329            if (DEBUG) {
330                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
331                Log.i(LOG_TAG, "testPerformAccessibilityActionClearSelection: "
332                        + elapsedTimeMillis + "ms");
333            }
334        }
335    }
336
337    @LargeTest
338    public void testAccessibilityEventGetSource() throws Exception {
339        final long startTimeMillis = SystemClock.uptimeMillis();
340        try {
341            // find a view and make sure it is not focused
342            final AccessibilityNodeInfo button = mUiTestAutomationBridge
343                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
344            assertFalse(button.isFocused());
345
346            AccessibilityEvent event = mUiTestAutomationBridge
347                    .executeCommandAndWaitForAccessibilityEvent(new Runnable() {
348                @Override
349                public void run() {
350                    // focus the view
351                    assertTrue(button.performAction(ACTION_FOCUS));
352                }
353            },
354            new Predicate<AccessibilityEvent>() {
355                @Override
356                public boolean apply(AccessibilityEvent event) {
357                    return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED
358                            && event.getPackageName().equals(getActivity().getPackageName())
359                            && event.getText().get(0).equals(button.getText()));
360                }
361            },
362            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
363
364            // check the last event
365            assertNotNull(event);
366
367            // check that last event source
368            AccessibilityNodeInfo source = event.getSource();
369            assertNotNull(source);
370
371            // bounds
372            Rect buttonBounds = new Rect();
373            button.getBoundsInParent(buttonBounds);
374            Rect sourceBounds = new Rect();
375            source.getBoundsInParent(sourceBounds);
376
377            assertEquals(buttonBounds.left, sourceBounds.left);
378            assertEquals(buttonBounds.right, sourceBounds.right);
379            assertEquals(buttonBounds.top, sourceBounds.top);
380            assertEquals(buttonBounds.bottom, sourceBounds.bottom);
381
382            // char sequence attributes
383            assertEquals(button.getPackageName(), source.getPackageName());
384            assertEquals(button.getClassName(), source.getClassName());
385            assertEquals(button.getText(), source.getText());
386            assertSame(button.getContentDescription(), source.getContentDescription());
387
388            // boolean attributes
389            assertSame(button.isFocusable(), source.isFocusable());
390            assertSame(button.isClickable(), source.isClickable());
391            assertSame(button.isEnabled(), source.isEnabled());
392            assertNotSame(button.isFocused(), source.isFocused());
393            assertSame(button.isLongClickable(), source.isLongClickable());
394            assertSame(button.isPassword(), source.isPassword());
395            assertSame(button.isSelected(), source.isSelected());
396            assertSame(button.isCheckable(), source.isCheckable());
397            assertSame(button.isChecked(), source.isChecked());
398        } finally {
399            if (DEBUG) {
400                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
401                Log.i(LOG_TAG, "testAccessibilityEventGetSource: " + elapsedTimeMillis + "ms");
402            }
403        }
404    }
405
406    @LargeTest
407    public void testObjectContract() throws Exception {
408        final long startTimeMillis = SystemClock.uptimeMillis();
409        try {
410            // find a view and make sure it is not focused
411            AccessibilityNodeInfo button = mUiTestAutomationBridge
412                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
413            assertNotNull(button);
414            AccessibilityNodeInfo parent = button.getParent();
415            final int childCount = parent.getChildCount();
416            for (int i = 0; i < childCount; i++) {
417                AccessibilityNodeInfo child = parent.getChild(i);
418                assertNotNull(child);
419                if (child.equals(button)) {
420                    assertEquals("Equal objects must have same hasCode.", button.hashCode(),
421                            child.hashCode());
422                    return;
423                }
424            }
425            fail("Parent's children do not have the info whose parent is the parent.");
426        } finally {
427            if (DEBUG) {
428                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
429                Log.i(LOG_TAG, "testObjectContract: " + elapsedTimeMillis + "ms");
430            }
431        }
432    }
433}
434