Merge change 21527 into donut

* changes:
  Add getvar and listvar commands to monkey to allow inspection of properties on the device.
This commit is contained in:
Android (Google) Code Review
2009-08-17 12:07:36 -07:00
4 changed files with 393 additions and 81 deletions

View File

@@ -27,14 +27,20 @@ COMMAND LIST
Individual commands are separated by newlines. The Monkey will
respond to every command with a line starting with OK for commands
that executed without a problem, or a line starting with ERROR for
commands that had problems being run. The Monkey may decide to return
more information about command execution. That information would come
on the same line after the OK or ERROR. A possible example:
commands that had problems being run. For commands that return a
value, that value is returned on the same line as the OK or ERROR
response. The value is everything after (but not include) the colon
on that line. For ERROR values, this could be a message indicating
what happened. A possible example:
key down menu
OK
touch monkey
ERROR: monkey not a number
getvar sdk
OK: donut
getvar foo
ERROR: no such var
The complete list of commands follows:
@@ -92,6 +98,16 @@ type string
This command will simulate a user typing the given string on the
keyboard by generating the proper KeyEvents.
listvar
This command lists all the vars that the monkey knows about. They are
returned as a whitespace separated list.
getvar varname
This command returns the value of the given var. listvar can be used
to find out what vars are supported.
quit
Fully quit the monkey and accept no new sessions.

View File

@@ -135,6 +135,10 @@ public class Monkey {
MonkeyEventSource mEventSource;
private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
// information on the current activity.
public static Intent currentIntent;
public static String currentPackage;
/**
* Monitor operations happening in the system.
*/
@@ -145,6 +149,8 @@ public class Monkey {
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
+ " start of " + intent + " in package " + pkg);
}
currentPackage = pkg;
currentIntent = intent;
return allow;
}
@@ -154,9 +160,10 @@ public class Monkey {
if (!allow) {
if (mVerbose > 0) {
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
+ " resume of package " + pkg);
+ " resume of package " + pkg);
}
}
currentPackage = pkg;
return allow;
}

View File

@@ -49,8 +49,55 @@ import java.util.StringTokenizer;
public class MonkeySourceNetwork implements MonkeyEventSource {
private static final String TAG = "MonkeyStub";
private interface MonkeyCommand {
MonkeyEvent translateCommand(List<String> command, CommandQueue queue);
/**
* ReturnValue from the MonkeyCommand that indicates whether the
* command was sucessful or not.
*/
public static class MonkeyCommandReturn {
private final boolean success;
private final String message;
public MonkeyCommandReturn(boolean success) {
this.success = success;
this.message = null;
}
public MonkeyCommandReturn(boolean success,
String message) {
this.success = success;
this.message = message;
}
boolean hasMessage() {
return message != null;
}
String getMessage() {
return message;
}
boolean wasSuccessful() {
return success;
}
}
public final static MonkeyCommandReturn OK = new MonkeyCommandReturn(true);
public final static MonkeyCommandReturn ERROR = new MonkeyCommandReturn(false);
public final static MonkeyCommandReturn EARG = new MonkeyCommandReturn(false,
"Invalid Argument");
/**
* Interface that MonkeyCommands must implement.
*/
public interface MonkeyCommand {
/**
* Translate the command line into a sequence of MonkeyEvents.
*
* @param command the command line.
* @param queue the command queue.
* @returs MonkeyCommandReturn indicating what happened.
*/
MonkeyCommandReturn translateCommand(List<String> command, CommandQueue queue);
}
/**
@@ -59,17 +106,19 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
private static class FlipCommand implements MonkeyCommand {
// flip open
// flip closed
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() > 1) {
String direction = command.get(1);
if ("open".equals(direction)) {
return new MonkeyFlipEvent(true);
queue.enqueueEvent(new MonkeyFlipEvent(true));
return OK;
} else if ("close".equals(direction)) {
return new MonkeyFlipEvent(false);
queue.enqueueEvent(new MonkeyFlipEvent(false));
return OK;
}
}
return null;
return EARG;
}
}
@@ -81,8 +130,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
// touch down 120 120
// touch move 140 140
// touch up 140 140
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 4) {
String actionName = command.get(1);
int x = 0;
@@ -93,7 +142,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
} catch (NumberFormatException e) {
// Ok, it wasn't a number
Log.e(TAG, "Got something that wasn't a number", e);
return null;
return EARG;
}
// figure out the action
@@ -107,14 +156,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
}
if (action == -1) {
Log.e(TAG, "Got a bad action: " + actionName);
return null;
return EARG;
}
return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
-1, action, x, y, 0);
queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
-1, action, x, y, 0));
return OK;
}
return null;
return EARG;
}
}
@@ -125,8 +174,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
// trackball [dx] [dy]
// trackball 1 0 -- move right
// trackball -1 0 -- move left
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 3) {
int dx = 0;
int dy = 0;
@@ -136,13 +185,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
} catch (NumberFormatException e) {
// Ok, it wasn't a number
Log.e(TAG, "Got something that wasn't a number", e);
return null;
return EARG;
}
return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
MotionEvent.ACTION_MOVE, dx, dy, 0);
queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
MotionEvent.ACTION_MOVE, dx, dy, 0));
return OK;
}
return null;
return EARG;
}
}
@@ -153,14 +203,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
// key [down|up] [keycode]
// key down 82
// key up 82
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 3) {
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;
return EARG;
}
Log.d(TAG, "keycode: " + keyCode);
int action = -1;
@@ -171,11 +221,12 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
}
if (action == -1) {
Log.e(TAG, "got unknown action.");
return null;
return EARG;
}
return new MonkeyKeyEvent(action, keyCode);
queue.enqueueEvent(new MonkeyKeyEvent(action, keyCode));
return OK;
}
return null;
return EARG;
}
}
@@ -210,19 +261,21 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
*/
private static class SleepCommand implements MonkeyCommand {
// sleep 2000
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 2) {
int sleep = -1;
String sleepStr = command.get(1);
try {
sleep = Integer.parseInt(sleepStr);
} catch (NumberFormatException e) {
Log.e(TAG, "Not a number: " + sleepStr, e);
Log.e(TAG, "Not a number: " + sleepStr, e);
return EARG;
}
return new MonkeyThrottleEvent(sleep);
queue.enqueueEvent(new MonkeyThrottleEvent(sleep));
return OK;
}
return null;
return EARG;
}
}
@@ -231,8 +284,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
*/
private static class TypeCommand implements MonkeyCommand {
// wake
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 2) {
String str = command.get(1);
@@ -248,9 +301,9 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
for (KeyEvent event : events) {
queue.enqueueEvent(new MonkeyKeyEvent(event));
}
return new MonkeyNoopEvent();
return OK;
}
return null;
return EARG;
}
}
@@ -259,12 +312,12 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
*/
private static class WakeCommand implements MonkeyCommand {
// wake
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (!wake()) {
return null;
return ERROR;
}
return new MonkeyNoopEvent();
return OK;
}
}
@@ -274,8 +327,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
*/
private static class TapCommand implements MonkeyCommand {
// tap x y
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 3) {
int x = 0;
int y = 0;
@@ -285,7 +338,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
} catch (NumberFormatException e) {
// Ok, it wasn't a number
Log.e(TAG, "Got something that wasn't a number", e);
return null;
return EARG;
}
queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
@@ -294,9 +347,9 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
-1, MotionEvent.ACTION_UP,
x, y, 0));
return new MonkeyNoopEvent();
return OK;
}
return null;
return EARG;
}
}
@@ -305,22 +358,22 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
*/
private static class PressCommand implements MonkeyCommand {
// press keycode
public MonkeyEvent translateCommand(List<String> command,
CommandQueue queue) {
public MonkeyCommandReturn translateCommand(List<String> 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;
return EARG;
}
queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode));
queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode));
return new MonkeyNoopEvent();
return OK;
}
return null;
return EARG;
}
}
@@ -355,6 +408,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
COMMAND_MAP.put("tap", new TapCommand());
COMMAND_MAP.put("press", new PressCommand());
COMMAND_MAP.put("type", new TypeCommand());
COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand());
COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand());
}
// QUIT command
@@ -363,10 +418,10 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
private static final String DONE = "done";
// command response strings
private static final String OK = "OK";
private static final String ERROR = "ERROR";
private static final String OK_STR = "OK";
private static final String ERROR_STR = "ERROR";
private static interface CommandQueue {
public static interface CommandQueue {
/**
* Enqueue an event to be returned later. This allows a
* command to return multiple events. Commands using the
@@ -499,21 +554,30 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
* Translate the given command line into a MonkeyEvent.
*
* @param commandLine the full command line given.
* @returns the MonkeyEvent corresponding to the command, or null
* if there was an issue.
*/
private MonkeyEvent translateCommand(String commandLine) {
private void translateCommand(String commandLine) {
Log.d(TAG, "translateCommand: " + commandLine);
List<String> parts = commandLineSplit(commandLine);
if (parts.size() > 0) {
MonkeyCommand command = COMMAND_MAP.get(parts.get(0));
if (command != null) {
return command.translateCommand(parts,
commandQueue);
MonkeyCommandReturn ret = command.translateCommand(parts,
commandQueue);
if (ret.wasSuccessful()) {
if (ret.hasMessage()) {
returnOk(ret.getMessage());
} else {
returnOk();
}
} else {
if (ret.hasMessage()) {
returnError(ret.getMessage());
} else {
returnError();
}
}
}
return null;
}
return null;
}
public MonkeyEvent getNextEvent() {
@@ -548,16 +612,16 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
}
if (DONE.equals(command)) {
// stop the server so it can accept new connections
// stop the server so it can accept new connections
try {
stopServer();
} catch (IOException e) {
Log.e(TAG, "Got IOException shutting down!", e);
return null;
}
// return a noop event so we keep executing the main
// loop
return new MonkeyNoopEvent();
// return a noop event so we keep executing the main
// loop
return new MonkeyNoopEvent();
}
// Do quit checking here
@@ -565,7 +629,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
// then we're done
Log.d(TAG, "Quit requested");
// let the host know the command ran OK
output.println(OK);
returnOk();
return null;
}
@@ -573,20 +637,12 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
// command, so we don't echo anything back to the
// user.
if (command.startsWith("#")) {
// keep going
continue;
// keep going
continue;
}
// Translate the command line
MonkeyEvent event = translateCommand(command);
if (event != null) {
// let the host know the command ran OK
output.println(OK);
return event;
}
// keep going. maybe the next command will make more sense
Log.e(TAG, "Got unknown command! \"" + command + "\"");
output.println(ERROR);
// Translate the command line. This will handle returning error/ok to the user
translateCommand(command);
}
} catch (IOException e) {
Log.e(TAG, "Exception: ", e);
@@ -594,6 +650,42 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
}
}
/**
* Returns ERROR to the user.
*/
private void returnError() {
output.println(ERROR_STR);
}
/**
* Returns ERROR to the user.
*
* @param msg the error message to include
*/
private void returnError(String msg) {
output.print(ERROR_STR);
output.print(":");
output.println(msg);
}
/**
* Returns OK to the user.
*/
private void returnOk() {
output.println(OK_STR);
}
/**
* Returns OK to the user.
*
* @param returnValue the value to return from this command.
*/
private void returnOk(String returnValue) {
output.print(OK_STR);
output.print(":");
output.println(returnValue);
}
public void setVerbose(int verbose) {
// We're not particualy verbose
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright 2009, 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 android.os.Build;
import android.os.SystemClock;
import android.view.Display;
import android.view.WindowManagerImpl;
import android.util.DisplayMetrics;
import com.android.commands.monkey.MonkeySourceNetwork.CommandQueue;
import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommand;
import com.android.commands.monkey.MonkeySourceNetwork.MonkeyCommandReturn;
import java.lang.Integer;
import java.lang.Float;
import java.lang.Long;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MonkeySourceNetworkVars {
/**
* Interface to get the value of a var.
*/
private static interface VarGetter {
/**
* Get the value of the var.
* @returns the value of the var.
*/
public String get();
}
private static class StaticVarGetter implements VarGetter {
private final String value;
public StaticVarGetter(String value) {
this.value = value;
}
public String get() {
return value;
}
}
// Use a TreeMap to keep the keys sorted so they get displayed nicely in listvar
private static final Map<String, VarGetter> VAR_MAP = new TreeMap<String, VarGetter>();
static {
VAR_MAP.put("build.board", new StaticVarGetter(Build.BOARD));
VAR_MAP.put("build.brand", new StaticVarGetter(Build.BRAND));
VAR_MAP.put("build.device", new StaticVarGetter(Build.DEVICE));
VAR_MAP.put("build.display", new StaticVarGetter(Build.DISPLAY));
VAR_MAP.put("build.fingerprint", new StaticVarGetter(Build.FINGERPRINT));
VAR_MAP.put("build.host", new StaticVarGetter(Build.HOST));
VAR_MAP.put("build.id", new StaticVarGetter(Build.ID));
VAR_MAP.put("build.model", new StaticVarGetter(Build.MODEL));
VAR_MAP.put("build.product", new StaticVarGetter(Build.PRODUCT));
VAR_MAP.put("build.tags", new StaticVarGetter(Build.TAGS));
VAR_MAP.put("build.brand", new StaticVarGetter(Long.toString(Build.TIME)));
VAR_MAP.put("build.type", new StaticVarGetter(Build.TYPE));
VAR_MAP.put("build.user", new StaticVarGetter(Build.USER));
VAR_MAP.put("build.cpu_abi", new StaticVarGetter(Build.CPU_ABI));
VAR_MAP.put("build.manufacturer", new StaticVarGetter(Build.MANUFACTURER));
VAR_MAP.put("build.version.incremental", new StaticVarGetter(Build.VERSION.INCREMENTAL));
VAR_MAP.put("build.version.release", new StaticVarGetter(Build.VERSION.RELEASE));
VAR_MAP.put("build.version.sdk", new StaticVarGetter(Integer.toString(Build.VERSION.SDK_INT)));
VAR_MAP.put("build.version.codename", new StaticVarGetter(Build.VERSION.CODENAME));
// Display
Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
VAR_MAP.put("display.width", new StaticVarGetter(Integer.toString(display.getWidth())));
VAR_MAP.put("display.height", new StaticVarGetter(Integer.toString(display.getHeight())));
DisplayMetrics dm = new DisplayMetrics();
display.getMetrics(dm);
VAR_MAP.put("display.density", new StaticVarGetter(Float.toString(dm.density)));
// am. note that the current activity information isn't valid
// until the first activity gets launched after the monkey has
// been started.
VAR_MAP.put("am.current.package", new VarGetter() {
public String get() {
return Monkey.currentPackage;
}
});
VAR_MAP.put("am.current.action", new VarGetter() {
public String get() {
if (Monkey.currentIntent == null) {
return null;
}
return Monkey.currentIntent.getAction();
}
});
VAR_MAP.put("am.current.comp.class", new VarGetter() {
public String get() {
if (Monkey.currentIntent == null) {
return null;
}
return Monkey.currentIntent.getComponent().getClassName();
}
});
VAR_MAP.put("am.current.comp.package", new VarGetter() {
public String get() {
if (Monkey.currentIntent == null) {
return null;
}
return Monkey.currentIntent.getComponent().getPackageName();
}
});
VAR_MAP.put("am.current.data", new VarGetter() {
public String get() {
if (Monkey.currentIntent == null) {
return null;
}
return Monkey.currentIntent.getDataString();
}
});
VAR_MAP.put("am.current.categories", new VarGetter() {
public String get() {
if (Monkey.currentIntent == null) {
return null;
}
StringBuffer sb = new StringBuffer();
for (String cat : Monkey.currentIntent.getCategories()) {
sb.append(cat).append(" ");
}
return sb.toString();
}
});
// clock
VAR_MAP.put("clock.realtime", new VarGetter() {
public String get() {
return Long.toString(SystemClock.elapsedRealtime());
}
});
VAR_MAP.put("clock.uptime", new VarGetter() {
public String get() {
return Long.toString(SystemClock.uptimeMillis());
}
});
VAR_MAP.put("clock.millis", new VarGetter() {
public String get() {
return Long.toString(System.currentTimeMillis());
}
});
}
/**
* Command to list the "vars" that the monkey knows about.
*/
public static class ListVarCommand implements MonkeySourceNetwork.MonkeyCommand {
// listvar
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
Set<String> keys = VAR_MAP.keySet();
StringBuffer sb = new StringBuffer();
for (String key : keys) {
sb.append(key).append(" ");
}
return new MonkeyCommandReturn(true, sb.toString());
}
}
/**
* Command to get the value of a var.
*/
public static class GetVarCommand implements MonkeyCommand {
// getvar varname
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() == 2) {
VarGetter getter = VAR_MAP.get(command.get(1));
if (getter == null) {
return new MonkeyCommandReturn(false, "unknown var");
}
return new MonkeyCommandReturn(true, getter.get());
}
return MonkeySourceNetwork.EARG;
}
}
}