diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt index 3ec6298f0..1a1ad9c3c 100644 --- a/cmds/monkey/README.NETWORK.txt +++ b/cmds/monkey/README.NETWORK.txt @@ -77,6 +77,16 @@ wake This command will wake the device up from sleep and allow user input. +tap x y +The tap command is a shortcut for the touch command. It will +automatically send both the up and the down event. + +press keycode + +The press command is a shortcut for the key command. The keycode +paramter works just like the key command and will automatically send +both the up and the down event. + OTHER NOTES There are some convenience features added to allow running without diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java index b444dd340..63e226c7d 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -36,7 +36,9 @@ import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.LinkedList; import java.util.List; +import java.util.Queue; import java.util.StringTokenizer; /** @@ -47,7 +49,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static final String TAG = "MonkeyStub"; private interface MonkeyCommand { - MonkeyEvent translateCommand(List command); + MonkeyEvent translateCommand(List command, CommandQueue queue); } /** @@ -56,7 +58,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static class FlipCommand implements MonkeyCommand { // flip open // flip closed - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() > 1) { String direction = command.get(1); if ("open".equals(direction)) { @@ -77,7 +80,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // touch down 120 120 // touch move 140 140 // touch up 140 140 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 4) { String actionName = command.get(1); int x = 0; @@ -120,7 +124,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // trackball [dx] [dy] // trackball 1 0 -- move right // trackball -1 0 -- move left - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 3) { int dx = 0; int dy = 0; @@ -147,29 +152,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // key [down|up] [keycode] // key down 82 // key up 82 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 3) { - int keyCode = -1; - String keyName = command.get(2); - try { - keyCode = Integer.parseInt(keyName); - } catch (NumberFormatException e) { - // Ok, it wasn't a number, see if we have a - // keycode name for it - keyCode = MonkeySourceRandom.getKeyCode(keyName); - if (keyCode == -1) { - // OK, one last ditch effort to find a match. - // Build the KEYCODE_STRING from the string - // we've been given and see if that key - // exists. This would allow you to do "key - // down menu", for example. - keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); - if (keyCode == -1) { - // Ok, you gave us something bad. - Log.e(TAG, "Can't find keyname: " + keyName); - return null; - } - } + int keyCode = getKeyCode(command.get(2)); + if (keyCode < 0) { + // Ok, you gave us something bad. + Log.e(TAG, "Can't find keyname: " + command.get(2)); + return null; } Log.d(TAG, "keycode: " + keyCode); int action = -1; @@ -188,12 +178,39 @@ 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. + */ + private static int getKeyCode(String keyName) { + int keyCode = -1; + try { + keyCode = Integer.parseInt(keyName); + } catch (NumberFormatException e) { + // Ok, it wasn't a number, see if we have a + // keycode name for it + keyCode = MonkeySourceRandom.getKeyCode(keyName); + if (keyCode == -1) { + // OK, one last ditch effort to find a match. + // Build the KEYCODE_STRING from the string + // we've been given and see if that key + // exists. This would allow you to do "key + // down menu", for example. + keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); + } + } + return keyCode; + } + /** * Command to put the Monkey to sleep. */ private static class SleepCommand implements MonkeyCommand { // sleep 2000 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 2) { int sleep = -1; String sleepStr = command.get(1); @@ -213,14 +230,71 @@ public class MonkeySourceNetwork implements MonkeyEventSource { */ private static class WakeCommand implements MonkeyCommand { // wake - public MonkeyEvent translateCommand(List command) { - if (wake()) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (!wake()) { return null; } return new MonkeyNoopEvent(); } } + /** + * Command to "tap" at a location (Sends a down and up touch + * event). + */ + private static class TapCommand implements MonkeyCommand { + // tap x y + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (command.size() == 3) { + int x = 0; + int y = 0; + try { + x = Integer.parseInt(command.get(1)); + y = Integer.parseInt(command.get(2)); + } catch (NumberFormatException e) { + // Ok, it wasn't a number + Log.e(TAG, "Got something that wasn't a number", e); + return null; + } + + queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + -1, MotionEvent.ACTION_DOWN, + x, y, 0)); + queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + -1, MotionEvent.ACTION_UP, + x, y, 0)); + return new MonkeyNoopEvent(); + } + return null; + } + } + + /** + * Command to "press" a buttons (Sends an up and down key event.) + */ + private static class PressCommand implements MonkeyCommand { + // press keycode + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (command.size() == 2) { + int keyCode = getKeyCode(command.get(1)); + if (keyCode < 0) { + // Ok, you gave us something bad. + Log.e(TAG, "Can't find keyname: " + command.get(1)); + return null; + } + + queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode)); + queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode)); + return new MonkeyNoopEvent(); + + } + return null; + } + } + /** * Force the device to wake up. * @@ -249,6 +323,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { COMMAND_MAP.put("key", new KeyCommand()); COMMAND_MAP.put("sleep", new SleepCommand()); COMMAND_MAP.put("wake", new WakeCommand()); + COMMAND_MAP.put("tap", new TapCommand()); + COMMAND_MAP.put("press", new PressCommand()); } // QUIT command @@ -258,6 +334,39 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static final String OK = "OK"; private static final String ERROR = "ERROR"; + private static interface CommandQueue { + /** + * Enqueue an event to be returned later. This allows a + * command to return multiple events. Commands using the + * command queue still have to return a valid event from their + * translateCommand method. The returned command will be + * executed before anything put into the queue. + * + * @param e the event to be enqueued. + */ + public void enqueueEvent(MonkeyEvent e); + }; + + // Queue of Events to be processed. This allows commands to push + // multiple events into the queue to be processed. + private static class CommandQueueImpl implements CommandQueue{ + private final Queue queuedEvents = new LinkedList(); + + public void enqueueEvent(MonkeyEvent e) { + queuedEvents.offer(e); + } + + /** + * Get the next queued event to excecute. + * + * @returns the next event, or null if there aren't any more. + */ + public MonkeyEvent getNextQueuedEvent() { + return queuedEvents.poll(); + } + }; + + private final CommandQueueImpl commandQueue = new CommandQueueImpl(); private final int port; private BufferedReader input; @@ -345,7 +454,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { if (parts.size() > 0) { MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); if (command != null) { - return command.translateCommand(parts); + return command.translateCommand(parts, + commandQueue); } return null; } @@ -366,6 +476,15 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // Now, get the next command. This call may block, but that's OK try { while (true) { + // Check to see if we have any events queued up. If + // we do, use those until we have no more. Then get + // more input from the user. + MonkeyEvent queuedEvent = commandQueue.getNextQueuedEvent(); + if (queuedEvent != null) { + // dispatch the event + return queuedEvent; + } + String command = input.readLine(); if (command == null) { Log.d(TAG, "Connection dropped.");