| /* |
| * Copyright (C) 2012 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.cts; |
| |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS; |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION; |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS; |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; |
| import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT; |
| |
| import android.accessibilityservice.AccessibilityService; |
| import android.accessibilityservice.AccessibilityServiceInfo; |
| import android.app.UiAutomation; |
| import android.graphics.Rect; |
| import android.os.SystemClock; |
| import android.test.suitebuilder.annotation.MediumTest; |
| import android.view.Gravity; |
| import android.view.WindowManager; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.accessibility.AccessibilityNodeInfo; |
| import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; |
| import android.view.accessibility.AccessibilityWindowInfo; |
| |
| import android.widget.Button; |
| import com.android.cts.accessibilityservice.R; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Queue; |
| import java.util.concurrent.TimeoutException; |
| |
| /** |
| * Test cases for testing the accessibility APIs for querying of the screen content. |
| * These APIs allow exploring the screen and requesting an action to be performed |
| * on a given view from an AccessibilityService. |
| */ |
| public class AccessibilityWindowQueryTest |
| extends AccessibilityActivityTestCase<AccessibilityWindowQueryActivity> { |
| |
| private static final long TIMEOUT_WINDOW_STATE_IDLE = 500; |
| |
| public AccessibilityWindowQueryTest() { |
| super(AccessibilityWindowQueryActivity.class); |
| } |
| |
| @MediumTest |
| public void testFindByText() throws Exception { |
| // find a view by text |
| List<AccessibilityNodeInfo> buttons = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText("b"); |
| assertEquals(9, buttons.size()); |
| } |
| |
| @MediumTest |
| public void testFindByContentDescription() throws Exception { |
| // find a view by text |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.contentDescription)).get(0); |
| assertNotNull(button); |
| } |
| |
| @MediumTest |
| public void testTraverseWindow() throws Exception { |
| verifyNodesInAppWindow(getInstrumentation().getUiAutomation().getRootInActiveWindow()); |
| } |
| |
| @MediumTest |
| public void testNoWindowsAccessIfFlagNotSet() throws Exception { |
| // Make sure the windows cannot be accessed. |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| assertTrue(uiAutomation.getWindows().isEmpty()); |
| |
| // Find a button to click on. |
| final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow() |
| .findAccessibilityNodeInfosByViewId( |
| "com.android.cts.accessibilityservice:id/button1").get(0); |
| |
| // Argh... |
| final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>(); |
| |
| // Click the button. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button1.performAction(AccessibilityNodeInfo.ACTION_CLICK); |
| } |
| }, |
| new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) { |
| events.add(event); |
| return true; |
| } |
| return false; |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| // Make sure the source window cannot be accessed. |
| AccessibilityEvent event = events.get(0); |
| assertNull(event.getSource().getWindow()); |
| } |
| |
| @MediumTest |
| public void testTraverseAllWindows() throws Exception { |
| setAccessInteractiveWindowsFlag(); |
| try { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| |
| List<AccessibilityWindowInfo> windows = uiAutomation.getWindows(); |
| Rect boundsInScreen = new Rect(); |
| |
| final int windowCount = windows.size(); |
| for (int i = 0; i < windowCount; i++) { |
| AccessibilityWindowInfo window = windows.get(i); |
| |
| window.getBoundsInScreen(boundsInScreen); |
| assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, emptiness check. |
| assertNull(window.getParent()); |
| assertSame(0, window.getChildCount()); |
| assertNull(window.getParent()); |
| assertNotNull(window.getRoot()); |
| |
| if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) { |
| assertTrue(window.isFocused()); |
| assertTrue(window.isActive()); |
| verifyNodesInAppWindow(window.getRoot()); |
| } else if (window.getType() == AccessibilityWindowInfo.TYPE_SYSTEM) { |
| assertFalse(window.isFocused()); |
| assertFalse(window.isActive()); |
| } |
| } |
| } finally { |
| clearAccessInteractiveWindowsFlag(); |
| } |
| } |
| |
| @MediumTest |
| public void testTraverseWindowFromEvent() throws Exception { |
| setAccessInteractiveWindowsFlag(); |
| try { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| |
| // Find a button to click on. |
| final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow() |
| .findAccessibilityNodeInfosByViewId( |
| "com.android.cts.accessibilityservice:id/button1").get(0); |
| |
| // Argh... |
| final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>(); |
| |
| // Click the button. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button1.performAction(AccessibilityNodeInfo.ACTION_CLICK); |
| } |
| }, |
| new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) { |
| events.add(event); |
| return true; |
| } |
| return false; |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| // Get the source window. |
| AccessibilityEvent event = events.get(0); |
| AccessibilityWindowInfo window = event.getSource().getWindow(); |
| |
| // Verify the application window. |
| Rect boundsInScreen = new Rect(); |
| window.getBoundsInScreen(boundsInScreen); |
| assertFalse(boundsInScreen.isEmpty()); // Varies on screen size, so just emptiness check. |
| assertSame(window.getType(), AccessibilityWindowInfo.TYPE_APPLICATION); |
| assertTrue(window.isFocused()); |
| assertTrue(window.isActive()); |
| assertNull(window.getParent()); |
| assertSame(0, window.getChildCount()); |
| assertNotNull(window.getRoot()); |
| |
| // Verify the window content. |
| verifyNodesInAppWindow(window.getRoot()); |
| } finally { |
| clearAccessInteractiveWindowsFlag(); |
| } |
| } |
| |
| @MediumTest |
| public void testInteractWithAppWindow() throws Exception { |
| setAccessInteractiveWindowsFlag(); |
| try { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| |
| // Find a button to click on. |
| final AccessibilityNodeInfo button1 = uiAutomation.getRootInActiveWindow() |
| .findAccessibilityNodeInfosByViewId( |
| "com.android.cts.accessibilityservice:id/button1").get(0); |
| |
| // Argh... |
| final List<AccessibilityEvent> events = new ArrayList<AccessibilityEvent>(); |
| |
| // Click the button. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button1.performAction(AccessibilityNodeInfo.ACTION_CLICK); |
| } |
| }, |
| new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) { |
| events.add(event); |
| return true; |
| } |
| return false; |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| // Get the source window. |
| AccessibilityEvent event = events.get(0); |
| AccessibilityWindowInfo window = event.getSource().getWindow(); |
| |
| // Find a another button from the event's window. |
| final AccessibilityNodeInfo button2 = window.getRoot() |
| .findAccessibilityNodeInfosByViewId( |
| "com.android.cts.accessibilityservice:id/button2").get(0); |
| |
| // Click the second button. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button2.performAction(AccessibilityNodeInfo.ACTION_CLICK); |
| } |
| }, |
| new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED; |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| } finally { |
| clearAccessInteractiveWindowsFlag(); |
| } |
| } |
| |
| @MediumTest |
| public void testSingleAccessibilityFocusAcrossWindows() throws Exception { |
| setAccessInteractiveWindowsFlag(); |
| try { |
| // Add two more windows. |
| addTwoAppPanelWindows(); |
| |
| // Put accessibility focus in the first app window. |
| ensureAppWindowFocusedOrFail(0); |
| // Make sure there only one accessibility focus. |
| assertSingleAccessibilityFocus(); |
| |
| // Put accessibility focus in the second app window. |
| ensureAppWindowFocusedOrFail(1); |
| // Make sure there only one accessibility focus. |
| assertSingleAccessibilityFocus(); |
| |
| // Put accessibility focus in the third app window. |
| ensureAppWindowFocusedOrFail(2); |
| // Make sure there only one accessibility focus. |
| assertSingleAccessibilityFocus(); |
| } finally { |
| ensureAccessibilityFocusCleared(); |
| clearAccessInteractiveWindowsFlag(); |
| } |
| } |
| |
| @MediumTest |
| public void testPerformActionFocus() throws Exception { |
| // find a view and make sure it is not focused |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isFocused()); |
| |
| // focus the view |
| assertTrue(button.performAction(ACTION_FOCUS)); |
| |
| // find the view again and make sure it is focused |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| assertTrue(button.isFocused()); |
| } |
| |
| @MediumTest |
| public void testPerformActionClearFocus() throws Exception { |
| // find a view and make sure it is not focused |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isFocused()); |
| |
| // focus the view |
| assertTrue(button.performAction(ACTION_FOCUS)); |
| |
| // find the view again and make sure it is focused |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| assertTrue(button.isFocused()); |
| |
| // unfocus the view |
| assertTrue(button.performAction(ACTION_CLEAR_FOCUS)); |
| |
| // find the view again and make sure it is not focused |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| assertFalse(button.isFocused()); |
| } |
| |
| @MediumTest |
| public void testPerformActionSelect() throws Exception { |
| // find a view and make sure it is not selected |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| |
| // select the view |
| assertTrue(button.performAction(ACTION_SELECT)); |
| |
| // find the view again and make sure it is selected |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| assertTrue(button.isSelected()); |
| } |
| |
| @MediumTest |
| public void testPerformActionClearSelection() throws Exception { |
| // find a view and make sure it is not selected |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| |
| // select the view |
| assertTrue(button.performAction(ACTION_SELECT)); |
| |
| // find the view again and make sure it is selected |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| |
| assertTrue(button.isSelected()); |
| |
| // unselect the view |
| assertTrue(button.performAction(ACTION_CLEAR_SELECTION)); |
| |
| // find the view again and make sure it is not selected |
| button = getInstrumentation().getUiAutomation().getRootInActiveWindow() |
| .findAccessibilityNodeInfosByText(getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| } |
| |
| @MediumTest |
| public void testPerformActionClick() throws Exception { |
| // find a view and make sure it is not selected |
| final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| |
| // Make an action and wait for an event. |
| AccessibilityEvent expected = getInstrumentation().getUiAutomation() |
| .executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button.performAction(ACTION_CLICK); |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED); |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| // Make sure the expected event was received. |
| assertNotNull(expected); |
| } |
| |
| @MediumTest |
| public void testPerformActionLongClick() throws Exception { |
| // find a view and make sure it is not selected |
| final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| |
| // Make an action and wait for an event. |
| AccessibilityEvent expected = getInstrumentation().getUiAutomation() |
| .executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| button.performAction(ACTION_LONG_CLICK); |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| // Make sure the expected event was received. |
| assertNotNull(expected); |
| } |
| |
| |
| @MediumTest |
| public void testPerformCustomAction() throws Exception { |
| // find a view and make sure it is not selected |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| |
| // find the custom action and perform it |
| List<AccessibilityAction> actions = button.getActionList(); |
| final int actionCount = actions.size(); |
| for (int i = 0; i < actionCount; i++) { |
| AccessibilityAction action = actions.get(i); |
| if (action.getId() == R.id.foo_custom_action) { |
| assertSame(action.getLabel(), "Foo"); |
| // perform the action |
| assertTrue(button.performAction(action.getId())); |
| return; |
| } |
| } |
| } |
| |
| @MediumTest |
| public void testGetEventSource() throws Exception { |
| // find a view and make sure it is not focused |
| final AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| assertFalse(button.isSelected()); |
| |
| // focus and wait for the event |
| AccessibilityEvent awaitedEvent = getInstrumentation().getUiAutomation() |
| .executeAndWaitForEvent( |
| new Runnable() { |
| @Override |
| public void run() { |
| assertTrue(button.performAction(ACTION_FOCUS)); |
| } |
| }, |
| new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED); |
| } |
| }, |
| TIMEOUT_ASYNC_PROCESSING); |
| |
| assertNotNull(awaitedEvent); |
| |
| // check that last event source |
| AccessibilityNodeInfo source = awaitedEvent.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().toString(), source.getText().toString()); |
| 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()); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionBack() throws Exception { |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_BACK)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionHome() throws Exception { |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_HOME)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionRecents() throws Exception { |
| // Check whether the action succeeded. |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_RECENTS)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| |
| // This is a necessary since the back action does not |
| // dismiss recents until they stop animating. Sigh... |
| SystemClock.sleep(5000); |
| |
| // Clean up. |
| getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_BACK); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionNotifications() throws Exception { |
| // Perform the action under test |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| |
| // Clean up. |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_BACK)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionQuickSettings() throws Exception { |
| // Check whether the action succeeded. |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| |
| // Clean up. |
| getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_BACK); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testPerformGlobalActionPowerDialog() throws Exception { |
| // Check whether the action succeeded. |
| assertTrue(getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_POWER_DIALOG)); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| |
| // Clean up. |
| getInstrumentation().getUiAutomation().performGlobalAction( |
| AccessibilityService.GLOBAL_ACTION_BACK); |
| |
| // Sleep a bit so the UI is settles. |
| waitForIdle(); |
| } |
| |
| @MediumTest |
| public void testObjectContract() throws Exception { |
| try { |
| AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo(); |
| info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; |
| getInstrumentation().getUiAutomation().setServiceInfo(info); |
| |
| // find a view and make sure it is not focused |
| AccessibilityNodeInfo button = getInstrumentation().getUiAutomation() |
| .getRootInActiveWindow().findAccessibilityNodeInfosByText( |
| getString(R.string.button5)).get(0); |
| 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 { |
| AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo(); |
| info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; |
| getInstrumentation().getUiAutomation().setServiceInfo(info); |
| } |
| } |
| |
| private void assertSingleAccessibilityFocus() { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| List<AccessibilityWindowInfo> windows = uiAutomation.getWindows(); |
| AccessibilityWindowInfo focused = null; |
| |
| final int windowCount = windows.size(); |
| for (int i = 0; i < windowCount; i++) { |
| AccessibilityWindowInfo window = windows.get(i); |
| |
| if (window.isAccessibilityFocused()) { |
| if (focused == null) { |
| focused = window; |
| |
| AccessibilityNodeInfo root = window.getRoot(); |
| assertEquals(uiAutomation.findFocus( |
| AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root); |
| assertEquals(root.findFocus( |
| AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), root); |
| } else { |
| throw new AssertionError("Duplicate accessibility focus"); |
| } |
| } else { |
| assertNull(window.getRoot().findFocus( |
| AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)); |
| } |
| } |
| } |
| |
| private void ensureAppWindowFocusedOrFail(int appWindowIndex) throws TimeoutException { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| List<AccessibilityWindowInfo> windows = uiAutomation.getWindows(); |
| AccessibilityWindowInfo focusTareget = null; |
| |
| int visitedAppWindows = -1; |
| final int windowCount = windows.size(); |
| for (int i = 0; i < windowCount; i++) { |
| AccessibilityWindowInfo window = windows.get(i); |
| if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) { |
| visitedAppWindows++; |
| if (appWindowIndex <= visitedAppWindows) { |
| focusTareget = window; |
| break; |
| } |
| } |
| } |
| |
| if (focusTareget == null) { |
| throw new IllegalStateException("Couldn't find app window: " + appWindowIndex); |
| } |
| |
| if (focusTareget.isAccessibilityFocused()) { |
| return; |
| } |
| |
| final AccessibilityWindowInfo finalFocusTarget = focusTareget; |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| assertTrue(finalFocusTarget.getRoot().performAction( |
| AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)); |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED; |
| } |
| }, TIMEOUT_ASYNC_PROCESSING); |
| |
| windows = uiAutomation.getWindows(); |
| for (int i = 0; i < windowCount; i++) { |
| AccessibilityWindowInfo window = windows.get(i); |
| if (window.getId() == focusTareget.getId()) { |
| assertTrue(window.isAccessibilityFocused()); |
| break; |
| } |
| } |
| } |
| |
| private void addTwoAppPanelWindows() throws TimeoutException { |
| final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| |
| uiAutomation.waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING); |
| |
| // Add the first window. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| WindowManager.LayoutParams params = new WindowManager.LayoutParams(); |
| params.gravity = Gravity.TOP; |
| params.width = WindowManager.LayoutParams.MATCH_PARENT; |
| params.height = WindowManager.LayoutParams.WRAP_CONTENT; |
| params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
| | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
| | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
| | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; |
| params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; |
| params.token = getActivity().getWindow().getDecorView().getWindowToken(); |
| |
| Button button = new Button(getActivity()); |
| button.setText(R.string.button1); |
| getActivity().getWindowManager().addView(button, params); |
| } |
| }); |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED; |
| } |
| }, TIMEOUT_ASYNC_PROCESSING); |
| |
| // Add the second window. |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| WindowManager.LayoutParams params = new WindowManager.LayoutParams(); |
| params.gravity = Gravity.BOTTOM; |
| params.width = WindowManager.LayoutParams.MATCH_PARENT; |
| params.height = WindowManager.LayoutParams.WRAP_CONTENT; |
| params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
| | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
| | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
| | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; |
| params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; |
| params.token = getActivity().getWindow().getDecorView().getWindowToken(); |
| |
| Button button = new Button(getActivity()); |
| button.setText(R.string.button2); |
| getActivity().getWindowManager().addView(button, params); |
| } |
| }); |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED; |
| } |
| }, TIMEOUT_ASYNC_PROCESSING); |
| } |
| |
| private void setAccessInteractiveWindowsFlag () { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| AccessibilityServiceInfo info = uiAutomation.getServiceInfo(); |
| info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; |
| uiAutomation.setServiceInfo(info); |
| } |
| |
| private void clearAccessInteractiveWindowsFlag () { |
| UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| AccessibilityServiceInfo info = uiAutomation.getServiceInfo(); |
| info.flags &= ~AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; |
| uiAutomation.setServiceInfo(info); |
| } |
| |
| private void ensureAccessibilityFocusCleared() { |
| try { |
| final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); |
| uiAutomation.executeAndWaitForEvent(new Runnable() { |
| @Override |
| public void run() { |
| List<AccessibilityWindowInfo> windows = uiAutomation.getWindows(); |
| final int windowCount = windows.size(); |
| for (int i = 0; i < windowCount; i++) { |
| AccessibilityWindowInfo window = windows.get(i); |
| if (window.isAccessibilityFocused()) { |
| window.getRoot().performAction( |
| AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); |
| } |
| } |
| } |
| }, new UiAutomation.AccessibilityEventFilter() { |
| @Override |
| public boolean accept(AccessibilityEvent event) { |
| return event.getEventType() == |
| AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED; |
| } |
| }, TIMEOUT_ASYNC_PROCESSING); |
| } catch (TimeoutException te) { |
| /* ignore */ |
| } |
| } |
| |
| private void verifyNodesInAppWindow(AccessibilityNodeInfo root) throws Exception { |
| try { |
| AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo(); |
| info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; |
| getInstrumentation().getUiAutomation().setServiceInfo(info); |
| |
| root.refresh(); |
| |
| // 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.ButtonB1"); |
| classNameAndTextList.add("android.widget.ButtonB2"); |
| classNameAndTextList.add("android.widget.ButtonB3"); |
| classNameAndTextList.add("android.widget.ButtonB4"); |
| classNameAndTextList.add("android.widget.ButtonB5"); |
| classNameAndTextList.add("android.widget.ButtonB6"); |
| classNameAndTextList.add("android.widget.ButtonB7"); |
| classNameAndTextList.add("android.widget.ButtonB8"); |
| classNameAndTextList.add("android.widget.ButtonB9"); |
| |
| String contentViewIdResName = "com.android.cts.accessibilityservice:id/added_content"; |
| boolean verifyContent = false; |
| |
| Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>(); |
| fringe.add(root); |
| |
| // do a BFS traversal and check nodes |
| while (!fringe.isEmpty()) { |
| AccessibilityNodeInfo current = fringe.poll(); |
| |
| if (!verifyContent |
| && contentViewIdResName.equals(current.getViewIdResourceName())) { |
| verifyContent = true; |
| } |
| |
| if (verifyContent) { |
| CharSequence text = current.getText(); |
| String receivedClassNameAndText = current.getClassName().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 { |
| AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo(); |
| info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; |
| getInstrumentation().getUiAutomation().setServiceInfo(info); |
| } |
| } |
| |
| @Override |
| protected void scrubClass(Class<?> testCaseClass) { |
| /* intentionally do not scrub */ |
| } |
| } |