Update the accessibility tests due to changes that fixed memory leaks.
Change-Id: Ie5521ac38b2064453a2a91dd9856d6a4b383af44
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl b/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
index 62703dc..c1fe57b 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
+++ b/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
@@ -16,15 +16,27 @@
package android.accessibilityservice;
import android.os.IBinder;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import java.util.List;
/**
- * Interface for registering an accessibility service delegate.
+ * Interface for registering an accessibility service delegate
+ * and asking it to perform some querying of the window for us.
*/
-oneway interface IAccessibilityServiceDelegateConnection {
+interface IAccessibilityServiceDelegateConnection {
- /**
- * Sets the delegate interface to which the
- * {@link DelegatingAccessibilityService} to delegate.
- */
void setAccessibilityServiceDelegate(in IBinder binder);
+
+ List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(in AccessibilityNodeInfo root,
+ String text);
+
+ AccessibilityNodeInfo getParent(in AccessibilityNodeInfo child);
+
+ AccessibilityNodeInfo getChild(in AccessibilityNodeInfo parent, int index);
+
+ boolean performAccessibilityAction(in AccessibilityNodeInfo target, int action);
+
+ AccessibilityNodeInfo getSource(in AccessibilityEvent event);
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/delegate/DelegatingAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/delegate/DelegatingAccessibilityService.java
index 5680b7c..21069b8 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/delegate/DelegatingAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/delegate/DelegatingAccessibilityService.java
@@ -25,6 +25,9 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import java.util.List;
/**
* This class is an accessibility service mock to which the system is bound and
@@ -127,10 +130,37 @@
private class AccessibilityServiceDelegateConnection extends
IAccessibilityServiceDelegateConnection.Stub {
+ @Override
public void setAccessibilityServiceDelegate(IBinder binder) {
sServiceDelegate.setDelegateInterface(IAccessibilityServiceDelegate.Stub
.asInterface(binder));
}
+
+ @Override
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(
+ AccessibilityNodeInfo root, String text) {
+ return root.findAccessibilityNodeInfosByText(text);
+ }
+
+ @Override
+ public AccessibilityNodeInfo getChild(AccessibilityNodeInfo parent, int index) {
+ return parent.getChild(index);
+ }
+
+ @Override
+ public AccessibilityNodeInfo getParent(AccessibilityNodeInfo child) {
+ return child.getParent();
+ }
+
+ @Override
+ public AccessibilityNodeInfo getSource(AccessibilityEvent event) {
+ return event.getSource();
+ }
+
+ @Override
+ public boolean performAccessibilityAction(AccessibilityNodeInfo target, int action) {
+ return target.performAction(action);
+ }
}
}
}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl b/tests/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
index 62703dc..c1fe57b 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/IAccessibilityServiceDelegateConnection.aidl
@@ -16,15 +16,27 @@
package android.accessibilityservice;
import android.os.IBinder;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import java.util.List;
/**
- * Interface for registering an accessibility service delegate.
+ * Interface for registering an accessibility service delegate
+ * and asking it to perform some querying of the window for us.
*/
-oneway interface IAccessibilityServiceDelegateConnection {
+interface IAccessibilityServiceDelegateConnection {
- /**
- * Sets the delegate interface to which the
- * {@link DelegatingAccessibilityService} to delegate.
- */
void setAccessibilityServiceDelegate(in IBinder binder);
+
+ List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(in AccessibilityNodeInfo root,
+ String text);
+
+ AccessibilityNodeInfo getParent(in AccessibilityNodeInfo child);
+
+ AccessibilityNodeInfo getChild(in AccessibilityNodeInfo parent, int index);
+
+ boolean performAccessibilityAction(in AccessibilityNodeInfo target, int action);
+
+ AccessibilityNodeInfo getSource(in AccessibilityEvent event);
}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDelegateHelper.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDelegateHelper.java
index 1e7c625..211f67b 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDelegateHelper.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityDelegateHelper.java
@@ -92,6 +92,11 @@
private boolean mInitialized;
/**
+ * Query connection to the delegating accessibility service.
+ */
+ private IAccessibilityServiceDelegateConnection mQueryConnection;
+
+ /**
* Creates a new instance.
*
* @param service The service to which to delegate.
@@ -180,10 +185,10 @@
* {@inheritDoc ServiceConnection#onServiceConnected(ComponentName,IBinder)}
*/
public void onServiceConnected(ComponentName name, IBinder service) {
- IAccessibilityServiceDelegateConnection connection =
- IAccessibilityServiceDelegateConnection.Stub.asInterface(service);
+ mQueryConnection = IAccessibilityServiceDelegateConnection.Stub.asInterface(service);
try {
- connection.setAccessibilityServiceDelegate(new IAccessibilityServiceDelegate.Stub() {
+ mQueryConnection.setAccessibilityServiceDelegate(
+ new IAccessibilityServiceDelegate.Stub() {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
mAccessibilityService.onAccessibilityEvent(event);
@@ -209,4 +214,13 @@
mInitialized = false;
/* do nothing */
}
+
+ /**
+ * Gets the query connection to the delegating accessibility service.
+ *
+ * @return The connection.
+ */
+ public IAccessibilityServiceDelegateConnection getQueryConnection() {
+ return mQueryConnection;
+ }
}
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivityTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivityTest.java
index d798052..3b41b6c 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivityTest.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryActivityTest.java
@@ -22,6 +22,7 @@
import android.accessibilityservice.AccessibilityService;
import android.content.Context;
import android.graphics.Rect;
+import android.os.RemoteException;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.accessibility.AccessibilityEvent;
@@ -65,6 +66,8 @@
public class AccessibilityWindowQueryActivityTest
extends ActivityInstrumentationTestCase2<AccessibilityWindowQueryActivity> {
+ private static AccessibilityQueryBridge sQueryBridge;
+
private interface AccessibilityEventFilter {
public boolean accept(AccessibilityEvent event);
}
@@ -82,16 +85,16 @@
@LargeTest
public void testFindByText() throws Exception {
// find a view by text
- List<AccessibilityNodeInfo> buttons = findAccessibilityNodeInfosByText(
- getAwaitedAccessibilityEventSource(), "butto");
+ List<AccessibilityNodeInfo> buttons =
+ getQueryBridge().findAccessibilityNodeInfosByText("butto");
assertEquals(9, buttons.size());
}
@LargeTest
public void testFindByContentDescription() throws Exception {
// find a view by text
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.contentDescription);
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.contentDescription));
assertNotNull(button);
}
@@ -117,7 +120,7 @@
classNameAndTextList.add("android.widget.ButtonButton9");
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
- fringe.add(getAwaitedAccessibilityEventSource());
+ fringe.add(getQueryBridge().getAwaitedAccessibilityEventSource());
// do a BFS traversal and check nodes
while (!fringe.isEmpty()) {
@@ -133,7 +136,7 @@
final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
- AccessibilityNodeInfo child = current.getChild(i);
+ AccessibilityNodeInfo child = getQueryBridge().getChild(current, i);
fringe.add(child);
}
}
@@ -142,99 +145,97 @@
@LargeTest
public void testPerformActionFocus() throws Exception {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertFalse(button.isFocused());
// focus the view
- assertTrue(button.performAction(ACTION_FOCUS));
+ assertTrue(getQueryBridge().performAction(button, ACTION_FOCUS));
// find the view again and make sure it is focused
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),
- R.string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertTrue(button.isFocused());
}
@LargeTest
public void testPerformActionClearFocus() throws Exception {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertFalse(button.isFocused());
// focus the view
- assertTrue(button.performAction(ACTION_FOCUS));
+ assertTrue(getQueryBridge().performAction(button, ACTION_FOCUS));
// find the view again and make sure it is focused
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),
- R.string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertTrue(button.isFocused());
// unfocus the view
- assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
+ assertTrue(getQueryBridge().performAction(button, ACTION_CLEAR_FOCUS));
// find the view again and make sure it is not focused
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),
- R.string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(getString(
+ R.string.button5));
assertFalse(button.isFocused());
}
@LargeTest
public void testPerformActionSelect() throws Exception {
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertFalse(button.isSelected());
// select the view
- assertTrue(button.performAction(ACTION_SELECT));
+ assertTrue(sQueryBridge.performAction(button, ACTION_SELECT));
// find the view again and make sure it is selected
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),
- R.string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertTrue(button.isSelected());
}
@LargeTest
public void testPerformActionClearSelection() throws Exception {
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertFalse(button.isSelected());
// select the view
- assertTrue(button.performAction(ACTION_SELECT));
+ assertTrue(sQueryBridge.performAction(button, ACTION_SELECT));
// find the view again and make sure it is selected
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),R
- .string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertTrue(button.isSelected());
// unselect the view
- assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
+ assertTrue(getQueryBridge().performAction(button, ACTION_CLEAR_SELECTION));
// find the view again and make sure it is not selected
- button = findAccessibilityNodeInfoByText(getAwaitedAccessibilityEventSource(),
- R.string.button5);
+ button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
assertFalse(button.isSelected());
}
@LargeTest
public void testGetEventSource() throws Exception {
// find a view and make sure it is not focused
- final AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
+ final AccessibilityNodeInfo button =
+ getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(getString(R.string.button5));
assertFalse(button.isSelected());
// focus and wait for the event
- AccessibilityQueryBridge bridge = AccessibilityQueryBridge.getInstance(
- getInstrumentation().getContext());
- bridge.perfromActionAndWaitForEvent(
+ getQueryBridge().perfromActionAndWaitForEvent(
new Runnable() {
@Override
public void run() {
- assertTrue(button.performAction(ACTION_FOCUS));
+ assertTrue(getQueryBridge().performAction(button, ACTION_FOCUS));
}
},
new AccessibilityEventFilter() {
@@ -245,7 +246,7 @@
});
// check that last event source
- AccessibilityNodeInfo source = getAwaitedAccessibilityEventSource();
+ AccessibilityNodeInfo source = getQueryBridge().getAwaitedAccessibilityEventSource();
assertNotNull(source);
// bounds
@@ -280,12 +281,12 @@
@LargeTest
public void testObjectContract() throws Exception {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = findAccessibilityNodeInfoByText(
- getAwaitedAccessibilityEventSource(), R.string.button5);
- AccessibilityNodeInfo parent = button.getParent();
+ AccessibilityNodeInfo button = getQueryBridge().findAccessibilityNodeInfoByTextFromRoot(
+ getString(R.string.button5));
+ AccessibilityNodeInfo parent = getQueryBridge().getParent(button);
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
- AccessibilityNodeInfo child = parent.getChild(i);
+ AccessibilityNodeInfo child = getQueryBridge().getChild(parent, i);
assertNotNull(child);
if (child.equals(button)) {
assertEquals("Equal objects must have same hasCode.", button.hashCode(),
@@ -301,14 +302,19 @@
/* intentionally do not scrub */
}
+ private AccessibilityQueryBridge getQueryBridge() {
+ if (sQueryBridge == null) {
+ sQueryBridge = new AccessibilityQueryBridge(getInstrumentation().getContext());
+ }
+ return sQueryBridge;
+ }
+
/**
* Starts the activity under tests and waits for the first accessibility
* event from that activity.
*/
private void startActivityAndWaitForFirstEvent() {
- AccessibilityQueryBridge bridge = AccessibilityQueryBridge.getInstance(
- getInstrumentation().getContext());
- bridge.perfromActionAndWaitForEvent(
+ getQueryBridge().perfromActionAndWaitForEvent(
new Runnable() {
@Override
public void run() {
@@ -328,55 +334,10 @@
}
/**
- * @return The source of the last accessibility event.
+ * @return The string for a given <code>resId</code>.
*/
- private AccessibilityNodeInfo getAwaitedAccessibilityEventSource() {
- AccessibilityQueryBridge bridge = AccessibilityQueryBridge.getInstance(
- getInstrumentation().getContext());
- AccessibilityEvent event = bridge.getAwaitedAccessibilityEvent();
- if (event != null) {
- return event.getSource();
- }
- return null;
- }
-
- private List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(AccessibilityNodeInfo root,
- String text) {
- if (root != null) {
- return root.findAccessibilityNodeInfosByText(text);
- }
- return Collections.emptyList();
- }
-
- /**
- * Finds the first accessibility info that contains text. The search starts
- * from the given <code>root</code>
- *
- * @param root Node from which to start the search.
- * @param resId Resource id of the searched text.
- * @return The node with this text or null.
- */
- private AccessibilityNodeInfo findAccessibilityNodeInfoByText(AccessibilityNodeInfo root,
- int resId) {
- return findAccessibilityNodeInfoByText(root,
- getInstrumentation().getContext().getString(resId));
- }
-
- /**
- * Finds the first accessibility info that contains text. The search starts
- * from the given <code>root</code>
- *
- * @param root Node from which to start the search.
- * @param text The searched text.
- * @return The node with this text or null.
- */
- private AccessibilityNodeInfo findAccessibilityNodeInfoByText(AccessibilityNodeInfo root,
- String text) {
- List<AccessibilityNodeInfo> nodes = findAccessibilityNodeInfosByText(root, text);
- if (nodes != null && !nodes.isEmpty()) {
- return nodes.get(0);
- }
- return null;
+ private String getString(int resId) {
+ return getInstrumentation().getContext().getString(resId);
}
/**
@@ -386,11 +347,6 @@
static class AccessibilityQueryBridge extends AccessibilityService {
/**
- * The singleton instance.
- */
- private static AccessibilityQueryBridge sInstance;
-
- /**
* Helper for connecting to the delegating accessibility service.
*/
private final AccessibilityDelegateHelper mAccessibilityDelegateHelper;
@@ -410,23 +366,6 @@
*/
private AccessibilityEventFilter mWaitedFilter;
- /**
- * Gets the {@link AccessibilityQueryBridge} singleton.
- *
- * @param context A context handle.
- * @return The mock service.
- */
- public static AccessibilityQueryBridge getInstance(Context context) {
- if (sInstance == null) {
- // since we do bind once and do not unbind from the delegating
- // service and JUnit3 does not support @BeforeTest and @AfterTest,
- // we will leak a service connection after the test but this
- // does not affect the test results and the test is twice as fast
- sInstance = new AccessibilityQueryBridge(context);
- }
- return sInstance;
- }
-
private AccessibilityQueryBridge(Context context) {
mAccessibilityDelegateHelper = new AccessibilityDelegateHelper(this);
mAccessibilityDelegateHelper.bindToDelegatingAccessibilityService(context);
@@ -446,10 +385,91 @@
}
/**
+ * Finds the first accessibility info that contains text. The search starts
+ * from the given <code>root</code>
+ *
+ * @param text The searched text.
+ * @return The node with this text or null.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByTextFromRoot(String text) {
+ List<AccessibilityNodeInfo> nodes = findAccessibilityNodeInfosByText(text);
+ if (nodes != null && !nodes.isEmpty()) {
+ return nodes.get(0);
+ }
+ return null;
+ }
+
+ /**
* @return The event that was waited for.
*/
- public AccessibilityEvent getAwaitedAccessibilityEvent() {
- return mAwaitedAccessbiliyEvent;
+ public AccessibilityNodeInfo getAwaitedAccessibilityEventSource() {
+ if (mAwaitedAccessbiliyEvent != null) {
+ return getSource(mAwaitedAccessbiliyEvent);
+ }
+ return null;
+ }
+
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
+ AccessibilityNodeInfo root = getAwaitedAccessibilityEventSource();
+ if (root != null) {
+ // Sending a node info across processes recycles
+ // it so use a clone to avoid losing state
+ AccessibilityNodeInfo rootClone = AccessibilityNodeInfo.obtain(root);
+ try {
+ return mAccessibilityDelegateHelper.getQueryConnection()
+ .findAccessibilityNodeInfosByText(rootClone, text);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ public AccessibilityNodeInfo getParent(AccessibilityNodeInfo child) {
+ try {
+ // Sending a node info across processes recycles
+ // it so use a clone to avoid losing state
+ AccessibilityNodeInfo childClone = AccessibilityNodeInfo.obtain(child);
+ return mAccessibilityDelegateHelper.getQueryConnection().getParent(childClone);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ return null;
+ }
+
+ public AccessibilityNodeInfo getChild(AccessibilityNodeInfo parent, int index) {
+ try {
+ // Sending a node info across processes recycles
+ // it so use a clone to avoid losing state
+ AccessibilityNodeInfo parentClone = AccessibilityNodeInfo.obtain(parent);
+ return mAccessibilityDelegateHelper.getQueryConnection().getChild(parentClone,
+ index);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ return null;
+ }
+
+ public boolean performAction(AccessibilityNodeInfo target, int action) {
+ try {
+ // Sending a node info across processes recycles
+ // it so use a clone to avoid losing state
+ AccessibilityNodeInfo targetClone = AccessibilityNodeInfo.obtain(target);
+ return mAccessibilityDelegateHelper.getQueryConnection().performAccessibilityAction(
+ targetClone, action);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ return false;
+ }
+
+ private AccessibilityNodeInfo getSource(AccessibilityEvent event) {
+ try {
+ return mAccessibilityDelegateHelper.getQueryConnection().getSource(event);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ return null;
}
/**