diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java index 0b4e269fd..5d89957bc 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -48,6 +48,8 @@ import java.util.StringTokenizer; */ public class MonkeySourceNetwork implements MonkeyEventSource { private static final String TAG = "MonkeyStub"; + /* The version of the monkey network protocol */ + public static final int MONKEY_NETWORK_VERSION = 2; /** * ReturnValue from the MonkeyCommand that indicates whether the @@ -95,7 +97,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { * * @param command the command line. * @param queue the command queue. - * @returs MonkeyCommandReturn indicating what happened. + * @return MonkeyCommandReturn indicating what happened. */ MonkeyCommandReturn translateCommand(List command, CommandQueue queue); } @@ -234,7 +236,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { * Get an integer keycode value from a given keyname. * * @param keyName the key name to get the code for - * @returns the integer keycode value, or -1 on error. + * @return the integer keycode value, or -1 on error. */ private static int getKeyCode(String keyName) { int keyCode = -1; @@ -408,6 +410,11 @@ public class MonkeySourceNetwork implements MonkeyEventSource { COMMAND_MAP.put("type", new TypeCommand()); COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand()); COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand()); + COMMAND_MAP.put("listviews", new MonkeySourceNetworkViews.ListViewsCommand()); + COMMAND_MAP.put("queryview", new MonkeySourceNetworkViews.QueryViewCommand()); + COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand()); + COMMAND_MAP.put("getviewswithtext", + new MonkeySourceNetworkViews.GetViewsWithTextCommand()); } // QUIT command @@ -444,7 +451,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { /** * Get the next queued event to excecute. * - * @returns the next event, or null if there aren't any more. + * @return the next event, or null if there aren't any more. */ public MonkeyEvent getNextQueuedEvent() { return queuedEvents.poll(); @@ -477,8 +484,12 @@ public class MonkeySourceNetwork implements MonkeyEventSource { */ private void startServer() throws IOException { clientSocket = serverSocket.accept(); - // At this point, we have a client connected. Wake the device - // up in preparation for doing some commands. + // At this point, we have a client connected. + // Attach the accessibility listeners so that we can start receiving + // view events. Do this before wake so we can catch the wake event + // if possible. + MonkeySourceNetworkViews.setup(); + // Wake the device up in preparation for doing some commands. wake(); input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); @@ -501,7 +512,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { * charaters with their real values. * * @param input the string to do replacement on. - * @returns the results with the characters replaced. + * @return the results with the characters replaced. */ private static String replaceQuotedChars(String input) { return input.replace("\\\"", "\""); @@ -559,8 +570,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { if (parts.size() > 0) { MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); if (command != null) { - MonkeyCommandReturn ret = command.translateCommand(parts, - commandQueue); + MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue); if (ret.wasSuccessful()) { if (ret.hasMessage()) { returnOk(ret.getMessage()); diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java index e9890ad2b..eea00c75c 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkVars.java @@ -159,6 +159,11 @@ public class MonkeySourceNetworkVars { return Long.toString(System.currentTimeMillis()); } }); + VAR_MAP.put("monkey.version", new VarGetter() { + public String get() { + return Integer.toString(MonkeySourceNetwork.MONKEY_NETWORK_VERSION); + } + }); } /** diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java new file mode 100644 index 000000000..f96f13315 --- /dev/null +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java @@ -0,0 +1,614 @@ +/* + * Copyright 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 com.android.commands.monkey; + +import static com.android.commands.monkey.MonkeySourceNetwork.EARG; + +import android.accessibilityservice.IAccessibilityServiceConnection; +import android.accessibilityservice.IEventListener; +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.Context; +import android.content.pm.IPackageManager; +import android.content.pm.ApplicationInfo; +import android.graphics.Rect; +import android.os.ServiceManager; +import android.os.RemoteException; +import android.util.Log; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.IAccessibilityManager; +import android.view.accessibility.AccessibilityEvent; + +import dalvik.system.DexClassLoader; + +import com.android.commands.monkey.MonkeySourceNetwork.CommandQueue; +import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommand; +import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommandReturn; + +import java.lang.reflect.Field; +import java.util.concurrent.atomic.AtomicReference; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + + +/** + * 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 volatile AtomicReference sLastAccessibilityEvent + = new AtomicReference(); + protected static IAccessibilityServiceConnection sConnection; + private static IPackageManager sPm = + IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + private static Map> sClassMap = new HashMap>(); + + private static final String REMOTE_ERROR = + "Unable to retrieve application info from PackageManager"; + private static final String CLASS_NOT_FOUND = "Error retrieving class information"; + private static final String NO_ACCESSIBILITY_EVENT = "No accessibility event has occured yet"; + private static final String NO_NODE = "Node with given ID does not exist"; + private static final String NO_CONNECTION = "Failed to connect to AccessibilityService, " + + "try restarting Monkey"; + + private static final Map COMMAND_MAP = + new HashMap(); + + /* Interface for view queries */ + private static interface ViewIntrospectionCommand { + /** + * Get the response to the query + * @return the response to the query + */ + public MonkeyCommandReturn query(AccessibilityNodeInfo node, List args); + } + + static { + COMMAND_MAP.put("getlocation", new GetLocation()); + COMMAND_MAP.put("gettext", new GetText()); + COMMAND_MAP.put("getclass", new GetClass()); + COMMAND_MAP.put("getchecked", new GetChecked()); + COMMAND_MAP.put("getenabled", new GetEnabled()); + COMMAND_MAP.put("getselected", new GetSelected()); + COMMAND_MAP.put("setselected", new SetSelected()); + COMMAND_MAP.put("getfocused", new GetFocused()); + COMMAND_MAP.put("setfocused", new SetFocused()); + COMMAND_MAP.put("getparent", new GetParent()); + COMMAND_MAP.put("getchildren", new GetChildren()); + COMMAND_MAP.put("getaccessibilityids", new GetAccessibilityIds()); + } + + /* This registers our listener with accessibility services, and gives us a connection object */ + private static IAccessibilityServiceConnection getConnection() throws RemoteException { + IEventListener listener = new IEventListener.Stub() { + public void setConnection(IAccessibilityServiceConnection connection) + throws RemoteException { + AccessibilityServiceInfo info = new AccessibilityServiceInfo(); + info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; + info.notificationTimeout = 0; + info.flags = AccessibilityServiceInfo.DEFAULT; + connection.setServiceInfo(info); + } + + public void onInterrupt() {} + + public void onAccessibilityEvent(AccessibilityEvent event) { + sLastAccessibilityEvent.set(AccessibilityEvent.obtain(event)); + } + }; + IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); + return manager.registerEventListener(listener); + } + + /** + * Registers the event listener for AccessibilityEvents. + * Also sets up a communication connection so we can query the + * accessibility service. + */ + public static void setup() { + try { + sConnection = getConnection(); + } catch (RemoteException re) { + Log.e(TAG,"Remote Exception encountered when" + + " attempting to connect to Accessibility Service"); + } + } + + + /** + * Get the ID class for the given package. + * This will cause issues if people reload a package with different + * resource identifiers, but don't restart the Monkey server. + * + * @param packageName The package that we want to retrieve the ID class for + * @return The ID class for the given package + */ + private static Class getIdClass(String packageName, String sourceDir) + throws RemoteException, ClassNotFoundException { + // This kind of reflection is expensive, so let's only do it + // if we need to + Class klass = sClassMap.get(packageName); + if (klass == null) { + DexClassLoader classLoader = new DexClassLoader( + sourceDir, "/data/local/tmp", + null, ClassLoader.getSystemClassLoader()); + klass = classLoader.loadClass(packageName + ".R$id"); + sClassMap.put(packageName, klass); + } + return klass; + } + + private static String getPositionFromNode(AccessibilityNodeInfo node) { + Rect nodePosition = new Rect(); + node.getBoundsInScreen(nodePosition); + StringBuilder positions = new StringBuilder(); + positions.append(nodePosition.left).append(" ").append(nodePosition.top); + positions.append(" ").append(nodePosition.right-nodePosition.left).append(" "); + positions.append(nodePosition.bottom-nodePosition.top); + return positions.toString(); + } + + + /** + * Converts a resource identifier into it's generated integer ID + * + * @param stringId the string identifier + * @return the generated integer identifier. + */ + private static int getId(String stringId, AccessibilityEvent event) + throws MonkeyViewException { + try { + AccessibilityNodeInfo node = event.getSource(); + String packageName = node.getPackageName().toString(); + ApplicationInfo appInfo = sPm.getApplicationInfo(packageName, 0); + Class klass; + klass = getIdClass(packageName, appInfo.sourceDir); + return klass.getField(stringId).getInt(null); + } catch (RemoteException e) { + throw new MonkeyViewException(REMOTE_ERROR); + } catch (ClassNotFoundException e){ + throw new MonkeyViewException(e.getMessage()); + } catch (NoSuchFieldException e){ + throw new MonkeyViewException("No such node with given id"); + } catch (IllegalAccessException e){ + throw new MonkeyViewException("Private identifier"); + } catch (NullPointerException e) { + // AccessibilityServiceConnection throws a NullPointerException if you hand it + // an ID that doesn't exist onscreen + throw new MonkeyViewException("No node with given id exists onscreen"); + } + } + + private static AccessibilityNodeInfo getNodeByAccessibilityIds( + String windowString, String viewString) throws RemoteException { + int windowId = Integer.parseInt(windowString); + int viewId = Integer.parseInt(viewString); + return sConnection.findAccessibilityNodeInfoByAccessibilityId(windowId, viewId); + } + + private static AccessibilityNodeInfo getNodeByViewId(String viewId, AccessibilityEvent event) + throws RemoteException, MonkeyViewException { + int id = getId(viewId, event); + return sConnection.findAccessibilityNodeInfoByViewIdInActiveWindow(id); + } + + /** + * Command to list all possible view ids for the given application. + * This lists all view ids regardless if they are on screen or not. + */ + public static class ListViewsCommand implements MonkeyCommand { + //listviews + public MonkeyCommandReturn translateCommand(List command, + CommandQueue queue) { + AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + 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 */ + if (node == null) { + return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); + } + String packageName = node.getPackageName().toString(); + try{ + Class klass; + ApplicationInfo appInfo = sPm.getApplicationInfo(packageName, 0); + klass = getIdClass(packageName, appInfo.sourceDir); + StringBuilder fieldBuilder = new StringBuilder(); + Field[] fields = klass.getFields(); + for (Field field : fields) { + fieldBuilder.append(field.getName() + " "); + } + return new MonkeyCommandReturn(true, fieldBuilder.toString()); + } catch (RemoteException e){ + return new MonkeyCommandReturn(false, REMOTE_ERROR); + } catch (ClassNotFoundException e){ + return new MonkeyCommandReturn(false, CLASS_NOT_FOUND); + } + } + } + + /** + * A command that allows for querying of views. It takes an id type, the requisite ids, + * and the command for querying the view. + */ + public static class QueryViewCommand implements MonkeyCommand { + //queryview [id type] [id(s)] [command] + //queryview viewid button1 gettext + //queryview accessibilityids 12 5 getparent + public MonkeyCommandReturn translateCommand(List command, + CommandQueue queue) { + if (command.size() > 2) { + if (sConnection == null) { + return new MonkeyCommandReturn(false, NO_CONNECTION); + } + AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + if (lastEvent == null) { + return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); + } + lastEvent.setSealed(true); + String idType = command.get(1); + AccessibilityNodeInfo node; + String viewQuery; + List args; + if ("viewid".equals(idType)) { + try { + node = getNodeByViewId(command.get(2), lastEvent); + viewQuery = command.get(3); + args = command.subList(4, command.size()); + } catch (RemoteException e) { + return new MonkeyCommandReturn(false, REMOTE_ERROR); + } catch (MonkeyViewException e) { + return new MonkeyCommandReturn(false, e.getMessage()); + } + } else if (idType.equals("accessibilityids")) { + try { + node = getNodeByAccessibilityIds(command.get(2), command.get(3)); + viewQuery = command.get(4); + args = command.subList(5, command.size()); + } catch (RemoteException e) { + return new MonkeyCommandReturn(false, REMOTE_ERROR); + } catch (NumberFormatException e) { + return EARG; + } + } else { + return EARG; + } + if (node == null) { + return new MonkeyCommandReturn(false, NO_NODE); + } + ViewIntrospectionCommand getter = COMMAND_MAP.get(viewQuery); + if (getter != null) { + return getter.query(node, args); + } else { + return EARG; + } + } + return EARG; + } + } + + /** + * A command that returns the accessibility ids of the root view. + */ + public static class GetRootViewCommand implements MonkeyCommand { + // getrootview + public MonkeyCommandReturn translateCommand(List command, + CommandQueue queue) { + AccessibilityEvent lastEvent = sLastAccessibilityEvent.get(); + if (lastEvent == null) { + return new MonkeyCommandReturn(false, NO_ACCESSIBILITY_EVENT); + } + lastEvent.setSealed(true); + AccessibilityNodeInfo node = lastEvent.getSource(); + return (new GetAccessibilityIds()).query(node, new ArrayList()); + } + } + + /** + * A command that returns the accessibility ids of the views that contain the given text. + * It takes a string of text and returns the accessibility ids of the nodes that contain the + * text as a list of integers separated by spaces. + */ + public static class GetViewsWithTextCommand implements MonkeyCommand { + // getviewswithtext [text] + // getviewswithtext "some text here" + public MonkeyCommandReturn translateCommand(List command, + CommandQueue queue) { + if (sConnection == null) { + return new MonkeyCommandReturn(false, NO_CONNECTION); + } + if (command.size() == 2) { + StringBuilder logs = new StringBuilder(); + String text = command.get(1); + List nodes; + try { + nodes = sConnection.findAccessibilityNodeInfosByViewTextInActiveWindow(text); + } catch (RemoteException e) { + return new MonkeyCommandReturn(false, REMOTE_ERROR); + } + if (nodes == null) { + return new MonkeyCommandReturn(true, ""); + } + ViewIntrospectionCommand idGetter = new GetAccessibilityIds(); + List emptyArgs = new ArrayList(); + StringBuilder ids = new StringBuilder(); + for (AccessibilityNodeInfo node : nodes) { + MonkeyCommandReturn result = idGetter.query(node, emptyArgs); + if (!result.wasSuccessful()){ + return result; + } + ids.append(result.getMessage()).append(" "); + } + return new MonkeyCommandReturn(true, ids.toString()); + } + return EARG; + } + } + + /** + * Command to retrieve the location of the given node. + * Returns the x, y, width and height of the view, separated by spaces. + */ + public static class GetLocation implements ViewIntrospectionCommand { + //queryview [id type] [id] getlocation + //queryview viewid button1 getlocation + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + Rect nodePosition = new Rect(); + node.getBoundsInScreen(nodePosition); + StringBuilder positions = new StringBuilder(); + positions.append(nodePosition.left).append(" ").append(nodePosition.top); + positions.append(" ").append(nodePosition.right-nodePosition.left).append(" "); + positions.append(nodePosition.bottom-nodePosition.top); + return new MonkeyCommandReturn(true, positions.toString()); + } + return EARG; + } + } + + + /** + * Command to retrieve the text of the given node + */ + public static class GetText implements ViewIntrospectionCommand { + //queryview [id type] [id] gettext + //queryview viewid button1 gettext + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + if (node.isPassword()){ + return new MonkeyCommandReturn(false, "Node contains a password"); + } + return new MonkeyCommandReturn(true, node.getText().toString()); + } + return EARG; + } + } + + + /** + * Command to retrieve the class name of the given node + */ + public static class GetClass implements ViewIntrospectionCommand { + //queryview [id type] [id] getclass + //queryview viewid button1 getclass + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + return new MonkeyCommandReturn(true, node.getClassName().toString()); + } + return EARG; + } + } + /** + * Command to retrieve the checked status of the given node + */ + public static class GetChecked implements ViewIntrospectionCommand { + //queryview [id type] [id] getchecked + //queryview viewid button1 getchecked + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + return new MonkeyCommandReturn(true, Boolean.toString(node.isChecked())); + } + return EARG; + } + } + + /** + * Command to retrieve whether the given node is enabled + */ + public static class GetEnabled implements ViewIntrospectionCommand { + //queryview [id type] [id] getenabled + //queryview viewid button1 getenabled + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + return new MonkeyCommandReturn(true, Boolean.toString(node.isEnabled())); + } + return EARG; + } + } + + /** + * Command to retrieve whether the given node is selected + */ + public static class GetSelected implements ViewIntrospectionCommand { + //queryview [id type] [id] getselected + //queryview viewid button1 getselected + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + return new MonkeyCommandReturn(true, Boolean.toString(node.isSelected())); + } + return EARG; + } + } + + /** + * Command to set the selected status of the given node. Takes a boolean value as its only + * argument. + */ + public static class SetSelected implements ViewIntrospectionCommand { + //queryview [id type] [id] setselected [boolean] + //queryview viewid button1 setselected true + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 1) { + boolean actionPerformed; + if (Boolean.valueOf(args.get(0))) { + actionPerformed = node.performAction(AccessibilityNodeInfo.ACTION_SELECT); + } else if (!Boolean.valueOf(args.get(0))) { + actionPerformed = + node.performAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); + } else { + return EARG; + } + return new MonkeyCommandReturn(actionPerformed); + } + return EARG; + } + } + + /** + * Command to get whether the given node is focused. + */ + public static class GetFocused implements ViewIntrospectionCommand { + //queryview [id type] [id] getfocused + //queryview viewid button1 getfocused + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + return new MonkeyCommandReturn(true, Boolean.toString(node.isFocused())); + } + return EARG; + } + } + + /** + * Command to set the focus status of the given node. Takes a boolean value + * as its only argument. + */ + public static class SetFocused implements ViewIntrospectionCommand { + //queryview [id type] [id] setfocused [boolean] + //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))) { + actionPerformed = node.performAction(AccessibilityNodeInfo.ACTION_FOCUS); + } else if (!Boolean.valueOf(args.get(0))) { + actionPerformed = node.performAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); + } else { + return EARG; + } + return new MonkeyCommandReturn(actionPerformed); + } + return EARG; + } + } + + /** + * Command to get the accessibility ids of the given node. Returns the accessibility ids as a + * space separated pair of integers with window id coming first, followed by the accessibility + * view id. + */ + public static class GetAccessibilityIds implements ViewIntrospectionCommand { + //queryview [id type] [id] getaccessibilityids + //queryview viewid button1 getaccessibilityids + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + int viewId; + try { + Class klass = node.getClass(); + Field field = klass.getDeclaredField("mAccessibilityViewId"); + field.setAccessible(true); + viewId = ((Integer) field.get(node)).intValue(); + } catch (NoSuchFieldException e) { + return new MonkeyCommandReturn(false, NO_NODE); + } catch (IllegalAccessException e) { + return new MonkeyCommandReturn(false, "Access exception"); + } + String ids = node.getWindowId() + " " + viewId; + return new MonkeyCommandReturn(true, ids); + } + return EARG; + } + } + + /** + * Command to get the accessibility ids of the parent of the given node. Returns the + * accessibility ids as a space separated pair of integers with window id coming first followed + * by the accessibility view id. + */ + public static class GetParent implements ViewIntrospectionCommand { + //queryview [id type] [id] getparent + //queryview viewid button1 getparent + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + AccessibilityNodeInfo parent = node.getParent(); + if (parent == null) { + return new MonkeyCommandReturn(false, "Given node has no parent"); + } + return (new GetAccessibilityIds()).query(parent, new ArrayList()); + } + return EARG; + } + } + + /** + * Command to get the accessibility ids of the children of the given node. Returns the + * children's ids as a space separated list of integer pairs. Each of the pairs consists of the + * window id, followed by the accessibility id. + */ + public static class GetChildren implements ViewIntrospectionCommand { + //queryview [id type] [id] getchildren + //queryview viewid button1 getchildren + public MonkeyCommandReturn query(AccessibilityNodeInfo node, + List args) { + if (args.size() == 0) { + ViewIntrospectionCommand idGetter = new GetAccessibilityIds(); + List emptyArgs = new ArrayList(); + StringBuilder ids = new StringBuilder(); + int totalChildren = node.getChildCount(); + for (int i = 0; i < totalChildren; i++) { + MonkeyCommandReturn result = idGetter.query(node.getChild(i), emptyArgs); + if (!result.wasSuccessful()) { + return result; + } else { + ids.append(result.getMessage()).append(" "); + } + } + return new MonkeyCommandReturn(true, ids.toString()); + } + return EARG; + } + } +} diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyViewException.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyViewException.java new file mode 100644 index 000000000..8c55dd416 --- /dev/null +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyViewException.java @@ -0,0 +1,35 @@ +/* + * 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 com.android.commands.monkey; + +public class MonkeyViewException extends java.lang.Exception { + /** + * Constructs a MonkeyViewException object + */ + public MonkeyViewException() { + super(); + } + + /** + * Constructs a MonkeyViewException object + * + * @param message the error message + */ + public MonkeyViewException(String message) { + super(message); + } + +}