Added deferreturn command

Change-Id: Id84ac667d42dab4648b24cc335917c3d15ec1de4
This commit is contained in:
Michael Wright
2011-07-18 18:35:45 -07:00
parent b36bed5899
commit c6c89b994e
2 changed files with 120 additions and 14 deletions

View File

@@ -50,6 +50,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
private static final String TAG = "MonkeyStub"; private static final String TAG = "MonkeyStub";
/* The version of the monkey network protocol */ /* The version of the monkey network protocol */
public static final int MONKEY_NETWORK_VERSION = 2; public static final int MONKEY_NETWORK_VERSION = 2;
private static DeferredReturn deferredReturn;
/** /**
* ReturnValue from the MonkeyCommand that indicates whether the * ReturnValue from the MonkeyCommand that indicates whether the
@@ -377,6 +378,52 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
} }
} }
/**
* Command to defer the return of another command until the given event occurs.
* deferreturn takes three arguments. It takes an event to wait for (e.g. waiting for the
* device to display a different activity would the "screenchange" event), a
* timeout, which is the number of microseconds to wait for the event to occur, and it takes
* a command. The command can be any other Monkey command that can be issued over the network
* (e.g. press KEYCODE_HOME). deferreturn will then run this command, return an OK, wait for
* the event to occur and return the deferred return value when either the event occurs or
* when the timeout is reached (whichever occurs first). Note that there is no difference
* between an event occurring and the timeout being reached; the client will have to verify
* that the change actually occured.
*
* Example:
* deferreturn screenchange 1000 press KEYCODE_HOME
* This command will press the home key on the device and then wait for the screen to change
* for up to one second. Either the screen will change, and the results fo the key press will
* be returned to the client, or the timeout will be reached, and the results for the key
* press will be returned to the client.
*/
private static class DeferReturnCommand implements MonkeyCommand {
// deferreturn [event] [timeout (ms)] [command]
// deferreturn screenchange 100 tap 10 10
public MonkeyCommandReturn translateCommand(List<String> command,
CommandQueue queue) {
if (command.size() > 3) {
String event = command.get(1);
int eventId;
if (event.equals("screenchange")) {
eventId = DeferredReturn.ON_WINDOW_STATE_CHANGE;
} else {
return EARG;
}
long timeout = Long.parseLong(command.get(2));
MonkeyCommand deferredCommand = COMMAND_MAP.get(command.get(3));
if (deferredCommand != null) {
List<String> parts = command.subList(3, command.size());
MonkeyCommandReturn ret = deferredCommand.translateCommand(parts, queue);
deferredReturn = new DeferredReturn(eventId, ret, timeout);
return OK;
}
}
return EARG;
}
}
/** /**
* Force the device to wake up. * Force the device to wake up.
* *
@@ -415,6 +462,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand()); COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand());
COMMAND_MAP.put("getviewswithtext", COMMAND_MAP.put("getviewswithtext",
new MonkeySourceNetworkViews.GetViewsWithTextCommand()); new MonkeySourceNetworkViews.GetViewsWithTextCommand());
COMMAND_MAP.put("deferreturn", new DeferReturnCommand());
} }
// QUIT command // QUIT command
@@ -458,6 +506,40 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
} }
}; };
// A holder class for a deferred return value. This allows us to defer returning the success of
// a call until a given event has occurred.
private static class DeferredReturn {
public static final int ON_WINDOW_STATE_CHANGE = 1;
private int event;
private MonkeyCommandReturn deferredReturn;
private long timeout;
public DeferredReturn(int event, MonkeyCommandReturn deferredReturn, long timeout) {
this.event = event;
this.deferredReturn = deferredReturn;
this.timeout = timeout;
}
/**
* Wait until the given event has occurred before returning the value.
* @return The MonkeyCommandReturn from the command that was deferred.
*/
public MonkeyCommandReturn waitForEvent() {
switch(event) {
case ON_WINDOW_STATE_CHANGE:
try {
synchronized(MonkeySourceNetworkViews.sConnection) {
MonkeySourceNetworkViews.sConnection.wait(timeout);
}
} catch(InterruptedException e) {
Log.d(TAG, "Deferral interrupted: " + e.getMessage());
}
}
return deferredReturn;
}
};
private final CommandQueueImpl commandQueue = new CommandQueueImpl(); private final CommandQueueImpl commandQueue = new CommandQueueImpl();
private BufferedReader input; private BufferedReader input;
@@ -571,23 +653,28 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); MonkeyCommand command = COMMAND_MAP.get(parts.get(0));
if (command != null) { if (command != null) {
MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue); MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue);
if (ret.wasSuccessful()) { handleReturn(ret);
if (ret.hasMessage()) {
returnOk(ret.getMessage());
} else {
returnOk();
}
} else {
if (ret.hasMessage()) {
returnError(ret.getMessage());
} else {
returnError();
}
}
} }
} }
} }
private void handleReturn(MonkeyCommandReturn ret) {
if (ret.wasSuccessful()) {
if (ret.hasMessage()) {
returnOk(ret.getMessage());
} else {
returnOk();
}
} else {
if (ret.hasMessage()) {
returnError(ret.getMessage());
} else {
returnError();
}
}
}
public MonkeyEvent getNextEvent() { public MonkeyEvent getNextEvent() {
if (!started) { if (!started) {
try { try {
@@ -611,6 +698,16 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
return queuedEvent; return queuedEvent;
} }
// Check to see if we have any returns that have been deferred. If so, now that
// we've run the queued commands, wait for the given event to happen (or the timeout
// to be reached), and handle the deferred MonkeyCommandReturn.
if (deferredReturn != null) {
Log.d(TAG, "Waiting for event");
MonkeyCommandReturn ret = deferredReturn.waitForEvent();
deferredReturn = null;
handleReturn(ret);
}
String command = input.readLine(); String command = input.readLine();
if (command == null) { if (command == null) {
Log.d(TAG, "Connection dropped."); Log.d(TAG, "Connection dropped.");

View File

@@ -111,7 +111,11 @@ public class MonkeySourceNetworkViews {
public void onInterrupt() {} public void onInterrupt() {}
public void onAccessibilityEvent(AccessibilityEvent event) { public void onAccessibilityEvent(AccessibilityEvent event) {
sLastAccessibilityEvent.set(AccessibilityEvent.obtain(event)); Log.d(TAG, "Accessibility Event");
sLastAccessibilityEvent.set(AccessibilityEvent.obtain(event));
synchronized(sConnection) {
sConnection.notifyAll();
}
} }
}; };
IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
@@ -402,6 +406,11 @@ public class MonkeySourceNetworkViews {
if (node.isPassword()){ if (node.isPassword()){
return new MonkeyCommandReturn(false, "Node contains a password"); return new MonkeyCommandReturn(false, "Node contains a password");
} }
/* Occasionally we get a null from the accessibility API, rather than an empty
* string */
if (node.getText() == null) {
return new MonkeyCommandReturn(true, "");
}
return new MonkeyCommandReturn(true, node.getText().toString()); return new MonkeyCommandReturn(true, node.getText().toString());
} }
return EARG; return EARG;