| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library android; | 5 library android; |
| 6 | 6 |
| 7 import "dart:async"; | 7 import "dart:async"; |
| 8 import "dart:convert" show LineSplitter, UTF8; | 8 import "dart:convert" show LineSplitter, UTF8; |
| 9 import "dart:core"; | 9 import "dart:core"; |
| 10 import "dart:io"; | 10 import "dart:io"; |
| 11 | 11 |
| 12 import "path.dart"; | 12 import "path.dart"; |
| 13 import "utils.dart"; | 13 import "utils.dart"; |
| 14 | 14 |
| 15 Future _executeCommand(String executable, | 15 Future _executeCommand(String executable, List<String> args, |
| 16 List<String> args, | 16 [String stdin = ""]) { |
| 17 [String stdin = ""]) { | |
| 18 return _executeCommandRaw(executable, args, stdin).then((results) => null); | 17 return _executeCommandRaw(executable, args, stdin).then((results) => null); |
| 19 } | 18 } |
| 20 | 19 |
| 21 Future _executeCommandGetOutput(String executable, | 20 Future _executeCommandGetOutput(String executable, List<String> args, |
| 22 List<String> args, | 21 [String stdin = ""]) { |
| 23 [String stdin = ""]) { | 22 return _executeCommandRaw(executable, args, stdin).then((output) => output); |
| 24 return _executeCommandRaw(executable, args, stdin) | |
| 25 .then((output) => output); | |
| 26 } | 23 } |
| 27 | 24 |
| 28 /** | 25 /** |
| 29 * [_executeCommandRaw] will write [stdin] to the standard input of the created | 26 * [_executeCommandRaw] will write [stdin] to the standard input of the created |
| 30 * process and will return a tuple (stdout, stderr). | 27 * process and will return a tuple (stdout, stderr). |
| 31 * | 28 * |
| 32 * If the exit code of the process was nonzero it will complete with an error. | 29 * If the exit code of the process was nonzero it will complete with an error. |
| 33 * If starting the process failed, it will complete with an error as well. | 30 * If starting the process failed, it will complete with an error as well. |
| 34 */ | 31 */ |
| 35 Future _executeCommandRaw(String executable, | 32 Future _executeCommandRaw(String executable, List<String> args, |
| 36 List<String> args, | 33 [String stdin = ""]) { |
| 37 [String stdin = ""]) { | |
| 38 Future<String> getOutput(Stream<List<int>> stream) { | 34 Future<String> getOutput(Stream<List<int>> stream) { |
| 39 return stream.transform(UTF8.decoder).toList() | 35 return stream |
| 36 .transform(UTF8.decoder) |
| 37 .toList() |
| 40 .then((data) => data.join("")); | 38 .then((data) => data.join("")); |
| 41 } | 39 } |
| 42 | 40 |
| 43 DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'"); | 41 DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'"); |
| 44 return Process.start(executable, args).then((Process process) { | 42 return Process.start(executable, args).then((Process process) { |
| 45 if (stdin != null && stdin != '') { | 43 if (stdin != null && stdin != '') { |
| 46 process.stdin.write(stdin); | 44 process.stdin.write(stdin); |
| 47 } | 45 } |
| 48 process.stdin.close(); | 46 process.stdin.close(); |
| 49 | 47 |
| 50 var futures = [getOutput(process.stdout), | 48 var futures = [ |
| 51 getOutput(process.stderr), | 49 getOutput(process.stdout), |
| 52 process.exitCode]; | 50 getOutput(process.stderr), |
| 51 process.exitCode |
| 52 ]; |
| 53 return Future.wait(futures).then((results) { | 53 return Future.wait(futures).then((results) { |
| 54 bool success = results[2] == 0; | 54 bool success = results[2] == 0; |
| 55 if (!success) { | 55 if (!success) { |
| 56 var error = "Running: '\$ $executable ${args.join(' ')}' failed:" | 56 var error = "Running: '\$ $executable ${args.join(' ')}' failed:" |
| 57 "stdout: \n ${results[0]}" | 57 "stdout: \n ${results[0]}" |
| 58 "stderr: \n ${results[1]}" | 58 "stderr: \n ${results[1]}" |
| 59 "exitCode: \n ${results[2]}"; | 59 "exitCode: \n ${results[2]}"; |
| 60 throw new Exception(error); | 60 throw new Exception(error); |
| 61 } else { | 61 } else { |
| 62 DebugLogger.info("Success: $executable finished"); | 62 DebugLogger.info("Success: $executable finished"); |
| 63 } | 63 } |
| 64 return results[0]; | 64 return results[0]; |
| 65 }); | 65 }); |
| 66 }); | 66 }); |
| 67 } | 67 } |
| 68 | 68 |
| 69 /** | 69 /** |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 void log(String msg) { | 146 void log(String msg) { |
| 147 DebugLogger.info("AndroidEmulator(${_adbDevice.deviceId}): $msg"); | 147 DebugLogger.info("AndroidEmulator(${_adbDevice.deviceId}): $msg"); |
| 148 } | 148 } |
| 149 } | 149 } |
| 150 | 150 |
| 151 /** | 151 /** |
| 152 * Helper class to create avd device configurations. | 152 * Helper class to create avd device configurations. |
| 153 */ | 153 */ |
| 154 class AndroidHelper { | 154 class AndroidHelper { |
| 155 static Future createAvd(String name, String target) { | 155 static Future createAvd(String name, String target) { |
| 156 var args = ['--silent', 'create', 'avd', '--name', '$name', | 156 var args = [ |
| 157 '--target', '$target', '--force', '--abi', 'armeabi-v7a']; | 157 '--silent', |
| 158 'create', |
| 159 'avd', |
| 160 '--name', |
| 161 '$name', |
| 162 '--target', |
| 163 '$target', |
| 164 '--force', |
| 165 '--abi', |
| 166 'armeabi-v7a' |
| 167 ]; |
| 158 // We're adding newlines to stdin to simulate <enter>. | 168 // We're adding newlines to stdin to simulate <enter>. |
| 159 return _executeCommand("android", args, "\n\n\n\n"); | 169 return _executeCommand("android", args, "\n\n\n\n"); |
| 160 } | 170 } |
| 161 } | 171 } |
| 162 | 172 |
| 163 /** | 173 /** |
| 164 * Used for communicating with an emulator or with a real device. | 174 * Used for communicating with an emulator or with a real device. |
| 165 */ | 175 */ |
| 166 class AdbDevice { | 176 class AdbDevice { |
| 167 static const _adbServerStartupTime = const Duration(seconds: 3); | 177 static const _adbServerStartupTime = const Duration(seconds: 3); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 182 * Polls the 'sys.boot_completed' property. Returns as soon as the property is | 192 * Polls the 'sys.boot_completed' property. Returns as soon as the property is |
| 183 * 1. | 193 * 1. |
| 184 */ | 194 */ |
| 185 Future waitForBootCompleted() { | 195 Future waitForBootCompleted() { |
| 186 var timeout = const Duration(seconds: 2); | 196 var timeout = const Duration(seconds: 2); |
| 187 var completer = new Completer(); | 197 var completer = new Completer(); |
| 188 | 198 |
| 189 checkUntilBooted() { | 199 checkUntilBooted() { |
| 190 _adbCommandGetOutput(['shell', 'getprop', 'sys.boot_completed']) | 200 _adbCommandGetOutput(['shell', 'getprop', 'sys.boot_completed']) |
| 191 .then((String stdout) { | 201 .then((String stdout) { |
| 192 stdout = stdout.trim(); | 202 stdout = stdout.trim(); |
| 193 if (stdout == '1') { | 203 if (stdout == '1') { |
| 194 completer.complete(); | 204 completer.complete(); |
| 195 } else { | 205 } else { |
| 196 new Timer(timeout, checkUntilBooted); | 206 new Timer(timeout, checkUntilBooted); |
| 197 } | 207 } |
| 198 }).catchError((error) { | 208 }).catchError((error) { |
| 199 new Timer(timeout, checkUntilBooted); | 209 new Timer(timeout, checkUntilBooted); |
| 200 }); | 210 }); |
| 201 } | 211 } |
| 202 checkUntilBooted(); | 212 checkUntilBooted(); |
| 203 return completer.future; | 213 return completer.future; |
| 204 } | 214 } |
| 205 | 215 |
| 206 /** | 216 /** |
| 207 * Put adb in root mode. | 217 * Put adb in root mode. |
| 208 */ | 218 */ |
| 209 Future adbRoot() { | 219 Future adbRoot() { |
| 210 var adbRootCompleter = new Completer(); | 220 var adbRootCompleter = new Completer(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 */ | 253 */ |
| 244 Future installApk(Path filename) { | 254 Future installApk(Path filename) { |
| 245 return _adbCommand( | 255 return _adbCommand( |
| 246 ['install', '-i', 'com.google.android.feedback', '-r', '$filename']); | 256 ['install', '-i', 'com.google.android.feedback', '-r', '$filename']); |
| 247 } | 257 } |
| 248 | 258 |
| 249 /** | 259 /** |
| 250 * Start the given intent on the device. | 260 * Start the given intent on the device. |
| 251 */ | 261 */ |
| 252 Future startActivity(Intent intent) { | 262 Future startActivity(Intent intent) { |
| 253 var arguments = ['shell', 'am', 'start', '-W', | 263 var arguments = [ |
| 254 '-a', intent.action, | 264 'shell', |
| 255 '-n', "${intent.package}/${intent.activity}"]; | 265 'am', |
| 266 'start', |
| 267 '-W', |
| 268 '-a', |
| 269 intent.action, |
| 270 '-n', |
| 271 "${intent.package}/${intent.activity}" |
| 272 ]; |
| 256 if (intent.dataUri != null) { | 273 if (intent.dataUri != null) { |
| 257 arguments.addAll(['-d', intent.dataUri]); | 274 arguments.addAll(['-d', intent.dataUri]); |
| 258 } | 275 } |
| 259 return _adbCommand(arguments); | 276 return _adbCommand(arguments); |
| 260 } | 277 } |
| 261 | 278 |
| 262 /** | 279 /** |
| 263 * Force to stop everything associated with [package]. | 280 * Force to stop everything associated with [package]. |
| 264 */ | 281 */ |
| 265 Future forceStop(String package) { | 282 Future forceStop(String package) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 * Helper to list all adb devices available. | 322 * Helper to list all adb devices available. |
| 306 */ | 323 */ |
| 307 class AdbHelper { | 324 class AdbHelper { |
| 308 static RegExp _deviceLineRegexp = | 325 static RegExp _deviceLineRegexp = |
| 309 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true); | 326 new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true); |
| 310 | 327 |
| 311 static Future<List<String>> listDevices() { | 328 static Future<List<String>> listDevices() { |
| 312 return Process.run('adb', ['devices']).then((ProcessResult result) { | 329 return Process.run('adb', ['devices']).then((ProcessResult result) { |
| 313 if (result.exitCode != 0) { | 330 if (result.exitCode != 0) { |
| 314 throw new Exception("Could not list devices [stdout: ${result.stdout}," | 331 throw new Exception("Could not list devices [stdout: ${result.stdout}," |
| 315 "stderr: ${result.stderr}]"); | 332 "stderr: ${result.stderr}]"); |
| 316 } | 333 } |
| 317 return _deviceLineRegexp.allMatches(result.stdout) | 334 return _deviceLineRegexp |
| 318 .map((Match m) => m.group(1)).toList(); | 335 .allMatches(result.stdout) |
| 336 .map((Match m) => m.group(1)) |
| 337 .toList(); |
| 319 }); | 338 }); |
| 320 } | 339 } |
| 321 } | 340 } |
| 322 | 341 |
| 323 /** | 342 /** |
| 324 * Represents an android intent. | 343 * Represents an android intent. |
| 325 */ | 344 */ |
| 326 class Intent { | 345 class Intent { |
| 327 String action; | 346 String action; |
| 328 String package; | 347 String package; |
| 329 String activity; | 348 String activity; |
| 330 String dataUri; | 349 String dataUri; |
| 331 | 350 |
| 332 Intent(this.action, this.package, this.activity, [this.dataUri]); | 351 Intent(this.action, this.package, this.activity, [this.dataUri]); |
| 333 } | 352 } |
| 334 | |
| OLD | NEW |