Added in simple command scripting to monkey over a TCP socket.
This allows a host program to talk to the monkey over TCP (via adb) and script up specific commands to run.
This commit is contained in:
@@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
LOCAL_MODULE := monkey
|
||||
include $(BUILD_JAVA_LIBRARY)
|
||||
|
||||
################################################################
|
||||
include $(CLEAR_VARS)
|
||||
ALL_PREBUILT += $(TARGET_OUT)/bin/monkey
|
||||
$(TARGET_OUT)/bin/monkey : $(LOCAL_PATH)/monkey | $(ACP)
|
||||
|
||||
86
cmds/monkey/README.NETWORK.txt
Normal file
86
cmds/monkey/README.NETWORK.txt
Normal file
@@ -0,0 +1,86 @@
|
||||
MONKEY NETWORK SCRIPT
|
||||
|
||||
The Monkey Network Script was designed to be a low-level way to
|
||||
programmability inject KeyEvents and MotionEvents into the input
|
||||
system. The idea is that a process will run on a host computer that
|
||||
will support higher-level operations (like conditionals, etc.) and
|
||||
will talk (via TCP over ADB) to the device in Monkey Network Script.
|
||||
For security reasons, the Monkey only binds to localhost, so you will
|
||||
need to use adb to setup port forwarding to actually talk to the
|
||||
device.
|
||||
|
||||
INITIAL SETUP
|
||||
|
||||
Setup port forwarding from a local port on your machine to a port on
|
||||
the device:
|
||||
|
||||
$ adb forward tcp:1080 tcp:1080
|
||||
|
||||
Start the monkey server
|
||||
|
||||
$ adb shell monkey --port 1080
|
||||
|
||||
Now you're ready to run commands
|
||||
|
||||
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:
|
||||
|
||||
key down menu
|
||||
OK
|
||||
touch monkey
|
||||
ERROR: monkey not a number
|
||||
|
||||
The complete list of commands follows:
|
||||
|
||||
key [down|up] keycode
|
||||
|
||||
This command injects KeyEvent's into the input system. The keycode
|
||||
parameter refers to the KEYCODE list in the KeyEvent class
|
||||
(http://developer.android.com/reference/android/view/KeyEvent.html).
|
||||
The format of that parameter is quite flexible. Using the menu key as
|
||||
an example, it can be 82 (the integer value of the keycode),
|
||||
KEYCODE_MENU (the name of the keycode), or just menu (and the Monkey
|
||||
will add the KEYCODE part). Do note that this last part doesn't work
|
||||
for things like KEYCODE_1 for obvious reasons.
|
||||
|
||||
Note that sending a full button press requires sending both the down
|
||||
and the up event for that key
|
||||
|
||||
touch [down|up|move] x y
|
||||
|
||||
This command injects a MotionEvent into the input system that
|
||||
simulates a user touching the touchscreen (or a pointer event). x and
|
||||
y specify coordinates on the display (0 0 being the upper left) for
|
||||
the touch event to happen. Just like key events, touch events at a
|
||||
single location require both a down and an up. To simulate dragging,
|
||||
send a "touch down", then a series of "touch move" events (to simulate
|
||||
the drag), followed by a "touch up" at the final location.
|
||||
|
||||
trackball dx dy
|
||||
|
||||
This command injects a MotionEvent into the input system that
|
||||
simulates a user using the trackball. dx and dy indicates the amount
|
||||
of change in the trackball location (as opposed to exact coordinates
|
||||
that the touch events use)
|
||||
|
||||
flip [open|close]
|
||||
|
||||
This simulates the opening or closing the keyboard (like on dream).
|
||||
|
||||
OTHER NOTES
|
||||
|
||||
There are some convenience features added to allow running without
|
||||
needing a host process.
|
||||
|
||||
Lines starting with a # character are considered comments. The Monkey
|
||||
eats them and returns no indication that it did anything (no ERROR and
|
||||
no OK).
|
||||
|
||||
You can put the Monkey to sleep by using the "sleep" command with a
|
||||
single argument, how many ms to sleep.
|
||||
57
cmds/monkey/example_script.txt
Normal file
57
cmds/monkey/example_script.txt
Normal file
@@ -0,0 +1,57 @@
|
||||
# Touch the android
|
||||
touch down 160 200
|
||||
touch up 160 200
|
||||
sleep 1000
|
||||
|
||||
# Hit Next
|
||||
touch down 300 450
|
||||
touch up 300 450
|
||||
sleep 1000
|
||||
|
||||
# Hit Next
|
||||
touch down 300 450
|
||||
touch up 300 450
|
||||
sleep 1000
|
||||
|
||||
# Hit Next
|
||||
touch down 300 450
|
||||
touch up 300 450
|
||||
sleep 1000
|
||||
|
||||
# Go down and select the account username
|
||||
key down dpad_down
|
||||
key up dpad_down
|
||||
key down dpad_down
|
||||
key up dpad_down
|
||||
key down dpad_center
|
||||
key up dpad_center
|
||||
# account name: bill
|
||||
key down b
|
||||
key up b
|
||||
key down i
|
||||
key up i
|
||||
key down l
|
||||
key up l
|
||||
key down l
|
||||
key up l
|
||||
|
||||
# Go down to the password field
|
||||
key down dpad_down
|
||||
key up dpad_down
|
||||
|
||||
# password: bill
|
||||
key down b
|
||||
key up b
|
||||
key down i
|
||||
key up i
|
||||
key down l
|
||||
key up l
|
||||
key down l
|
||||
key up l
|
||||
|
||||
# Select next
|
||||
touch down 300 450
|
||||
touch up 300 450
|
||||
|
||||
# quit
|
||||
quit
|
||||
@@ -125,6 +125,9 @@ public class Monkey {
|
||||
/** a filename to the script (if any) **/
|
||||
private String mScriptFileName = null;
|
||||
|
||||
/** a TCP port to listen on for remote commands. */
|
||||
private int mServerPort = -1;
|
||||
|
||||
private static final File TOMBSTONES_PATH = new File("/data/tombstones");
|
||||
private HashSet<String> mTombstones = null;
|
||||
|
||||
@@ -365,6 +368,9 @@ public class Monkey {
|
||||
// script mode, ignore other options
|
||||
mEventSource = new MonkeySourceScript(mScriptFileName, mThrottle);
|
||||
mEventSource.setVerbose(mVerbose);
|
||||
} else if (mServerPort != -1) {
|
||||
mEventSource = new MonkeySourceNetwork(mServerPort);
|
||||
mCount = Integer.MAX_VALUE;
|
||||
} else {
|
||||
// random source by default
|
||||
if (mVerbose >= 2) { // check seeding performance
|
||||
@@ -527,7 +533,9 @@ public class Monkey {
|
||||
// do nothing - it's caught at the very start of run()
|
||||
} else if (opt.equals("--dbg-no-events")) {
|
||||
mSendNoEvents = true;
|
||||
} else if (opt.equals("-f")) {
|
||||
} else if (opt.equals("--port")) {
|
||||
mServerPort = (int) nextOptionLong("Server port to listen on for commands");
|
||||
} else if (opt.equals("-f")) {
|
||||
mScriptFileName = nextOptionData();
|
||||
} else if (opt.equals("-h")) {
|
||||
showUsage();
|
||||
@@ -544,19 +552,23 @@ public class Monkey {
|
||||
return false;
|
||||
}
|
||||
|
||||
String countStr = nextArg();
|
||||
if (countStr == null) {
|
||||
System.err.println("** Error: Count not specified");
|
||||
showUsage();
|
||||
return false;
|
||||
}
|
||||
// If a server port hasn't been specified, we need to specify
|
||||
// a count
|
||||
if (mServerPort == -1) {
|
||||
String countStr = nextArg();
|
||||
if (countStr == null) {
|
||||
System.err.println("** Error: Count not specified");
|
||||
showUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
mCount = Integer.parseInt(countStr);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("** Error: Count is not a number");
|
||||
showUsage();
|
||||
return false;
|
||||
try {
|
||||
mCount = Integer.parseInt(countStr);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("** Error: Count is not a number");
|
||||
showUsage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -749,9 +761,11 @@ public class Monkey {
|
||||
} else if (injectCode == MonkeyEvent.INJECT_ERROR_SECURITY_EXCEPTION) {
|
||||
systemCrashed = !mIgnoreSecurityExceptions;
|
||||
}
|
||||
} else {
|
||||
// Event Source has signaled that we have no more events to process
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, we succeeded!
|
||||
return mCount;
|
||||
}
|
||||
@@ -904,6 +918,7 @@ public class Monkey {
|
||||
System.err.println(" [--pct-appswitch PERCENT] [--pct-flip PERCENT]");
|
||||
System.err.println(" [--pct-anyevent PERCENT]");
|
||||
System.err.println(" [--wait-dbg] [--dbg-no-events] [-f scriptfile]");
|
||||
System.err.println(" [--port port]");
|
||||
System.err.println(" [-s SEED] [-v [-v] ...] [--throttle MILLISEC]");
|
||||
System.err.println(" COUNT");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* 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.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.Integer;
|
||||
import java.lang.NumberFormatException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* An Event source for getting Monkey Network Script commands from
|
||||
* over the network.
|
||||
*/
|
||||
public class MonkeySourceNetwork implements MonkeyEventSource {
|
||||
private static final String TAG = "MonkeyStub";
|
||||
|
||||
private interface MonkeyCommand {
|
||||
MonkeyEvent translateCommand(List<String> command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command to simulate closing and opening the keyboard.
|
||||
*/
|
||||
private static class FlipCommand implements MonkeyCommand {
|
||||
// flip open
|
||||
// flip closed
|
||||
public MonkeyEvent translateCommand(List<String> command) {
|
||||
if (command.size() > 1) {
|
||||
String direction = command.get(1);
|
||||
if ("open".equals(direction)) {
|
||||
return new MonkeyFlipEvent(true);
|
||||
} else if ("close".equals(direction)) {
|
||||
return new MonkeyFlipEvent(false);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command to send touch events to the input system.
|
||||
*/
|
||||
private static class TouchCommand implements MonkeyCommand {
|
||||
// touch [down|up|move] [x] [y]
|
||||
// touch down 120 120
|
||||
// touch move 140 140
|
||||
// touch up 140 140
|
||||
public MonkeyEvent translateCommand(List<String> command) {
|
||||
if (command.size() == 4) {
|
||||
String actionName = command.get(1);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
try {
|
||||
x = Integer.parseInt(command.get(2));
|
||||
y = Integer.parseInt(command.get(3));
|
||||
} catch (NumberFormatException e) {
|
||||
// Ok, it wasn't a number
|
||||
Log.e(TAG, "Got something that wasn't a number", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// figure out the action
|
||||
int action = -1;
|
||||
if ("down".equals(actionName)) {
|
||||
action = MotionEvent.ACTION_DOWN;
|
||||
} else if ("up".equals(actionName)) {
|
||||
action = MotionEvent.ACTION_UP;
|
||||
} else if ("move".equals(actionName)) {
|
||||
action = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
if (action == -1) {
|
||||
Log.e(TAG, "Got a bad action: " + actionName);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER,
|
||||
-1, action, x, y, 0);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command to send Trackball events to the input system.
|
||||
*/
|
||||
private static class TrackballCommand implements MonkeyCommand {
|
||||
// trackball [dx] [dy]
|
||||
// trackball 1 0 -- move right
|
||||
// trackball -1 0 -- move left
|
||||
public MonkeyEvent translateCommand(List<String> command) {
|
||||
if (command.size() == 3) {
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
try {
|
||||
dx = Integer.parseInt(command.get(1));
|
||||
dy = 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;
|
||||
}
|
||||
return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1,
|
||||
MotionEvent.ACTION_MOVE, dx, dy, 0);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command to send Key events to the input system.
|
||||
*/
|
||||
private static class KeyCommand implements MonkeyCommand {
|
||||
// key [down|up] [keycode]
|
||||
// key down 82
|
||||
// key up 82
|
||||
public MonkeyEvent translateCommand(List<String> command) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "keycode: " + keyCode);
|
||||
int action = -1;
|
||||
if ("down".equals(command.get(1))) {
|
||||
action = KeyEvent.ACTION_DOWN;
|
||||
} else if ("up".equals(command.get(1))) {
|
||||
action = KeyEvent.ACTION_UP;
|
||||
}
|
||||
if (action == -1) {
|
||||
Log.e(TAG, "got unknown action.");
|
||||
return null;
|
||||
}
|
||||
return new MonkeyKeyEvent(action, keyCode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command to put the Monkey to sleep.
|
||||
*/
|
||||
private static class SleepCommand implements MonkeyCommand {
|
||||
// sleep 2000
|
||||
public MonkeyEvent translateCommand(List<String> command) {
|
||||
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);
|
||||
}
|
||||
return new MonkeyThrottleEvent(sleep);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// This maps from command names to command implementations.
|
||||
private static final Map<String, MonkeyCommand> COMMAND_MAP = new HashMap<String, MonkeyCommand>();
|
||||
|
||||
static {
|
||||
// Add in all the commands we support
|
||||
COMMAND_MAP.put("flip", new FlipCommand());
|
||||
COMMAND_MAP.put("touch", new TouchCommand());
|
||||
COMMAND_MAP.put("trackball", new TrackballCommand());
|
||||
COMMAND_MAP.put("key", new KeyCommand());
|
||||
COMMAND_MAP.put("sleep", new SleepCommand());
|
||||
}
|
||||
|
||||
// QUIT command
|
||||
private static final String QUIT = "quit";
|
||||
|
||||
// command response strings
|
||||
private static final String OK = "OK";
|
||||
private static final String ERROR = "ERROR";
|
||||
|
||||
|
||||
private final int port;
|
||||
private BufferedReader input;
|
||||
private PrintWriter output;
|
||||
private boolean started = false;
|
||||
|
||||
public MonkeySourceNetwork(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a network server listening on the specified port. The
|
||||
* network protocol is a line oriented protocol, where each line
|
||||
* is a different command that can be run.
|
||||
*
|
||||
* @param port the port to listen on
|
||||
*/
|
||||
private void startServer() throws IOException {
|
||||
// Only bind this to local host. This means that you can only
|
||||
// talk to the monkey locally, or though adb port forwarding.
|
||||
ServerSocket server = new ServerSocket(port,
|
||||
0, // default backlog
|
||||
InetAddress.getLocalHost());
|
||||
Socket s = server.accept();
|
||||
input = new BufferedReader(new InputStreamReader(s.getInputStream()));
|
||||
// auto-flush
|
||||
output = new PrintWriter(s.getOutputStream(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function splits the given line into String parts. It obey's quoted
|
||||
* strings and returns them as a single part.
|
||||
*
|
||||
* "This is a test" -> returns only one element
|
||||
* This is a test -> returns four elements
|
||||
*
|
||||
* @param line the line to parse
|
||||
* @return the List of elements
|
||||
*/
|
||||
private static List<String> commandLineSplit(String line) {
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
|
||||
boolean insideQuote = false;
|
||||
StringBuffer quotedWord = new StringBuffer();
|
||||
while (tok.hasMoreTokens()) {
|
||||
String cur = tok.nextToken();
|
||||
if (!insideQuote && cur.startsWith("\"")) {
|
||||
// begin quote
|
||||
quotedWord.append(cur);
|
||||
insideQuote = true;
|
||||
} else if (insideQuote) {
|
||||
// end quote
|
||||
if (cur.endsWith("\"")) {
|
||||
insideQuote = false;
|
||||
quotedWord.append(cur);
|
||||
String word = quotedWord.toString();
|
||||
|
||||
// trim off the quotes
|
||||
result.add(word.substring(1, word.length() - 1));
|
||||
} else {
|
||||
quotedWord.append(cur);
|
||||
}
|
||||
} else {
|
||||
result.add(cur);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
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);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MonkeyEvent getNextEvent() {
|
||||
if (!started) {
|
||||
try {
|
||||
startServer();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Got IOException from server", e);
|
||||
return null;
|
||||
}
|
||||
started = true;
|
||||
}
|
||||
|
||||
// Now, get the next command. This call may block, but that's OK
|
||||
try {
|
||||
while (true) {
|
||||
String command = input.readLine();
|
||||
if (command == null) {
|
||||
Log.d(TAG, "Connection dropped.");
|
||||
return null;
|
||||
}
|
||||
// Do quit checking here
|
||||
if (QUIT.equals(command)) {
|
||||
// then we're done
|
||||
Log.d(TAG, "Quit requested");
|
||||
// let the host know the command ran OK
|
||||
output.println(OK);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do comment checking here. Comments aren't a
|
||||
// command, so we don't echo anything back to the
|
||||
// user.
|
||||
if (command.startsWith("#")) {
|
||||
// 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);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setVerbose(int verbose) {
|
||||
// We're not particualy verbose
|
||||
}
|
||||
|
||||
public boolean validate() {
|
||||
// we have no pre-conditions to validate
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
||||
/** Nice names for all key events. */
|
||||
private static final String[] KEY_NAMES = {
|
||||
"KEYCODE_UNKNOWN",
|
||||
"KEYCODE_MENU",
|
||||
"KEYCODE_SOFT_LEFT",
|
||||
"KEYCODE_SOFT_RIGHT",
|
||||
"KEYCODE_HOME",
|
||||
"KEYCODE_BACK",
|
||||
@@ -186,6 +186,22 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
||||
return KEY_NAMES[keycode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the keyCode from a given KEYCODE_NAME. NOTE: This may
|
||||
* be an expensive operation.
|
||||
*
|
||||
* @param keyName the name of the KEYCODE_VALUE to lookup.
|
||||
* @returns the intenger keyCode value, or -1 if not found
|
||||
*/
|
||||
public static int getKeyCode(String keyName) {
|
||||
for (int x = 0; x < KEY_NAMES.length; x++) {
|
||||
if (KEY_NAMES[x].equals(keyName)) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public MonkeySourceRandom(long seed, ArrayList<ComponentName> MainApps, long throttle) {
|
||||
// default values for random distributions
|
||||
// note, these are straight percentages, to match user input (cmd line args)
|
||||
|
||||
Reference in New Issue
Block a user