Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2009, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package com.android.commands.monkey; |
| 17 | |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 18 | import android.content.Context; |
| 19 | import android.os.IPowerManager; |
| 20 | import android.os.RemoteException; |
| 21 | import android.os.ServiceManager; |
| 22 | import android.os.SystemClock; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 23 | import android.util.Log; |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 24 | import android.view.KeyCharacterMap; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 25 | import android.view.KeyEvent; |
| 26 | import android.view.MotionEvent; |
| 27 | |
| 28 | import java.io.BufferedReader; |
| 29 | import java.io.IOException; |
| 30 | import java.io.InputStreamReader; |
| 31 | import java.io.PrintWriter; |
| 32 | import java.lang.Integer; |
| 33 | import java.lang.NumberFormatException; |
| 34 | import java.net.InetAddress; |
| 35 | import java.net.ServerSocket; |
| 36 | import java.net.Socket; |
| 37 | import java.util.ArrayList; |
| 38 | import java.util.HashMap; |
| 39 | import java.util.Map; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 40 | import java.util.LinkedList; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 41 | import java.util.List; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 42 | import java.util.Queue; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 43 | import java.util.StringTokenizer; |
| 44 | |
| 45 | /** |
| 46 | * An Event source for getting Monkey Network Script commands from |
| 47 | * over the network. |
| 48 | */ |
| 49 | public class MonkeySourceNetwork implements MonkeyEventSource { |
| 50 | private static final String TAG = "MonkeyStub"; |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 51 | /* The version of the monkey network protocol */ |
| 52 | public static final int MONKEY_NETWORK_VERSION = 2; |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 53 | private static DeferredReturn deferredReturn; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 54 | |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 55 | /** |
| 56 | * ReturnValue from the MonkeyCommand that indicates whether the |
| 57 | * command was sucessful or not. |
| 58 | */ |
| 59 | public static class MonkeyCommandReturn { |
| 60 | private final boolean success; |
| 61 | private final String message; |
| 62 | |
| 63 | public MonkeyCommandReturn(boolean success) { |
| 64 | this.success = success; |
| 65 | this.message = null; |
| 66 | } |
| 67 | |
| 68 | public MonkeyCommandReturn(boolean success, |
| 69 | String message) { |
| 70 | this.success = success; |
| 71 | this.message = message; |
| 72 | } |
| 73 | |
| 74 | boolean hasMessage() { |
| 75 | return message != null; |
| 76 | } |
| 77 | |
| 78 | String getMessage() { |
| 79 | return message; |
| 80 | } |
| 81 | |
| 82 | boolean wasSuccessful() { |
| 83 | return success; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | public final static MonkeyCommandReturn OK = new MonkeyCommandReturn(true); |
| 88 | public final static MonkeyCommandReturn ERROR = new MonkeyCommandReturn(false); |
| 89 | public final static MonkeyCommandReturn EARG = new MonkeyCommandReturn(false, |
| 90 | "Invalid Argument"); |
| 91 | |
| 92 | /** |
| 93 | * Interface that MonkeyCommands must implement. |
| 94 | */ |
| 95 | public interface MonkeyCommand { |
| 96 | /** |
| 97 | * Translate the command line into a sequence of MonkeyEvents. |
| 98 | * |
| 99 | * @param command the command line. |
| 100 | * @param queue the command queue. |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 101 | * @return MonkeyCommandReturn indicating what happened. |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 102 | */ |
| 103 | MonkeyCommandReturn translateCommand(List<String> command, CommandQueue queue); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Command to simulate closing and opening the keyboard. |
| 108 | */ |
| 109 | private static class FlipCommand implements MonkeyCommand { |
| 110 | // flip open |
| 111 | // flip closed |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 112 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 113 | CommandQueue queue) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 114 | if (command.size() > 1) { |
| 115 | String direction = command.get(1); |
| 116 | if ("open".equals(direction)) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 117 | queue.enqueueEvent(new MonkeyFlipEvent(true)); |
| 118 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 119 | } else if ("close".equals(direction)) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 120 | queue.enqueueEvent(new MonkeyFlipEvent(false)); |
| 121 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 122 | } |
| 123 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 124 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 125 | } |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Command to send touch events to the input system. |
| 130 | */ |
| 131 | private static class TouchCommand implements MonkeyCommand { |
| 132 | // touch [down|up|move] [x] [y] |
| 133 | // touch down 120 120 |
| 134 | // touch move 140 140 |
| 135 | // touch up 140 140 |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 136 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 137 | CommandQueue queue) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 138 | if (command.size() == 4) { |
| 139 | String actionName = command.get(1); |
| 140 | int x = 0; |
| 141 | int y = 0; |
| 142 | try { |
| 143 | x = Integer.parseInt(command.get(2)); |
| 144 | y = Integer.parseInt(command.get(3)); |
| 145 | } catch (NumberFormatException e) { |
| 146 | // Ok, it wasn't a number |
| 147 | Log.e(TAG, "Got something that wasn't a number", e); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 148 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | // figure out the action |
| 152 | int action = -1; |
| 153 | if ("down".equals(actionName)) { |
| 154 | action = MotionEvent.ACTION_DOWN; |
| 155 | } else if ("up".equals(actionName)) { |
| 156 | action = MotionEvent.ACTION_UP; |
| 157 | } else if ("move".equals(actionName)) { |
| 158 | action = MotionEvent.ACTION_MOVE; |
| 159 | } |
| 160 | if (action == -1) { |
| 161 | Log.e(TAG, "Got a bad action: " + actionName); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 162 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 163 | } |
| 164 | |
Jeff Brown | 585ab96 | 2010-10-04 20:58:18 -0700 | [diff] [blame] | 165 | queue.enqueueEvent(new MonkeyTouchEvent(action) |
| 166 | .addPointer(0, x, y)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 167 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 168 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 169 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 170 | } |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | * Command to send Trackball events to the input system. |
| 175 | */ |
| 176 | private static class TrackballCommand implements MonkeyCommand { |
| 177 | // trackball [dx] [dy] |
| 178 | // trackball 1 0 -- move right |
| 179 | // trackball -1 0 -- move left |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 180 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 181 | CommandQueue queue) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 182 | if (command.size() == 3) { |
| 183 | int dx = 0; |
| 184 | int dy = 0; |
| 185 | try { |
| 186 | dx = Integer.parseInt(command.get(1)); |
| 187 | dy = Integer.parseInt(command.get(2)); |
| 188 | } catch (NumberFormatException e) { |
| 189 | // Ok, it wasn't a number |
| 190 | Log.e(TAG, "Got something that wasn't a number", e); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 191 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 192 | } |
Jeff Brown | 585ab96 | 2010-10-04 20:58:18 -0700 | [diff] [blame] | 193 | queue.enqueueEvent(new MonkeyTrackballEvent(MotionEvent.ACTION_MOVE) |
| 194 | .addPointer(0, dx, dy)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 195 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 196 | |
| 197 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 198 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 199 | } |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * Command to send Key events to the input system. |
| 204 | */ |
| 205 | private static class KeyCommand implements MonkeyCommand { |
| 206 | // key [down|up] [keycode] |
| 207 | // key down 82 |
| 208 | // key up 82 |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 209 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 210 | CommandQueue queue) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 211 | if (command.size() == 3) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 212 | int keyCode = getKeyCode(command.get(2)); |
| 213 | if (keyCode < 0) { |
| 214 | // Ok, you gave us something bad. |
| 215 | Log.e(TAG, "Can't find keyname: " + command.get(2)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 216 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 217 | } |
| 218 | Log.d(TAG, "keycode: " + keyCode); |
| 219 | int action = -1; |
| 220 | if ("down".equals(command.get(1))) { |
| 221 | action = KeyEvent.ACTION_DOWN; |
| 222 | } else if ("up".equals(command.get(1))) { |
| 223 | action = KeyEvent.ACTION_UP; |
| 224 | } |
| 225 | if (action == -1) { |
| 226 | Log.e(TAG, "got unknown action."); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 227 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 228 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 229 | queue.enqueueEvent(new MonkeyKeyEvent(action, keyCode)); |
| 230 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 231 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 232 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 233 | } |
| 234 | } |
| 235 | |
| 236 | /** |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 237 | * Get an integer keycode value from a given keyname. |
| 238 | * |
| 239 | * @param keyName the key name to get the code for |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 240 | * @return the integer keycode value, or -1 on error. |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 241 | */ |
| 242 | private static int getKeyCode(String keyName) { |
| 243 | int keyCode = -1; |
| 244 | try { |
| 245 | keyCode = Integer.parseInt(keyName); |
| 246 | } catch (NumberFormatException e) { |
| 247 | // Ok, it wasn't a number, see if we have a |
| 248 | // keycode name for it |
| 249 | keyCode = MonkeySourceRandom.getKeyCode(keyName); |
Bill Napier | 3d3d642 | 2012-02-16 16:58:19 -0800 | [diff] [blame] | 250 | if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 251 | // OK, one last ditch effort to find a match. |
| 252 | // Build the KEYCODE_STRING from the string |
| 253 | // we've been given and see if that key |
| 254 | // exists. This would allow you to do "key |
| 255 | // down menu", for example. |
| 256 | keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); |
Bill Napier | 3d3d642 | 2012-02-16 16:58:19 -0800 | [diff] [blame] | 257 | if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { |
| 258 | // Still unknown |
| 259 | return -1; |
| 260 | } |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 261 | } |
| 262 | } |
| 263 | return keyCode; |
| 264 | } |
| 265 | |
| 266 | /** |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 267 | * Command to put the Monkey to sleep. |
| 268 | */ |
| 269 | private static class SleepCommand implements MonkeyCommand { |
| 270 | // sleep 2000 |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 271 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 272 | CommandQueue queue) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 273 | if (command.size() == 2) { |
| 274 | int sleep = -1; |
| 275 | String sleepStr = command.get(1); |
| 276 | try { |
| 277 | sleep = Integer.parseInt(sleepStr); |
| 278 | } catch (NumberFormatException e) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 279 | Log.e(TAG, "Not a number: " + sleepStr, e); |
| 280 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 281 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 282 | queue.enqueueEvent(new MonkeyThrottleEvent(sleep)); |
| 283 | return OK; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 284 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 285 | return EARG; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 286 | } |
| 287 | } |
| 288 | |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 289 | /** |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 290 | * Command to type a string |
| 291 | */ |
| 292 | private static class TypeCommand implements MonkeyCommand { |
| 293 | // wake |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 294 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 295 | CommandQueue queue) { |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 296 | if (command.size() == 2) { |
| 297 | String str = command.get(1); |
| 298 | |
| 299 | char[] chars = str.toString().toCharArray(); |
| 300 | |
| 301 | // Convert the string to an array of KeyEvent's for |
| 302 | // the built in keymap. |
| 303 | KeyCharacterMap keyCharacterMap = KeyCharacterMap. |
Jeff Brown | f083bd4 | 2010-11-02 15:53:10 -0700 | [diff] [blame] | 304 | load(KeyCharacterMap.VIRTUAL_KEYBOARD); |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 305 | KeyEvent[] events = keyCharacterMap.getEvents(chars); |
| 306 | |
| 307 | // enqueue all the events we just got. |
| 308 | for (KeyEvent event : events) { |
| 309 | queue.enqueueEvent(new MonkeyKeyEvent(event)); |
| 310 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 311 | return OK; |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 312 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 313 | return EARG; |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 314 | } |
| 315 | } |
| 316 | |
| 317 | /** |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 318 | * Command to wake the device up |
| 319 | */ |
| 320 | private static class WakeCommand implements MonkeyCommand { |
| 321 | // wake |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 322 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 323 | CommandQueue queue) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 324 | if (!wake()) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 325 | return ERROR; |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 326 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 327 | return OK; |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 328 | } |
| 329 | } |
| 330 | |
| 331 | /** |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 332 | * Command to "tap" at a location (Sends a down and up touch |
| 333 | * event). |
| 334 | */ |
| 335 | private static class TapCommand implements MonkeyCommand { |
| 336 | // tap x y |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 337 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 338 | CommandQueue queue) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 339 | if (command.size() == 3) { |
| 340 | int x = 0; |
| 341 | int y = 0; |
| 342 | try { |
| 343 | x = Integer.parseInt(command.get(1)); |
| 344 | y = Integer.parseInt(command.get(2)); |
| 345 | } catch (NumberFormatException e) { |
| 346 | // Ok, it wasn't a number |
| 347 | Log.e(TAG, "Got something that wasn't a number", e); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 348 | return EARG; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 349 | } |
| 350 | |
Jeff Brown | 585ab96 | 2010-10-04 20:58:18 -0700 | [diff] [blame] | 351 | queue.enqueueEvent(new MonkeyTouchEvent(MotionEvent.ACTION_DOWN) |
| 352 | .addPointer(0, x, y)); |
| 353 | queue.enqueueEvent(new MonkeyTouchEvent(MotionEvent.ACTION_UP) |
| 354 | .addPointer(0, x, y)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 355 | return OK; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 356 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 357 | return EARG; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 358 | } |
| 359 | } |
| 360 | |
| 361 | /** |
| 362 | * Command to "press" a buttons (Sends an up and down key event.) |
| 363 | */ |
| 364 | private static class PressCommand implements MonkeyCommand { |
| 365 | // press keycode |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 366 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 367 | CommandQueue queue) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 368 | if (command.size() == 2) { |
| 369 | int keyCode = getKeyCode(command.get(1)); |
| 370 | if (keyCode < 0) { |
| 371 | // Ok, you gave us something bad. |
| 372 | Log.e(TAG, "Can't find keyname: " + command.get(1)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 373 | return EARG; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 374 | } |
| 375 | |
| 376 | queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode)); |
| 377 | queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode)); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 378 | return OK; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 379 | |
| 380 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 381 | return EARG; |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 382 | } |
| 383 | } |
| 384 | |
| 385 | /** |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 386 | * Command to defer the return of another command until the given event occurs. |
| 387 | * deferreturn takes three arguments. It takes an event to wait for (e.g. waiting for the |
| 388 | * device to display a different activity would the "screenchange" event), a |
| 389 | * timeout, which is the number of microseconds to wait for the event to occur, and it takes |
| 390 | * a command. The command can be any other Monkey command that can be issued over the network |
| 391 | * (e.g. press KEYCODE_HOME). deferreturn will then run this command, return an OK, wait for |
| 392 | * the event to occur and return the deferred return value when either the event occurs or |
| 393 | * when the timeout is reached (whichever occurs first). Note that there is no difference |
| 394 | * between an event occurring and the timeout being reached; the client will have to verify |
| 395 | * that the change actually occured. |
| 396 | * |
| 397 | * Example: |
| 398 | * deferreturn screenchange 1000 press KEYCODE_HOME |
| 399 | * This command will press the home key on the device and then wait for the screen to change |
| 400 | * for up to one second. Either the screen will change, and the results fo the key press will |
| 401 | * be returned to the client, or the timeout will be reached, and the results for the key |
| 402 | * press will be returned to the client. |
| 403 | */ |
| 404 | private static class DeferReturnCommand implements MonkeyCommand { |
| 405 | // deferreturn [event] [timeout (ms)] [command] |
| 406 | // deferreturn screenchange 100 tap 10 10 |
| 407 | public MonkeyCommandReturn translateCommand(List<String> command, |
| 408 | CommandQueue queue) { |
| 409 | if (command.size() > 3) { |
| 410 | String event = command.get(1); |
| 411 | int eventId; |
| 412 | if (event.equals("screenchange")) { |
| 413 | eventId = DeferredReturn.ON_WINDOW_STATE_CHANGE; |
| 414 | } else { |
| 415 | return EARG; |
| 416 | } |
| 417 | long timeout = Long.parseLong(command.get(2)); |
| 418 | MonkeyCommand deferredCommand = COMMAND_MAP.get(command.get(3)); |
| 419 | if (deferredCommand != null) { |
| 420 | List<String> parts = command.subList(3, command.size()); |
| 421 | MonkeyCommandReturn ret = deferredCommand.translateCommand(parts, queue); |
| 422 | deferredReturn = new DeferredReturn(eventId, ret, timeout); |
| 423 | return OK; |
| 424 | } |
| 425 | } |
| 426 | return EARG; |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | |
| 431 | /** |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 432 | * Force the device to wake up. |
| 433 | * |
| 434 | * @return true if woken up OK. |
| 435 | */ |
| 436 | private static final boolean wake() { |
| 437 | IPowerManager pm = |
| 438 | IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); |
| 439 | try { |
Dianne Hackborn | d574af0 | 2015-07-14 17:57:51 -0700 | [diff] [blame] | 440 | pm.wakeUp(SystemClock.uptimeMillis(), "Monkey", null); |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 441 | } catch (RemoteException e) { |
| 442 | Log.e(TAG, "Got remote exception", e); |
| 443 | return false; |
| 444 | } |
| 445 | return true; |
| 446 | } |
| 447 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 448 | // This maps from command names to command implementations. |
| 449 | private static final Map<String, MonkeyCommand> COMMAND_MAP = new HashMap<String, MonkeyCommand>(); |
| 450 | |
| 451 | static { |
| 452 | // Add in all the commands we support |
| 453 | COMMAND_MAP.put("flip", new FlipCommand()); |
| 454 | COMMAND_MAP.put("touch", new TouchCommand()); |
| 455 | COMMAND_MAP.put("trackball", new TrackballCommand()); |
| 456 | COMMAND_MAP.put("key", new KeyCommand()); |
| 457 | COMMAND_MAP.put("sleep", new SleepCommand()); |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 458 | COMMAND_MAP.put("wake", new WakeCommand()); |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 459 | COMMAND_MAP.put("tap", new TapCommand()); |
| 460 | COMMAND_MAP.put("press", new PressCommand()); |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 461 | COMMAND_MAP.put("type", new TypeCommand()); |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 462 | COMMAND_MAP.put("listvar", new MonkeySourceNetworkVars.ListVarCommand()); |
| 463 | COMMAND_MAP.put("getvar", new MonkeySourceNetworkVars.GetVarCommand()); |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 464 | COMMAND_MAP.put("listviews", new MonkeySourceNetworkViews.ListViewsCommand()); |
| 465 | COMMAND_MAP.put("queryview", new MonkeySourceNetworkViews.QueryViewCommand()); |
| 466 | COMMAND_MAP.put("getrootview", new MonkeySourceNetworkViews.GetRootViewCommand()); |
| 467 | COMMAND_MAP.put("getviewswithtext", |
| 468 | new MonkeySourceNetworkViews.GetViewsWithTextCommand()); |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 469 | COMMAND_MAP.put("deferreturn", new DeferReturnCommand()); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | // QUIT command |
| 473 | private static final String QUIT = "quit"; |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 474 | // DONE command |
| 475 | private static final String DONE = "done"; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 476 | |
| 477 | // command response strings |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 478 | private static final String OK_STR = "OK"; |
| 479 | private static final String ERROR_STR = "ERROR"; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 480 | |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 481 | public static interface CommandQueue { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 482 | /** |
| 483 | * Enqueue an event to be returned later. This allows a |
| 484 | * command to return multiple events. Commands using the |
| 485 | * command queue still have to return a valid event from their |
| 486 | * translateCommand method. The returned command will be |
| 487 | * executed before anything put into the queue. |
| 488 | * |
| 489 | * @param e the event to be enqueued. |
| 490 | */ |
| 491 | public void enqueueEvent(MonkeyEvent e); |
| 492 | }; |
| 493 | |
| 494 | // Queue of Events to be processed. This allows commands to push |
| 495 | // multiple events into the queue to be processed. |
| 496 | private static class CommandQueueImpl implements CommandQueue{ |
| 497 | private final Queue<MonkeyEvent> queuedEvents = new LinkedList<MonkeyEvent>(); |
| 498 | |
| 499 | public void enqueueEvent(MonkeyEvent e) { |
| 500 | queuedEvents.offer(e); |
| 501 | } |
| 502 | |
| 503 | /** |
| 504 | * Get the next queued event to excecute. |
| 505 | * |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 506 | * @return the next event, or null if there aren't any more. |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 507 | */ |
| 508 | public MonkeyEvent getNextQueuedEvent() { |
| 509 | return queuedEvents.poll(); |
| 510 | } |
| 511 | }; |
| 512 | |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 513 | // A holder class for a deferred return value. This allows us to defer returning the success of |
| 514 | // a call until a given event has occurred. |
| 515 | private static class DeferredReturn { |
| 516 | public static final int ON_WINDOW_STATE_CHANGE = 1; |
| 517 | |
| 518 | private int event; |
| 519 | private MonkeyCommandReturn deferredReturn; |
| 520 | private long timeout; |
| 521 | |
| 522 | public DeferredReturn(int event, MonkeyCommandReturn deferredReturn, long timeout) { |
| 523 | this.event = event; |
| 524 | this.deferredReturn = deferredReturn; |
| 525 | this.timeout = timeout; |
| 526 | } |
| 527 | |
| 528 | /** |
| 529 | * Wait until the given event has occurred before returning the value. |
| 530 | * @return The MonkeyCommandReturn from the command that was deferred. |
| 531 | */ |
| 532 | public MonkeyCommandReturn waitForEvent() { |
| 533 | switch(event) { |
| 534 | case ON_WINDOW_STATE_CHANGE: |
| 535 | try { |
Svetoslav Ganov | bdf03ad | 2011-11-30 17:48:42 -0800 | [diff] [blame] | 536 | synchronized(MonkeySourceNetworkViews.class) { |
| 537 | MonkeySourceNetworkViews.class.wait(timeout); |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 538 | } |
| 539 | } catch(InterruptedException e) { |
| 540 | Log.d(TAG, "Deferral interrupted: " + e.getMessage()); |
| 541 | } |
| 542 | } |
| 543 | return deferredReturn; |
| 544 | } |
| 545 | }; |
| 546 | |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 547 | private final CommandQueueImpl commandQueue = new CommandQueueImpl(); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 548 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 549 | private BufferedReader input; |
| 550 | private PrintWriter output; |
| 551 | private boolean started = false; |
| 552 | |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 553 | private ServerSocket serverSocket; |
| 554 | private Socket clientSocket; |
| 555 | |
| 556 | public MonkeySourceNetwork(int port) throws IOException { |
| 557 | // Only bind this to local host. This means that you can only |
| 558 | // talk to the monkey locally, or though adb port forwarding. |
| 559 | serverSocket = new ServerSocket(port, |
| 560 | 0, // default backlog |
| 561 | InetAddress.getLocalHost()); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 562 | } |
| 563 | |
| 564 | /** |
| 565 | * Start a network server listening on the specified port. The |
| 566 | * network protocol is a line oriented protocol, where each line |
| 567 | * is a different command that can be run. |
| 568 | * |
| 569 | * @param port the port to listen on |
| 570 | */ |
| 571 | private void startServer() throws IOException { |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 572 | clientSocket = serverSocket.accept(); |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 573 | // At this point, we have a client connected. |
| 574 | // Attach the accessibility listeners so that we can start receiving |
| 575 | // view events. Do this before wake so we can catch the wake event |
| 576 | // if possible. |
| 577 | MonkeySourceNetworkViews.setup(); |
| 578 | // Wake the device up in preparation for doing some commands. |
Bill Napier | ad90429 | 2009-08-10 13:22:32 -0700 | [diff] [blame] | 579 | wake(); |
| 580 | |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 581 | input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 582 | // auto-flush |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 583 | output = new PrintWriter(clientSocket.getOutputStream(), true); |
| 584 | } |
| 585 | |
| 586 | /** |
| 587 | * Stop the server from running so it can reconnect a new client. |
| 588 | */ |
| 589 | private void stopServer() throws IOException { |
| 590 | clientSocket.close(); |
Svetoslav Ganov | 00fc93c | 2013-01-02 10:13:10 -0800 | [diff] [blame] | 591 | MonkeySourceNetworkViews.teardown(); |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 592 | input.close(); |
| 593 | output.close(); |
| 594 | started = false; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 595 | } |
| 596 | |
| 597 | /** |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 598 | * Helper function for commandLineSplit that replaces quoted |
| 599 | * charaters with their real values. |
| 600 | * |
| 601 | * @param input the string to do replacement on. |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 602 | * @return the results with the characters replaced. |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 603 | */ |
| 604 | private static String replaceQuotedChars(String input) { |
| 605 | return input.replace("\\\"", "\""); |
| 606 | } |
| 607 | |
| 608 | /** |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 609 | * This function splits the given line into String parts. It obey's quoted |
| 610 | * strings and returns them as a single part. |
| 611 | * |
| 612 | * "This is a test" -> returns only one element |
| 613 | * This is a test -> returns four elements |
| 614 | * |
| 615 | * @param line the line to parse |
| 616 | * @return the List of elements |
| 617 | */ |
| 618 | private static List<String> commandLineSplit(String line) { |
| 619 | ArrayList<String> result = new ArrayList<String>(); |
| 620 | StringTokenizer tok = new StringTokenizer(line); |
| 621 | |
| 622 | boolean insideQuote = false; |
| 623 | StringBuffer quotedWord = new StringBuffer(); |
| 624 | while (tok.hasMoreTokens()) { |
| 625 | String cur = tok.nextToken(); |
| 626 | if (!insideQuote && cur.startsWith("\"")) { |
| 627 | // begin quote |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 628 | quotedWord.append(replaceQuotedChars(cur)); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 629 | insideQuote = true; |
| 630 | } else if (insideQuote) { |
| 631 | // end quote |
| 632 | if (cur.endsWith("\"")) { |
| 633 | insideQuote = false; |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 634 | quotedWord.append(" ").append(replaceQuotedChars(cur)); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 635 | String word = quotedWord.toString(); |
| 636 | |
| 637 | // trim off the quotes |
| 638 | result.add(word.substring(1, word.length() - 1)); |
| 639 | } else { |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 640 | quotedWord.append(" ").append(replaceQuotedChars(cur)); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 641 | } |
| 642 | } else { |
Bill Napier | 3faef17 | 2009-08-11 16:07:38 -0700 | [diff] [blame] | 643 | result.add(replaceQuotedChars(cur)); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 644 | } |
| 645 | } |
| 646 | return result; |
| 647 | } |
| 648 | |
| 649 | /** |
| 650 | * Translate the given command line into a MonkeyEvent. |
| 651 | * |
| 652 | * @param commandLine the full command line given. |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 653 | */ |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 654 | private void translateCommand(String commandLine) { |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 655 | Log.d(TAG, "translateCommand: " + commandLine); |
| 656 | List<String> parts = commandLineSplit(commandLine); |
| 657 | if (parts.size() > 0) { |
| 658 | MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); |
| 659 | if (command != null) { |
Michael Wright | b36bed5 | 2011-06-14 16:44:41 -0700 | [diff] [blame] | 660 | MonkeyCommandReturn ret = command.translateCommand(parts, commandQueue); |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 661 | handleReturn(ret); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 662 | } |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 663 | } |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 664 | } |
| 665 | |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 666 | private void handleReturn(MonkeyCommandReturn ret) { |
| 667 | if (ret.wasSuccessful()) { |
| 668 | if (ret.hasMessage()) { |
| 669 | returnOk(ret.getMessage()); |
| 670 | } else { |
| 671 | returnOk(); |
| 672 | } |
| 673 | } else { |
| 674 | if (ret.hasMessage()) { |
| 675 | returnError(ret.getMessage()); |
| 676 | } else { |
| 677 | returnError(); |
| 678 | } |
| 679 | } |
| 680 | } |
| 681 | |
| 682 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 683 | public MonkeyEvent getNextEvent() { |
| 684 | if (!started) { |
| 685 | try { |
| 686 | startServer(); |
| 687 | } catch (IOException e) { |
| 688 | Log.e(TAG, "Got IOException from server", e); |
| 689 | return null; |
| 690 | } |
| 691 | started = true; |
| 692 | } |
| 693 | |
| 694 | // Now, get the next command. This call may block, but that's OK |
| 695 | try { |
| 696 | while (true) { |
Bill Napier | bdc2220 | 2009-08-10 20:50:30 -0700 | [diff] [blame] | 697 | // Check to see if we have any events queued up. If |
| 698 | // we do, use those until we have no more. Then get |
| 699 | // more input from the user. |
| 700 | MonkeyEvent queuedEvent = commandQueue.getNextQueuedEvent(); |
| 701 | if (queuedEvent != null) { |
| 702 | // dispatch the event |
| 703 | return queuedEvent; |
| 704 | } |
| 705 | |
Michael Wright | c6c89b9 | 2011-07-18 18:35:45 -0700 | [diff] [blame] | 706 | // Check to see if we have any returns that have been deferred. If so, now that |
| 707 | // we've run the queued commands, wait for the given event to happen (or the timeout |
| 708 | // to be reached), and handle the deferred MonkeyCommandReturn. |
| 709 | if (deferredReturn != null) { |
| 710 | Log.d(TAG, "Waiting for event"); |
| 711 | MonkeyCommandReturn ret = deferredReturn.waitForEvent(); |
| 712 | deferredReturn = null; |
| 713 | handleReturn(ret); |
| 714 | } |
| 715 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 716 | String command = input.readLine(); |
| 717 | if (command == null) { |
| 718 | Log.d(TAG, "Connection dropped."); |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 719 | // Treat this exactly the same as if the user had |
| 720 | // ended the session cleanly with a done commant. |
| 721 | command = DONE; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 722 | } |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 723 | |
| 724 | if (DONE.equals(command)) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 725 | // stop the server so it can accept new connections |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 726 | try { |
| 727 | stopServer(); |
| 728 | } catch (IOException e) { |
| 729 | Log.e(TAG, "Got IOException shutting down!", e); |
| 730 | return null; |
| 731 | } |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 732 | // return a noop event so we keep executing the main |
| 733 | // loop |
| 734 | return new MonkeyNoopEvent(); |
Bill Napier | 9d8557c | 2009-08-11 16:36:43 -0700 | [diff] [blame] | 735 | } |
| 736 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 737 | // Do quit checking here |
| 738 | if (QUIT.equals(command)) { |
| 739 | // then we're done |
| 740 | Log.d(TAG, "Quit requested"); |
| 741 | // let the host know the command ran OK |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 742 | returnOk(); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 743 | return null; |
| 744 | } |
| 745 | |
| 746 | // Do comment checking here. Comments aren't a |
| 747 | // command, so we don't echo anything back to the |
| 748 | // user. |
| 749 | if (command.startsWith("#")) { |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 750 | // keep going |
| 751 | continue; |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 752 | } |
| 753 | |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 754 | // Translate the command line. This will handle returning error/ok to the user |
| 755 | translateCommand(command); |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 756 | } |
| 757 | } catch (IOException e) { |
| 758 | Log.e(TAG, "Exception: ", e); |
| 759 | return null; |
| 760 | } |
| 761 | } |
| 762 | |
Bill Napier | f948160 | 2009-08-17 11:20:15 -0700 | [diff] [blame] | 763 | /** |
| 764 | * Returns ERROR to the user. |
| 765 | */ |
| 766 | private void returnError() { |
| 767 | output.println(ERROR_STR); |
| 768 | } |
| 769 | |
| 770 | /** |
| 771 | * Returns ERROR to the user. |
| 772 | * |
| 773 | * @param msg the error message to include |
| 774 | */ |
| 775 | private void returnError(String msg) { |
| 776 | output.print(ERROR_STR); |
| 777 | output.print(":"); |
| 778 | output.println(msg); |
| 779 | } |
| 780 | |
| 781 | /** |
| 782 | * Returns OK to the user. |
| 783 | */ |
| 784 | private void returnOk() { |
| 785 | output.println(OK_STR); |
| 786 | } |
| 787 | |
| 788 | /** |
| 789 | * Returns OK to the user. |
| 790 | * |
| 791 | * @param returnValue the value to return from this command. |
| 792 | */ |
| 793 | private void returnOk(String returnValue) { |
| 794 | output.print(OK_STR); |
| 795 | output.print(":"); |
| 796 | output.println(returnValue); |
| 797 | } |
| 798 | |
Bill Napier | a68dbdb | 2009-08-07 11:34:12 -0700 | [diff] [blame] | 799 | public void setVerbose(int verbose) { |
| 800 | // We're not particualy verbose |
| 801 | } |
| 802 | |
| 803 | public boolean validate() { |
| 804 | // we have no pre-conditions to validate |
| 805 | return true; |
| 806 | } |
| 807 | } |