From 5aa76327f5292ce1d1d23e96381b93c0272e4a2c Mon Sep 17 00:00:00 2001 From: Ramanan Rajeswaran Date: Mon, 17 Aug 2009 08:52:11 -0700 Subject: [PATCH] Add monkeyrunner to code base --- tools/monkeyrunner/Android.mk | 18 + tools/monkeyrunner/MODULE_LICENSE_APACHE2 | 0 tools/monkeyrunner/NOTICE | 190 +++++++ tools/monkeyrunner/etc/Android.mk | 20 + tools/monkeyrunner/etc/manifest.txt | 1 + tools/monkeyrunner/etc/monkeyrunner | 74 +++ tools/monkeyrunner/src/Android.mk | 29 ++ .../android/monkeyrunner/MonkeyRunner.java | 480 ++++++++++++++++++ .../android/monkeyrunner/ScriptRunner.java | 96 ++++ 9 files changed, 908 insertions(+) create mode 100644 tools/monkeyrunner/Android.mk create mode 100644 tools/monkeyrunner/MODULE_LICENSE_APACHE2 create mode 100644 tools/monkeyrunner/NOTICE create mode 100644 tools/monkeyrunner/etc/Android.mk create mode 100644 tools/monkeyrunner/etc/manifest.txt create mode 100755 tools/monkeyrunner/etc/monkeyrunner create mode 100644 tools/monkeyrunner/src/Android.mk create mode 100644 tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java create mode 100644 tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java diff --git a/tools/monkeyrunner/Android.mk b/tools/monkeyrunner/Android.mk new file mode 100644 index 000000000..d15c67e3f --- /dev/null +++ b/tools/monkeyrunner/Android.mk @@ -0,0 +1,18 @@ +# +# Copyright (C) 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. +# +MONKEYRUNNER_LOCAL_DIR := $(call my-dir) +include $(MONKEYRUNNER_LOCAL_DIR)/etc/Android.mk +include $(MONKEYRUNNER_LOCAL_DIR)/src/Android.mk diff --git a/tools/monkeyrunner/MODULE_LICENSE_APACHE2 b/tools/monkeyrunner/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000..e69de29bb diff --git a/tools/monkeyrunner/NOTICE b/tools/monkeyrunner/NOTICE new file mode 100644 index 000000000..c5b1efa7a --- /dev/null +++ b/tools/monkeyrunner/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/tools/monkeyrunner/etc/Android.mk b/tools/monkeyrunner/etc/Android.mk new file mode 100644 index 000000000..2d757fdbd --- /dev/null +++ b/tools/monkeyrunner/etc/Android.mk @@ -0,0 +1,20 @@ +# +# Copyright (C) 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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PREBUILT_EXECUTABLES := monkeyrunner +include $(BUILD_HOST_PREBUILT) diff --git a/tools/monkeyrunner/etc/manifest.txt b/tools/monkeyrunner/etc/manifest.txt new file mode 100644 index 000000000..288be5f3b --- /dev/null +++ b/tools/monkeyrunner/etc/manifest.txt @@ -0,0 +1 @@ +Main-Class: com.android.monkeyrunner.MonkeyRunner diff --git a/tools/monkeyrunner/etc/monkeyrunner b/tools/monkeyrunner/etc/monkeyrunner new file mode 100755 index 000000000..364be2a40 --- /dev/null +++ b/tools/monkeyrunner/etc/monkeyrunner @@ -0,0 +1,74 @@ +#!/bin/sh +# Copyright 2005-2007, 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. + +# Set up prog to be the path of this script, including following symlinks, +# and set up progdir to be the fully-qualified pathname of its directory. +prog="$0" +while [ -h "${prog}" ]; do + newProg=`/bin/ls -ld "${prog}"` + newProg=`expr "${newProg}" : ".* -> \(.*\)$"` + if expr "x${newProg}" : 'x/' >/dev/null; then + prog="${newProg}" + else + progdir=`dirname "${prog}"` + prog="${progdir}/${newProg}" + fi +done +oldwd=`pwd` +progdir=`dirname "${prog}"` +cd "${progdir}" +progdir=`pwd` +prog="${progdir}"/`basename "${prog}"` +cd "${oldwd}" + +jarfile=monkeyrunner.jar +frameworkdir="$progdir" +libdir="$progdir" +if [ ! -r "$frameworkdir/$jarfile" ] +then + frameworkdir=`dirname "$progdir"`/tools/lib + libdir=`dirname "$progdir"`/tools/lib +fi +if [ ! -r "$frameworkdir/$jarfile" ] +then + frameworkdir=`dirname "$progdir"`/framework + libdir=`dirname "$progdir"`/lib +fi +if [ ! -r "$frameworkdir/$jarfile" ] +then + echo `basename "$prog"`": can't find $jarfile" + exit 1 +fi + + +# Check args. +if [ debug = "$1" ]; then + # add this in for debugging + java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y + shift 1 +else + java_debug= +fi + +if [ "$OSTYPE" = "cygwin" ] ; then + jarpath=`cygpath -w "$frameworkdir/$jarfile"` + progdir=`cygpath -w "$progdir"` +else + jarpath="$frameworkdir/$jarfile" +fi + +# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored +# might need more memory, e.g. -Xmx128M +exec java -Xmx128M $os_opts $java_debug -Djava.ext.dirs="$frameworkdir" -Djava.library.path="$libdir" -Dcom.android.monkeyrunner.bindir="$progdir" -jar "$jarpath" "$@" diff --git a/tools/monkeyrunner/src/Android.mk b/tools/monkeyrunner/src/Android.mk new file mode 100644 index 000000000..576025a0c --- /dev/null +++ b/tools/monkeyrunner/src/Android.mk @@ -0,0 +1,29 @@ +# +# Copyright (C) 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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAR_MANIFEST := ../etc/manifest.txt +LOCAL_JAVA_LIBRARIES := \ + ddmlib \ + jython + + +LOCAL_MODULE := monkeyrunner + +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java new file mode 100644 index 000000000..3d5161599 --- /dev/null +++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java @@ -0,0 +1,480 @@ +/* + * Copyright (C) 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.monkeyrunner; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.IDevice; +import com.android.ddmlib.Log; +import com.android.ddmlib.NullOutputReceiver; +import com.android.ddmlib.RawImage; +import com.android.ddmlib.Log.ILogOutput; +import com.android.ddmlib.Log.LogLevel; + +import java.awt.image.BufferedImage; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.imageio.ImageIO; + +/** + * MonkeyRunner is a host side application to control a monkey instance on a + * device. MonkeyRunner provides some useful helper functions to control the + * device as well as various other methods to help script tests. + */ +public class MonkeyRunner { + + static String monkeyServer = null; + static int monkeyPort; + static Socket monkeySocket = null; + + static IDevice monkeyDevice; + + static BufferedReader monkeyReader; + static BufferedWriter monkeyWriter; + + static String scriptName = null; + + // delay between key events + final static int KEY_INPUT_DELAY = 1000; + + public static void main(String[] args) { + + processOptions(args); + + initAdbConnection(); + openMonkeyConnection(); + + start_script(); + + ScriptRunner.run(scriptName); + + end_script(); + closeMonkeyConnection(); + } + + /** + * Initialize an adb session with a device connected to the host + * + */ + public static void initAdbConnection() { + String adbLocation = "adb"; + boolean device = false; + boolean emulator = false; + String serial = null; + + AndroidDebugBridge.init(false /* debugger support */); + + try { + AndroidDebugBridge bridge = AndroidDebugBridge.createBridge( + adbLocation, true /* forceNewBridge */); + + // we can't just ask for the device list right away, as the internal thread getting + // them from ADB may not be done getting the first list. + // Since we don't really want getDevices() to be blocking, we wait here manually. + int count = 0; + while (bridge.hasInitialDeviceList() == false) { + try { + Thread.sleep(100); + count++; + } catch (InterruptedException e) { + // pass + } + + // let's not wait > 10 sec. + if (count > 100) { + System.err.println("Timeout getting device list!"); + return; + } + } + + // now get the devices + IDevice[] devices = bridge.getDevices(); + + if (devices.length == 0) { + printAndExit("No devices found!", true /* terminate */); + } + + monkeyDevice = null; + + if (emulator || device) { + for (IDevice d : devices) { + // this test works because emulator and device can't both be true at the same + // time. + if (d.isEmulator() == emulator) { + // if we already found a valid target, we print an error and return. + if (monkeyDevice != null) { + if (emulator) { + printAndExit("Error: more than one emulator launched!", + true /* terminate */); + } else { + printAndExit("Error: more than one device connected!",true /* terminate */); + } + } + monkeyDevice = d; + } + } + } else if (serial != null) { + for (IDevice d : devices) { + if (serial.equals(d.getSerialNumber())) { + monkeyDevice = d; + break; + } + } + } else { + if (devices.length > 1) { + printAndExit("Error: more than one emulator or device available!", + true /* terminate */); + } + monkeyDevice = devices[0]; + } + + } finally { + } + + } + + /** + * Open a tcp session over adb with the device to communicate monkey commands + */ + public static void openMonkeyConnection() { + try { + InetAddress addr = InetAddress.getByName(monkeyServer); + monkeySocket = new Socket(addr, monkeyPort); + } catch (UnknownHostException e) { + e.printStackTrace(); + } catch(IOException e) { + e.printStackTrace(); + } + } + + /** + * Close tcp session with the monkey on the device + * + */ + public static void closeMonkeyConnection() { + try { + monkeyReader.close(); + monkeyWriter.close(); + monkeySocket.close(); + AndroidDebugBridge.terminate(); + } catch(IOException e) { + e.printStackTrace(); + } + } + + /** + * This is a house cleaning type routine to run before starting a script. Puts + * the device in a known state. + */ + public static void start_script() { + press("menu"); + press("menu"); + press("home"); + } + + public static void end_script() { + String command = "END"; + sendMonkeyEvent(command); + } + + /** This is a method for scripts to launch an activity on the device + * + * @param name The name of the activity to launch + */ + public static void launch_activity(String name) { + try { + System.out.println("Launching: " + name); + monkeyDevice.executeShellCommand("am start -a android.intent.action.MAIN -n " + + name, new NullOutputReceiver()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Grabs the current state of the screen stores it as a png + * + * @param tag filename or tag descriptor of the screenshot + */ + public static void grabscreen(String tag) { + tag += ".png"; + + try { + Thread.sleep(1000); + getDeviceImage(monkeyDevice, tag, false); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + } + } + + /** + * Sleeper method for script to call + * + * @param msec msecs to sleep for + */ + public static void sleep(int msec) { + try { + Thread.sleep(msec); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * Tap function for scripts to call at a particular x and y location + * + * @param x x-coordinate + * @param y y-coordinate + */ + public static boolean tap(int x, int y) { + String command = "touch down " + x + " " + y + "\r\n" + + "touch up " + x + " " + y + "\r\n"; + + System.out.println("Tapping: " + x + ", " + y); + return sendMonkeyEvent(command); + } + + /** + * Press function for scripts to call on a particular button or key + * + * @param key key to press + */ + public static boolean press(String key) { + String command = "key down " + key + "\r\n" + + "key up " + key + "\r\n"; + + System.out.println("Pressing: " + key); + return sendMonkeyEvent(command); + } + + /** + * dpad down function + */ + public static boolean down() { + return press("dpad_down"); + } + + /** + * dpad up function + */ + public static boolean up() { + return press("dpad_up"); + } + + /** + * Function to type text on the device + * + * @param text text to type + */ + public static boolean type(String text) { + System.out.println("Typing: " + text); + for (int i=0; i> 11) & 0x01F) << 3; + int g = ((value >> 5) & 0x03F) << 2; + int b = ((value >> 0) & 0x01F) << 3; + + value = 0xFF << 24 | r << 16 | g << 8 | b; + + image.setRGB(y, rawImage.width - x - 1, value); + } + } + } else { + // convert raw data to an Image + image = new BufferedImage(rawImage.width, rawImage.height, + BufferedImage.TYPE_INT_ARGB); + + byte[] buffer = rawImage.data; + int index = 0; + for (int y = 0 ; y < rawImage.height ; y++) { + for (int x = 0 ; x < rawImage.width ; x++) { + + int value = buffer[index++] & 0x00FF; + value |= (buffer[index++] << 8) & 0x0FF00; + + int r = ((value >> 11) & 0x01F) << 3; + int g = ((value >> 5) & 0x03F) << 2; + int b = ((value >> 0) & 0x01F) << 3; + + value = 0xFF << 24 | r << 16 | g << 8 | b; + + image.setRGB(x, y, value); + } + } + } + + if (!ImageIO.write(image, "png", new File(filepath))) { + throw new IOException("Failed to find png writer"); + } + } + + private static void printUsageAndQuit() { + // 80 cols marker: 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + System.out.println("Usage: monkeyrunner [options] SCRIPT_FILE"); + System.out.println(""); + System.out.println(" -s MonkeyServer IP Address."); + System.out.println(" -p MonkeyServer TCP Port."); + System.out.println(""); + System.out.println(""); + + System.exit(1); + } + + private static void printAndExit(String message, boolean terminate) { + System.out.println(message); + if (terminate) { + AndroidDebugBridge.terminate(); + } + System.exit(1); + } +} diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java new file mode 100644 index 000000000..6a4405b4e --- /dev/null +++ b/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java @@ -0,0 +1,96 @@ +package com.android.monkeyrunner; + +import org.python.core.Py; +import org.python.core.PyObject; +import org.python.util.PythonInterpreter; +import org.python.util.InteractiveConsole; + +import java.io.File; +import java.io.IOException; +import java.io.FileInputStream; +import java.lang.RuntimeException; +import java.util.Properties; + + +/** + * Runs Jython based scripts. + */ +public class ScriptRunner { + + /** The "this" scope object for scripts. */ + private final Object scope; + private final String variable; + + /** Private constructor. */ + private ScriptRunner(Object scope, String variable) { + this.scope = scope; + this.variable = variable; + } + + /** Creates a new instance for the given scope object. */ + public static ScriptRunner newInstance(Object scope, String variable) { + return new ScriptRunner(scope, variable); + } + + /** + * Runs the specified Jython script. First runs the initialization script to + * preload the appropriate client library version. + */ + public static void run(String scriptfilename) { + try { + initPython(); + PythonInterpreter python = new PythonInterpreter(); + + python.execfile(scriptfilename); + } catch(Exception e) { + e.printStackTrace(); + } + } + + + /** Initialize the python interpreter. */ + private static void initPython() { + Properties props = new Properties(); + // Default is 'message' which displays sys-package-mgr bloat + // Choose one of error,warning,message,comment,debug + props.setProperty("python.verbose", "error"); + props.setProperty("python.path", System.getProperty("java.class.path")); + PythonInterpreter.initialize(System.getProperties(), props, new String[] {""}); + } + + /** + * Create and run a console using a new python interpreter for the test + * associated with this instance. + */ + public void console() throws IOException { + initPython(); + InteractiveConsole python = new InteractiveConsole(); + initInterpreter(python, scope, variable); + python.interact(); + } + + /** + * Start an interactive python interpreter using the specified set of local + * variables. Use this to interrupt a running test script with a prompt: + * + * @param locals + */ + public static void console(PyObject locals) { + initPython(); + InteractiveConsole python = new InteractiveConsole(locals); + python.interact(); + } + + /** + * Initialize a python interpreter. + * + * @param python + * @param scope + * @throws IOException + */ + public static void initInterpreter(PythonInterpreter python, Object scope, String variable) + throws IOException { + // Store the current test case as the this variable + python.set(variable, scope); + } +}