blob: 3dc140b4ce0a7ea4ee6c46b61741f4c79defee7a [file] [log] [blame]
/**
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.accessibilityservice;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
import android.graphics.Rect;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.frameworks.coretests.R;
import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* Activity for testing the accessibility APIs for "interrogation" of
* the screen content. These APIs allow exploring the screen and
* requesting an action to be performed on a given view from an
* AccessiiblityService.
*/
public class InterrogationActivityTest
extends ActivityInstrumentationTestCase2<InterrogationActivity> {
private static final boolean DEBUG = false;
private static String LOG_TAG = "InterrogationActivityTest";
// Timeout for the accessibility state of an Activity to be fully initialized.
private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
// Timeout for which non getting accessibility events considers the app idle.
private static final long IDLE_EVENT_TIME_DELTA_MILLIS = 200;
// Timeout in which to wait for idle device.
private static final long GLOBAL_IDLE_DETECTION_TIMEOUT_MILLIS = 1000;
// Handle to a connection to the AccessibilityManagerService
private UiTestAutomationBridge mUiTestAutomationBridge;
public InterrogationActivityTest() {
super(InterrogationActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
mUiTestAutomationBridge = new UiTestAutomationBridge();
mUiTestAutomationBridge.connect();
mUiTestAutomationBridge.waitForIdle(IDLE_EVENT_TIME_DELTA_MILLIS,
GLOBAL_IDLE_DETECTION_TIMEOUT_MILLIS);
mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
// wait for the first accessibility event
@Override
public void run() {
// bring up the activity
getActivity();
}
},
new Predicate<AccessibilityEvent>() {
@Override
public boolean apply(AccessibilityEvent event) {
return (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
&& event.getPackageName().equals(getActivity().getPackageName()));
}
},
TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
}
@Override
public void tearDown() throws Exception {
mUiTestAutomationBridge.disconnect();
super.tearDown();
}
@LargeTest
public void testFindAccessibilityNodeInfoByViewId() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertNotNull(button);
assertEquals(0, button.getChildCount());
// bounds
Rect bounds = new Rect();
button.getBoundsInParent(bounds);
assertEquals(0, bounds.left);
assertEquals(0, bounds.top);
assertEquals(160, bounds.right);
assertEquals(100, bounds.bottom);
// char sequence attributes
assertEquals("com.android.frameworks.coretests", button.getPackageName());
assertEquals("android.widget.Button", button.getClassName());
assertEquals("Button5", button.getText());
assertNull(button.getContentDescription());
// boolean attributes
assertTrue(button.isFocusable());
assertTrue(button.isClickable());
assertTrue(button.isEnabled());
assertFalse(button.isFocused());
assertTrue(button.isClickable());
assertFalse(button.isPassword());
assertFalse(button.isSelected());
assertFalse(button.isCheckable());
assertFalse(button.isChecked());
// actions
assertEquals(ACTION_FOCUS | ACTION_SELECT | ACTION_CLEAR_SELECTION,
button.getActions());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewId: "
+ elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testFindAccessibilityNodeInfoByViewText() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view by text
List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
.findAccessibilityNodeInfosByTextInActiveWindow("butto");
assertEquals(9, buttons.size());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewText: "
+ elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view by text
List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
.findAccessibilityNodeInfosByTextInActiveWindow("contentDescription");
assertEquals(1, buttons.size());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewTextContentDescription: "
+ elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testTraverseAllViews() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// make list of expected nodes
List<String> classNameAndTextList = new ArrayList<String>();
classNameAndTextList.add("android.widget.LinearLayout");
classNameAndTextList.add("android.widget.LinearLayout");
classNameAndTextList.add("android.widget.LinearLayout");
classNameAndTextList.add("android.widget.LinearLayout");
classNameAndTextList.add("android.widget.ButtonButton1");
classNameAndTextList.add("android.widget.ButtonButton2");
classNameAndTextList.add("android.widget.ButtonButton3");
classNameAndTextList.add("android.widget.ButtonButton4");
classNameAndTextList.add("android.widget.ButtonButton5");
classNameAndTextList.add("android.widget.ButtonButton6");
classNameAndTextList.add("android.widget.ButtonButton7");
classNameAndTextList.add("android.widget.ButtonButton8");
classNameAndTextList.add("android.widget.ButtonButton9");
AccessibilityNodeInfo root = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
assertNotNull("We must find the existing root.", root);
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
fringe.add(root);
// do a BFS traversal and check nodes
while (!fringe.isEmpty()) {
AccessibilityNodeInfo current = fringe.poll();
CharSequence className = current.getClassName();
CharSequence text = current.getText();
String receivedClassNameAndText = className.toString()
+ ((text != null) ? text.toString() : "");
String expectedClassNameAndText = classNameAndTextList.remove(0);
assertEquals("Did not get the expected node info",
expectedClassNameAndText, receivedClassNameAndText);
final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
AccessibilityNodeInfo child = current.getChild(i);
fringe.add(child);
}
}
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testPerformAccessibilityActionFocus() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testPerformAccessibilityActionFocus: " + elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testPerformAccessibilityActionClearFocus() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
// unfocus the view
assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
// find the view again and make sure it is not focused
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testPerformAccessibilityActionClearFocus: "
+ elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testPerformAccessibilityActionSelect() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not selected
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testPerformAccessibilityActionSelect: " + elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testPerformAccessibilityActionClearSelection() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not selected
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
// unselect the view
assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
// find the view again and make sure it is not selected
button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testPerformAccessibilityActionClearSelection: "
+ elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testAccessibilityEventGetSource() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
final AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
AccessibilityEvent event = mUiTestAutomationBridge
.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
@Override
public void run() {
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
}
},
new Predicate<AccessibilityEvent>() {
@Override
public boolean apply(AccessibilityEvent event) {
return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED
&& event.getPackageName().equals(getActivity().getPackageName())
&& event.getText().get(0).equals(button.getText()));
}
},
TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
// check the last event
assertNotNull(event);
// check that last event source
AccessibilityNodeInfo source = event.getSource();
assertNotNull(source);
// bounds
Rect buttonBounds = new Rect();
button.getBoundsInParent(buttonBounds);
Rect sourceBounds = new Rect();
source.getBoundsInParent(sourceBounds);
assertEquals(buttonBounds.left, sourceBounds.left);
assertEquals(buttonBounds.right, sourceBounds.right);
assertEquals(buttonBounds.top, sourceBounds.top);
assertEquals(buttonBounds.bottom, sourceBounds.bottom);
// char sequence attributes
assertEquals(button.getPackageName(), source.getPackageName());
assertEquals(button.getClassName(), source.getClassName());
assertEquals(button.getText(), source.getText());
assertSame(button.getContentDescription(), source.getContentDescription());
// boolean attributes
assertSame(button.isFocusable(), source.isFocusable());
assertSame(button.isClickable(), source.isClickable());
assertSame(button.isEnabled(), source.isEnabled());
assertNotSame(button.isFocused(), source.isFocused());
assertSame(button.isLongClickable(), source.isLongClickable());
assertSame(button.isPassword(), source.isPassword());
assertSame(button.isSelected(), source.isSelected());
assertSame(button.isCheckable(), source.isCheckable());
assertSame(button.isChecked(), source.isChecked());
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testAccessibilityEventGetSource: " + elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testObjectContract() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
AccessibilityNodeInfo button = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertNotNull(button);
AccessibilityNodeInfo parent = button.getParent();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
AccessibilityNodeInfo child = parent.getChild(i);
assertNotNull(child);
if (child.equals(button)) {
assertEquals("Equal objects must have same hasCode.", button.hashCode(),
child.hashCode());
return;
}
}
fail("Parent's children do not have the info whose parent is the parent.");
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testObjectContract: " + elapsedTimeMillis + "ms");
}
}
}
@LargeTest
public void testGetRootAccessibilityNodeInfoInActiveWindow() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// get the root via the designated API
AccessibilityNodeInfo fetched = mUiTestAutomationBridge
.getRootAccessibilityNodeInfoInActiveWindow();
assertNotNull(fetched);
// get the root via traversal
AccessibilityNodeInfo expected = mUiTestAutomationBridge
.findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
while (true) {
AccessibilityNodeInfo parent = expected.getParent();
if (parent == null) {
break;
}
expected = parent;
}
assertNotNull(expected);
assertEquals("The node with id \"root\" should be the root.", expected, fetched);
} finally {
if (DEBUG) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
Log.i(LOG_TAG, "testGetRootAccessibilityNodeInfoInActiveWindow: "
+ elapsedTimeMillis + "ms");
}
}
}
}