| /* |
| * 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.content.Context; |
| import android.os.IPowerManager; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.SystemClock; |
| import android.util.Log; |
| import android.view.KeyCharacterMap; |
| 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.LinkedList; |
| import java.util.List; |
| import java.util.Queue; |
| 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"; |
| /* The version of the monkey network protocol */ |
| public static final int MONKEY_NETWORK_VERSION = 2; |
| private static DeferredReturn deferredReturn; |
| |
| /** |
| * 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. |
| * @return MonkeyCommandReturn indicating what happened. |
| */ |
| MonkeyCommandReturn translateCommand(List<String> command, CommandQueue queue); |
| } |
| |
| /** |
| * Command to simulate closing and opening the keyboard. |
| */ |
| private static class FlipCommand implements MonkeyCommand { |
| // flip open |
| // flip closed |
| public MonkeyCommandReturn translateCommand(List<String> command, |
| CommandQueue queue) { |
| if (command.size() > 1) { |
| String direction = command.get(1); |
| if ("open".equals(direction)) { |
| queue.enqueueEvent(new MonkeyFlipEvent(true)); |
| return OK; |
| } else if ("close".equals(direction)) { |
| queue.enqueueEvent(new MonkeyFlipEvent(false)); |
| return OK; |
| } |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * 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 MonkeyCommandReturn translateCommand(List<String> command, |
| CommandQueue queue) { |
| 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 EARG; |
| } |
| |
| // 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 EARG; |
| } |
| |
| queue.enqueueEvent(new MonkeyTouchEvent(action) |
| .addPointer(0, x, y)); |
| return OK; |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * 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 MonkeyCommandReturn translateCommand(List<String> command, |
| CommandQueue queue) { |
| 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 EARG; |
| } |
| queue.enqueueEvent(new MonkeyTrackballEvent(MotionEvent.ACTION_MOVE) |
| .addPointer(0, dx, dy)); |
| return OK; |
| |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * 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 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 EARG; |
| } |
| 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 EARG; |
| } |
| queue.enqueueEvent(new MonkeyKeyEvent(action, keyCode)); |
| return OK; |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * Get an integer keycode value from a given keyname. |
| * |
| * @param keyName the key name to get the code for |
| * @return 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 == KeyEvent.KEYCODE_UNKNOWN) { |
| // 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 == KeyEvent.KEYCODE_UNKNOWN) { |
| // Still unknown |
| return -1; |
| } |
| } |
| } |
| return keyCode; |
| } |
| |
| /** |
| * Command to put the Monkey to sleep. |
| */ |
| private static class SleepCommand implements MonkeyCommand { |
| // sleep 2000 |
| 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); |
| return EARG; |
| } |
| queue.enqueueEvent(new MonkeyThrottleEvent(sleep)); |
| return OK; |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * Command to type a string |
| */ |
| private static class TypeCommand implements MonkeyCommand { |
| // wake |
| public MonkeyCommandReturn translateCommand(List<String> command, |
| CommandQueue queue) { |
| if (command.size() == 2) { |
| String str = command.get(1); |
| |
| char[] chars = str.toString().toCharArray(); |
| |
| // Convert the string to an array of KeyEvent's for |
| // the built in keymap. |
| KeyCharacterMap keyCharacterMap = KeyCharacterMap. |
| load(KeyCharacterMap.VIRTUAL_KEYBOARD); |
| KeyEvent[] events = keyCharacterMap.getEvents(chars); |
| |
| // enqueue all the events we just got. |
| for (KeyEvent event : events) { |
| queue.enqueueEvent(new MonkeyKeyEvent(event)); |
| } |
| return OK; |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * Command to wake the device up |
| */ |
| private static class WakeCommand implements MonkeyCommand { |
| // wake |
| public MonkeyCommandReturn translateCommand(List<String> command, |
| CommandQueue queue) { |
| if (!wake()) { |
| return ERROR; |
| } |
| return OK; |
| } |
| } |
| |
| /** |
| * Command to "tap" at a location (Sends a down and up touch |
| * event). |
| */ |
| private static class TapCommand implements MonkeyCommand { |
| // tap x y |
| public MonkeyCommandReturn translateCommand(List<String> 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 EARG; |
| } |
| |
| queue.enqueueEvent(new MonkeyTouchEvent(MotionEvent.ACTION_DOWN) |
| .addPointer(0, x, y)); |
| queue.enqueueEvent(new MonkeyTouchEvent(MotionEvent.ACTION_UP) |
| .addPointer(0, x, y)); |
| return OK; |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * Command to "press" a buttons (Sends an up and down key event.) |
| */ |
| private static class PressCommand implements MonkeyCommand { |
| // press keycode |
| 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 EARG; |
| } |
| |
| queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode)); |
| queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode)); |
| return OK; |
| |
| } |
| return EARG; |
| } |
| } |
| |
| /** |
| * 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. |
| * |
| * @return true if woken up OK. |
| */ |
| private static final boolean wake() { |
| IPowerManager pm = |
| IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); |
| try { |
| pm.wakeUp(SystemClock.uptimeMillis(), "Monkey", null); |
| } catch (RemoteException e) { |
| Log.e(TAG, "Got remote exception", e); |
| return false; |
| } |
| return true; |
| } |
| |
| // 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()); |
| COMMAND_MAP.put("wake", new WakeCommand()); |
| 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()); |
| COMMAND_MAP.put("listviews", new MonkeySourceNetworkViews.ListViewsCommand()); |
| COMMAND_MAP.put("queryview", new MonkeySourceNetworkViews.QueryViewCommand()); |
| COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand()); |
| COMMAND_MAP.put("getviewswithtext", |
| new MonkeySourceNetworkViews.GetViewsWithTextCommand()); |
| COMMAND_MAP.put("deferreturn", new DeferReturnCommand()); |
| } |
| |
| // QUIT command |
| private static final String QUIT = "quit"; |
| // DONE command |
| private static final String DONE = "done"; |
| |
| // command response strings |
| private static final String OK_STR = "OK"; |
| private static final String ERROR_STR = "ERROR"; |
| |
| public 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<MonkeyEvent> queuedEvents = new LinkedList<MonkeyEvent>(); |
| |
| public void enqueueEvent(MonkeyEvent e) { |
| queuedEvents.offer(e); |
| } |
| |
| /** |
| * Get the next queued event to excecute. |
| * |
| * @return the next event, or null if there aren't any more. |
| */ |
| public MonkeyEvent getNextQueuedEvent() { |
| return queuedEvents.poll(); |
| } |
| }; |
| |
| // 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.class) { |
| MonkeySourceNetworkViews.class.wait(timeout); |
| } |
| } catch(InterruptedException e) { |
| Log.d(TAG, "Deferral interrupted: " + e.getMessage()); |
| } |
| } |
| return deferredReturn; |
| } |
| }; |
| |
| private final CommandQueueImpl commandQueue = new CommandQueueImpl(); |
| |
| private BufferedReader input; |
| private PrintWriter output; |
| private boolean started = false; |
| |
| private ServerSocket serverSocket; |
| private Socket clientSocket; |
| |
| public MonkeySourceNetwork(int port) 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 = new ServerSocket(port, |
| 0, // default backlog |
| InetAddress.getLocalHost()); |
| } |
| |
| /** |
| * 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 { |
| clientSocket = serverSocket.accept(); |
| // At this point, we have a client connected. |
| // Attach the accessibility listeners so that we can start receiving |
| // view events. Do this before wake so we can catch the wake event |
| // if possible. |
| MonkeySourceNetworkViews.setup(); |
| // Wake the device up in preparation for doing some commands. |
| wake(); |
| |
| input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); |
| // auto-flush |
| output = new PrintWriter(clientSocket.getOutputStream(), true); |
| } |
| |
| /** |
| * Stop the server from running so it can reconnect a new client. |
| */ |
| private void stopServer() throws IOException { |
| clientSocket.close(); |
| MonkeySourceNetworkViews.teardown(); |
| input.close(); |
| output.close(); |
| started = false; |
| } |
| |
| /** |
| * Helper function for commandLineSplit that replaces quoted |
| * charaters with their real values. |
| * |
| * @param input the string to do replacement on. |
| * @return the results with the characters replaced. |
| */ |
| private static String replaceQuotedChars(String input) { |
| return input.replace("\\\"", "\""); |
| } |
| |
| /** |
| * 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(replaceQuotedChars(cur)); |
| insideQuote = true; |
| } else if (insideQuote) { |
| // end quote |
| if (cur.endsWith("\"")) { |
| insideQuote = false; |
| quotedWord.append(" ").append(replaceQuotedChars(cur)); |
| String word = quotedWord.toString(); |
| |
| // trim off the quotes |
| result.add(word.substring(1, word.length() - 1)); |
| } else { |
| quotedWord.append(" ").append(replaceQuotedChars(cur)); |
| } |
| } else { |
| result.add(replaceQuotedChars(cur)); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Translate the given command line into a MonkeyEvent. |
| * |
| * @param commandLine the full command line given. |
| */ |
| 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) { |
| MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue); |
| handleReturn(ret); |
| } |
| } |
| } |
| |
| 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() { |
| 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) { |
| // 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; |
| } |
| |
| // 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(); |
| if (command == null) { |
| Log.d(TAG, "Connection dropped."); |
| // Treat this exactly the same as if the user had |
| // ended the session cleanly with a done commant. |
| command = DONE; |
| } |
| |
| if (DONE.equals(command)) { |
| // 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(); |
| } |
| |
| // 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 |
| returnOk(); |
| 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. This will handle returning error/ok to the user |
| translateCommand(command); |
| } |
| } catch (IOException e) { |
| Log.e(TAG, "Exception: ", e); |
| return null; |
| } |
| } |
| |
| /** |
| * 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 |
| } |
| |
| public boolean validate() { |
| // we have no pre-conditions to validate |
| return true; |
| } |
| } |