Add getvar and listvar commands to monkey to allow inspection of properties on the device.

This commit is contained in:
Bill Napier
2009-08-17 11:20:15 -07:00
parent 12ad9fb10e
commit f94816017e
4 changed files with 393 additions and 81 deletions

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;
}
}
}