From 4ce026b4b196e24ee125247843697680fb8e207e Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Mon, 23 Jan 2012 18:14:56 -0800 Subject: [PATCH] Updating the monkey to use a dedicated UI test bridge. 1. The MonkeySourceNetworkViews was registering a raw event listener for accessibility events and hence perform connection and cache management in similar way to an AccessibilityService. This is fragile and requires the Monkey implementor to know internal framework stuff. Now the functionality required by the class is accessed via the new UiTestAutomationBridge. Change-Id: Idd5820e42a4b4dfc1d9eed8977ec5ccd96485daa --- .../monkey/MonkeySourceNetworkViews.java | 131 ++++-------------- 1 file changed, 25 insertions(+), 106 deletions(-) diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java index c2a109317..659ea8a35 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java @@ -18,49 +18,33 @@ package com.android.commands.monkey; import static com.android.commands.monkey.MonkeySourceNetwork.EARG; -import android.accessibilityservice.IAccessibilityServiceConnection; -import android.accessibilityservice.IEventListener; -import android.content.Context; -import android.content.pm.IPackageManager; +import android.accessibilityservice.UiTestAutomationBridge; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.graphics.Rect; -import android.os.ServiceManager; import android.os.RemoteException; -import android.os.SystemClock; -import android.util.Log; -import android.view.accessibility.AccessibilityInteractionClient; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.IAccessibilityManager; +import android.os.ServiceManager; import android.view.accessibility.AccessibilityEvent; - -import dalvik.system.DexClassLoader; +import android.view.accessibility.AccessibilityNodeInfo; import com.android.commands.monkey.MonkeySourceNetwork.CommandQueue; import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommand; import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommandReturn; +import dalvik.system.DexClassLoader; + import java.lang.reflect.Field; -import java.util.concurrent.atomic.AtomicReference; -import java.util.Map; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.ArrayList; - +import java.util.Map; /** * Utility class that enables Monkey to perform view introspection when issued Monkey Network * Script commands over the network. */ public class MonkeySourceNetworkViews { - private static final String TAG = "MonkeyViews"; - - private static final int TIMEOUT_REGISTER_EVENT_LISTENER = 2000; - - private static final int NO_ID = -1; - - private static volatile AtomicReference sLastAccessibilityEvent - = new AtomicReference(); - protected static int sConnectionId; + protected static UiTestAutomationBridge sUiTestAutomationBridge; private static IPackageManager sPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); private static Map> sClassMap = new HashMap>(); @@ -100,78 +84,16 @@ public class MonkeySourceNetworkViews { COMMAND_MAP.put("getaccessibilityids", new GetAccessibilityIds()); } - private static int getConnection() throws RemoteException { - if (sConnectionId != NO_ID) { - return sConnectionId; - } - IEventListener listener = new IEventListener.Stub() { - public void setConnection(IAccessibilityServiceConnection connection, - int connectionId) { - sConnectionId = connectionId; - if (connection != null) { - AccessibilityInteractionClient.getInstance().addConnection(connectionId, - connection); - } else { - AccessibilityInteractionClient.getInstance().removeConnection(connectionId); - } - synchronized (MonkeySourceNetworkViews.class) { - notifyAll(); - } - } - - public void onInterrupt() {} - - public void onAccessibilityEvent(AccessibilityEvent event) { - Log.d(TAG, "Accessibility Event"); - sLastAccessibilityEvent.set(AccessibilityEvent.obtain(event)); - synchronized (MonkeySourceNetworkViews.class) { - notifyAll(); - } - } - }; - - IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( - ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); - - final long beginTime = SystemClock.uptimeMillis(); - synchronized (MonkeySourceNetworkViews.class) { - manager.registerEventListener(listener); - while (true) { - if (sConnectionId != NO_ID) { - return sConnectionId; - } - final long elapsedTime = (SystemClock.uptimeMillis() - beginTime); - final long remainingTime = TIMEOUT_REGISTER_EVENT_LISTENER - elapsedTime; - if (remainingTime <= 0) { - if (sConnectionId == NO_ID) { - throw new IllegalStateException("Cound not register IEventListener."); - } - return sConnectionId; - } - try { - MonkeySourceNetworkViews.class.wait(remainingTime); - } catch (InterruptedException ie) { - /* ignore */ - } - } - } - } - /** * Registers the event listener for AccessibilityEvents. * Also sets up a communication connection so we can query the * accessibility service. */ public static void setup() { - try { - sConnectionId = getConnection(); - } catch (RemoteException re) { - Log.e(TAG,"Remote Exception encountered when" - + " attempting to connect to Accessibility Service"); - } + sUiTestAutomationBridge = new UiTestAutomationBridge(); + sUiTestAutomationBridge.connect(); } - /** * Get the ID class for the given package. * This will cause issues if people reload a package with different @@ -181,7 +103,7 @@ public class MonkeySourceNetworkViews { * @return The ID class for the given package */ private static Class getIdClass(String packageName, String sourceDir) - throws RemoteException, ClassNotFoundException { + throws ClassNotFoundException { // This kind of reflection is expensive, so let's only do it // if we need to Class klass = sClassMap.get(packageName); @@ -240,15 +162,15 @@ public class MonkeySourceNetworkViews { String windowString, String viewString) { int windowId = Integer.parseInt(windowString); int viewId = Integer.parseInt(viewString); - return AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByAccessibilityId(sConnectionId, windowId, viewId); + return sUiTestAutomationBridge.findAccessibilityNodeInfoByAccessibilityId(windowId, + viewId); } private static AccessibilityNodeInfo getNodeByViewId(String viewId, AccessibilityEvent event) throws MonkeyViewException { int id = getId(viewId, event); - return AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, id); + return sUiTestAutomationBridge.findAccessibilityNodeInfoByViewId( + UiTestAutomationBridge.ACTIVE_WINDOW_ID, UiTestAutomationBridge.ROOT_NODE_ID, id); } /** @@ -259,11 +181,10 @@ public class MonkeySourceNetworkViews { //listviews public MonkeyCommandReturn translateCommand(List command, CommandQueue queue) { - AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + AccessibilityEvent lastEvent = sUiTestAutomationBridge.getLastAccessibilityEvent(); if (lastEvent == null) { return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); } - lastEvent.setSealed(true); AccessibilityNodeInfo node = lastEvent.getSource(); /* Occasionally the API will generate an event with no source, which is essentially the * same as it generating no event at all */ @@ -300,14 +221,13 @@ public class MonkeySourceNetworkViews { public MonkeyCommandReturn translateCommand(List command, CommandQueue queue) { if (command.size() > 2) { - if (sConnectionId < 0) { + if (!sUiTestAutomationBridge.isConnected()) { return new MonkeyCommandReturn(false, NO_CONNECTION); } - AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + AccessibilityEvent lastEvent = sUiTestAutomationBridge.getLastAccessibilityEvent(); if (lastEvent == null) { return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); } - lastEvent.setSealed(true); String idType = command.get(1); AccessibilityNodeInfo node; String viewQuery; @@ -352,11 +272,10 @@ public class MonkeySourceNetworkViews { // getrootview public MonkeyCommandReturn translateCommand(List command, CommandQueue queue) { - AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + AccessibilityEvent lastEvent = sUiTestAutomationBridge.getLastAccessibilityEvent(); if (lastEvent == null) { return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); } - lastEvent.setSealed(true); AccessibilityNodeInfo node = lastEvent.getSource(); return (new GetAccessibilityIds()).query(node, new ArrayList()); } @@ -372,13 +291,14 @@ public class MonkeySourceNetworkViews { // getviewswithtext "some text here" public MonkeyCommandReturn translateCommand(List command, CommandQueue queue) { - if (sConnectionId < 0) { + if (!sUiTestAutomationBridge.isConnected()) { return new MonkeyCommandReturn(false, NO_CONNECTION); } if (command.size() == 2) { String text = command.get(1); - List nodes = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId, text); + List nodes = sUiTestAutomationBridge + .findAccessibilityNodeInfosByText(UiTestAutomationBridge.ACTIVE_WINDOW_ID, + UiTestAutomationBridge.ROOT_NODE_ID, text); ViewIntrospectionCommand idGetter = new GetAccessibilityIds(); List emptyArgs = new ArrayList(); StringBuilder ids = new StringBuilder(); @@ -550,7 +470,6 @@ public class MonkeySourceNetworkViews { //queryview viewid button1 setfocused false public MonkeyCommandReturn query(AccessibilityNodeInfo node, List args) { - node.setSealed(true); if (args.size() == 1) { boolean actionPerformed; if (Boolean.valueOf(args.get(0))) { @@ -579,7 +498,7 @@ public class MonkeySourceNetworkViews { if (args.size() == 0) { int viewId; try { - Class klass = node.getClass(); + Class klass = node.getClass(); Field field = klass.getDeclaredField("mAccessibilityViewId"); field.setAccessible(true); viewId = ((Integer) field.get(node)).intValue();