diff options
Diffstat (limited to 'monkeyrunner/src/com/android')
28 files changed, 0 insertions, 4347 deletions
diff --git a/monkeyrunner/src/com/android/monkeyrunner/JythonUtils.java b/monkeyrunner/src/com/android/monkeyrunner/JythonUtils.java deleted file mode 100644 index badddff..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/JythonUtils.java +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (C) 2010 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 java.lang.reflect.AccessibleObject; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.text.BreakIterator; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.Py; -import org.python.core.PyBoolean; -import org.python.core.PyDictionary; -import org.python.core.PyFloat; -import org.python.core.PyInteger; -import org.python.core.PyList; -import org.python.core.PyNone; -import org.python.core.PyObject; -import org.python.core.PyReflectedField; -import org.python.core.PyReflectedFunction; -import org.python.core.PyString; -import org.python.core.PyStringMap; -import org.python.core.PyTuple; - -import com.android.monkeyrunner.doc.MonkeyRunnerExported; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.collect.ImmutableMap.Builder; - -/** - * Collection of useful utilities function for interacting with the Jython interpreter. - */ -public final class JythonUtils { - private static final Logger LOG = Logger.getLogger(JythonUtils.class.getCanonicalName()); - private JythonUtils() { } - - /** - * Mapping of PyObject classes to the java class we want to convert them to. - */ - private static final Map<Class<? extends PyObject>, Class<?>> PYOBJECT_TO_JAVA_OBJECT_MAP; - static { - Builder<Class<? extends PyObject>, Class<?>> builder = ImmutableMap.builder(); - - builder.put(PyString.class, String.class); - // What python calls float, most people call double - builder.put(PyFloat.class, Double.class); - builder.put(PyInteger.class, Integer.class); - builder.put(PyBoolean.class, Boolean.class); - - PYOBJECT_TO_JAVA_OBJECT_MAP = builder.build(); - } - - /** - * Utility method to be called from Jython bindings to give proper handling of keyword and - * positional arguments. - * - * @param args the PyObject arguments from the binding - * @param kws the keyword arguments from the binding - * @return an ArgParser for this binding, or null on error - */ - public static ArgParser createArgParser(PyObject[] args, String[] kws) { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - // Up 2 levels in the current stack to give us the calling function - StackTraceElement element = stackTrace[2]; - - String methodName = element.getMethodName(); - String className = element.getClassName(); - - Class<?> clz; - try { - clz = Class.forName(className); - } catch (ClassNotFoundException e) { - LOG.log(Level.SEVERE, "Got exception: ", e); - return null; - } - - Method m; - - try { - m = clz.getMethod(methodName, PyObject[].class, String[].class); - } catch (SecurityException e) { - LOG.log(Level.SEVERE, "Got exception: ", e); - return null; - } catch (NoSuchMethodException e) { - LOG.log(Level.SEVERE, "Got exception: ", e); - return null; - } - - MonkeyRunnerExported annotation = m.getAnnotation(MonkeyRunnerExported.class); - return new ArgParser(methodName, args, kws, - annotation.args()); - } - - /** - * Get a python floating point value from an ArgParser. - * - * @param ap the ArgParser to get the value from. - * @param position the position in the parser - * @return the double value - */ - public static double getFloat(ArgParser ap, int position) { - PyObject arg = ap.getPyObject(position); - - if (Py.isInstance(arg, PyFloat.TYPE)) { - return ((PyFloat) arg).asDouble(); - } - if (Py.isInstance(arg, PyInteger.TYPE)) { - return ((PyInteger) arg).asDouble(); - } - throw Py.TypeError("Unable to parse argument: " + position); - } - - /** - * Get a python floating point value from an ArgParser. - * - * @param ap the ArgParser to get the value from. - * @param position the position in the parser - * @param defaultValue the default value to return if the arg isn't specified. - * @return the double value - */ - public static double getFloat(ArgParser ap, int position, double defaultValue) { - PyObject arg = ap.getPyObject(position, new PyFloat(defaultValue)); - - if (Py.isInstance(arg, PyFloat.TYPE)) { - return ((PyFloat) arg).asDouble(); - } - if (Py.isInstance(arg, PyInteger.TYPE)) { - return ((PyInteger) arg).asDouble(); - } - throw Py.TypeError("Unable to parse argument: " + position); - } - - /** - * Get a list of arguments from an ArgParser. - * - * @param ap the ArgParser - * @param position the position in the parser to get the argument from - * @return a list of those items - */ - @SuppressWarnings("unchecked") - public static List<Object> getList(ArgParser ap, int position) { - PyObject arg = ap.getPyObject(position, Py.None); - if (Py.isInstance(arg, PyNone.TYPE)) { - return Collections.emptyList(); - } - - List<Object> ret = Lists.newArrayList(); - PyList array = (PyList) arg; - for (int x = 0; x < array.__len__(); x++) { - PyObject item = array.__getitem__(x); - - Class<?> javaClass = PYOBJECT_TO_JAVA_OBJECT_MAP.get(item.getClass()); - if (javaClass != null) { - ret.add(item.__tojava__(javaClass)); - } - } - return ret; - } - - /** - * Get a dictionary from an ArgParser. For ease of use, key types are always coerced to - * strings. If key type cannot be coeraced to string, an exception is raised. - * - * @param ap the ArgParser to work with - * @param position the position in the parser to get. - * @return a Map mapping the String key to the value - */ - public static Map<String, Object> getMap(ArgParser ap, int position) { - PyObject arg = ap.getPyObject(position, Py.None); - if (Py.isInstance(arg, PyNone.TYPE)) { - return Collections.emptyMap(); - } - - Map<String, Object> ret = Maps.newHashMap(); - // cast is safe as getPyObjectbyType ensures it - PyDictionary dict = (PyDictionary) arg; - PyList items = dict.items(); - for (int x = 0; x < items.__len__(); x++) { - // It's a list of tuples - PyTuple item = (PyTuple) items.__getitem__(x); - // We call str(key) on the key to get the string and then convert it to the java string. - String key = (String) item.__getitem__(0).__str__().__tojava__(String.class); - PyObject value = item.__getitem__(1); - - // Look up the conversion type and convert the value - Class<?> javaClass = PYOBJECT_TO_JAVA_OBJECT_MAP.get(value.getClass()); - if (javaClass != null) { - ret.put(key, value.__tojava__(javaClass)); - } - } - return ret; - } - - private static PyObject convertObject(Object o) { - if (o instanceof String) { - return new PyString((String) o); - } else if (o instanceof Double) { - return new PyFloat((Double) o); - } else if (o instanceof Integer) { - return new PyInteger((Integer) o); - } else if (o instanceof Float) { - float f = (Float) o; - return new PyFloat(f); - } else if (o instanceof Boolean) { - return new PyBoolean((Boolean) o); - } - return Py.None; - } - - /** - * Convert the given Java Map into a PyDictionary. - * - * @param map the map to convert - * @return the python dictionary - */ - public static PyDictionary convertMapToDict(Map<String, Object> map) { - Map<PyObject, PyObject> resultMap = Maps.newHashMap(); - - for (Entry<String, Object> entry : map.entrySet()) { - resultMap.put(new PyString(entry.getKey()), - convertObject(entry.getValue())); - } - return new PyDictionary(resultMap); - } - - /** - * This function should be called from classDictInit for any classes that are being exported - * to jython. This jython converts all the MonkeyRunnerExported annotations for the given class - * into the proper python form. It also removes any functions listed in the dictionary that - * aren't specifically annotated in the java class. - * - * NOTE: Make sure the calling class implements {@link ClassDictInit} to ensure that - * classDictInit gets called. - * - * @param clz the class to examine. - * @param dict the dictionary to update. - */ - public static void convertDocAnnotationsForClass(Class<?> clz, PyObject dict) { - Preconditions.checkNotNull(dict); - Preconditions.checkArgument(dict instanceof PyStringMap); - - // See if the class has the annotation - if (clz.isAnnotationPresent(MonkeyRunnerExported.class)) { - MonkeyRunnerExported doc = clz.getAnnotation(MonkeyRunnerExported.class); - String fullDoc = buildClassDoc(doc, clz); - dict.__setitem__("__doc__", new PyString(fullDoc)); - } - - // Get all the keys from the dict and put them into a set. As we visit the annotated methods, - // we will remove them from this set. At the end, these are the "hidden" methods that - // should be removed from the dict - Collection<String> functions = Sets.newHashSet(); - for (PyObject item : dict.asIterable()) { - functions.add(item.toString()); - } - - // And remove anything that starts with __, as those are pretty important to retain - functions = Collections2.filter(functions, new Predicate<String>() { - @Override - public boolean apply(String value) { - return !value.startsWith("__"); - } - }); - - // Look at all the methods in the class and find the one's that have the - // @MonkeyRunnerExported annotation. - for (Method m : clz.getMethods()) { - if (m.isAnnotationPresent(MonkeyRunnerExported.class)) { - String methodName = m.getName(); - PyObject pyFunc = dict.__finditem__(methodName); - if (pyFunc != null && pyFunc instanceof PyReflectedFunction) { - PyReflectedFunction realPyFunc = (PyReflectedFunction) pyFunc; - MonkeyRunnerExported doc = m.getAnnotation(MonkeyRunnerExported.class); - - realPyFunc.__doc__ = new PyString(buildDoc(doc)); - functions.remove(methodName); - } - } - } - - // Also look at all the fields (both static and instance). - for (Field f : clz.getFields()) { - if (f.isAnnotationPresent(MonkeyRunnerExported.class)) { - String fieldName = f.getName(); - PyObject pyField = dict.__finditem__(fieldName); - if (pyField != null && pyField instanceof PyReflectedField) { - PyReflectedField realPyfield = (PyReflectedField) pyField; - MonkeyRunnerExported doc = f.getAnnotation(MonkeyRunnerExported.class); - - // TODO: figure out how to set field documentation. __doc__ is Read Only - // in this context. - // realPyfield.__setattr__("__doc__", new PyString(buildDoc(doc))); - functions.remove(fieldName); - } - } - } - - // Now remove any elements left from the functions collection - for (String name : functions) { - dict.__delitem__(name); - } - } - - private static final Predicate<AccessibleObject> SHOULD_BE_DOCUMENTED = new Predicate<AccessibleObject>() { - @Override - public boolean apply(AccessibleObject ao) { - return ao.isAnnotationPresent(MonkeyRunnerExported.class); - } - }; - private static final Predicate<Field> IS_FIELD_STATIC = new Predicate<Field>() { - @Override - public boolean apply(Field f) { - return (f.getModifiers() & Modifier.STATIC) != 0; - } - }; - - /** - * build a jython doc-string for a class from the annotation and the fields - * contained within the class - * - * @param doc the annotation - * @param clz the class to be documented - * @return the doc-string - */ - private static String buildClassDoc(MonkeyRunnerExported doc, Class<?> clz) { - // Below the class doc, we need to document all the documented field this class contains - Collection<Field> annotatedFields = Collections2.filter(Arrays.asList(clz.getFields()), SHOULD_BE_DOCUMENTED); - Collection<Field> staticFields = Collections2.filter(annotatedFields, IS_FIELD_STATIC); - Collection<Field> nonStaticFields = Collections2.filter(annotatedFields, Predicates.not(IS_FIELD_STATIC)); - - StringBuilder sb = new StringBuilder(); - for (String line : splitString(doc.doc(), 80)) { - sb.append(line).append("\n"); - } - - if (staticFields.size() > 0) { - sb.append("\nClass Fields: \n"); - for (Field f : staticFields) { - sb.append(buildFieldDoc(f)); - } - } - - if (nonStaticFields.size() > 0) { - sb.append("\n\nFields: \n"); - for (Field f : nonStaticFields) { - sb.append(buildFieldDoc(f)); - } - } - - return sb.toString(); - } - - /** - * Build a doc-string for the annotated field. - * - * @param f the field. - * @return the doc-string. - */ - private static String buildFieldDoc(Field f) { - MonkeyRunnerExported annotation = f.getAnnotation(MonkeyRunnerExported.class); - StringBuilder sb = new StringBuilder(); - int indentOffset = 2 + 3 + f.getName().length(); - String indent = makeIndent(indentOffset); - - sb.append(" ").append(f.getName()).append(" - "); - - boolean first = true; - for (String line : splitString(annotation.doc(), 80 - indentOffset)) { - if (first) { - first = false; - sb.append(line).append("\n"); - } else { - sb.append(indent).append(line).append("\n"); - } - } - - - return sb.toString(); - } - - /** - * Build a jython doc-string from the MonkeyRunnerExported annotation. - * - * @param doc the annotation to build from - * @return a jython doc-string - */ - private static String buildDoc(MonkeyRunnerExported doc) { - Collection<String> docs = splitString(doc.doc(), 80); - StringBuilder sb = new StringBuilder(); - for (String d : docs) { - sb.append(d).append("\n"); - } - - if (doc.args() != null && doc.args().length > 0) { - String[] args = doc.args(); - String[] argDocs = doc.argDocs(); - - sb.append("\n Args:\n"); - for (int x = 0; x < doc.args().length; x++) { - sb.append(" ").append(args[x]); - if (argDocs != null && argDocs.length > x) { - sb.append(" - "); - int indentOffset = args[x].length() + 3 + 4; - Collection<String> lines = splitString(argDocs[x], 80 - indentOffset); - boolean first = true; - String indent = makeIndent(indentOffset); - for (String line : lines) { - if (first) { - first = false; - sb.append(line).append("\n"); - } else { - sb.append(indent).append(line).append("\n"); - } - } - } - } - } - - return sb.toString(); - } - - private static String makeIndent(int indentOffset) { - if (indentOffset == 0) { - return ""; - } - StringBuffer sb = new StringBuffer(); - while (indentOffset > 0) { - sb.append(' '); - indentOffset--; - } - return sb.toString(); - } - - private static Collection<String> splitString(String source, int offset) { - BreakIterator boundary = BreakIterator.getLineInstance(); - boundary.setText(source); - - List<String> lines = Lists.newArrayList(); - StringBuilder currentLine = new StringBuilder(); - int start = boundary.first(); - - for (int end = boundary.next(); - end != BreakIterator.DONE; - start = end, end = boundary.next()) { - String b = source.substring(start, end); - if (currentLine.length() + b.length() < offset) { - currentLine.append(b); - } else { - // emit the old line - lines.add(currentLine.toString()); - currentLine = new StringBuilder(b); - } - } - lines.add(currentLine.toString()); - return lines; - } - - /** - * Obtain the set of method names available from Python. - * - * @param clazz Class to inspect. - * @return set of method names annotated with {@code MonkeyRunnerExported}. - */ - public static Set<String> getMethodNames(Class<?> clazz) { - HashSet<String> methodNames = new HashSet<String>(); - for (Method m: clazz.getMethods()) { - if (m.isAnnotationPresent(MonkeyRunnerExported.class)) { - methodNames.add(m.getName()); - } - } - return methodNames; - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java deleted file mode 100644 index 5dc7e7b..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.base.Functions; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; - -import com.android.chimpchat.ChimpChat; -import com.android.chimpchat.core.By; -import com.android.chimpchat.core.IChimpView; -import com.android.chimpchat.core.IChimpDevice; -import com.android.chimpchat.core.IChimpImage; -import com.android.chimpchat.core.TouchPressType; -import com.android.chimpchat.hierarchyviewer.HierarchyViewer; - -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.Py; -import org.python.core.PyDictionary; -import org.python.core.PyList; -import org.python.core.PyObject; -import org.python.core.PyTuple; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -/* - * Abstract base class that represents a single connected Android - * Device and provides MonkeyRunner API methods for interacting with - * that device. Each backend will need to create a concrete - * implementation of this class. - */ -@MonkeyRunnerExported(doc = "Represents a device attached to the system.") -public class MonkeyDevice extends PyObject implements ClassDictInit { - private static final Logger LOG = Logger.getLogger(MonkeyDevice.class.getName()); - - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(MonkeyDevice.class, dict); - } - - @MonkeyRunnerExported(doc = "Sends a DOWN event when used with touch() or press().") - public static final String DOWN = TouchPressType.DOWN.getIdentifier(); - - @MonkeyRunnerExported(doc = "Sends an UP event when used with touch() or press().") - public static final String UP = TouchPressType.UP.getIdentifier(); - - @MonkeyRunnerExported(doc = "Sends a DOWN event, immediately followed by an UP event when used with touch() or press()") - public static final String DOWN_AND_UP = TouchPressType.DOWN_AND_UP.getIdentifier(); - - @MonkeyRunnerExported(doc = "Sends a MOVE event when used with touch().") - public static final String MOVE = TouchPressType.MOVE.getIdentifier(); - - private IChimpDevice impl; - - public MonkeyDevice(IChimpDevice impl) { - this.impl = impl; - } - - public IChimpDevice getImpl() { - return impl; - } - - @MonkeyRunnerExported(doc = "Get the HierarchyViewer object for the device.", - returns = "A HierarchyViewer object") - public HierarchyViewer getHierarchyViewer(PyObject[] args, String[] kws) { - return impl.getHierarchyViewer(); - } - - @MonkeyRunnerExported(doc = - "Gets the device's screen buffer, yielding a screen capture of the entire display.", - returns = "A MonkeyImage object (a bitmap wrapper)") - public MonkeyImage takeSnapshot() { - IChimpImage image = impl.takeSnapshot(); - return new MonkeyImage(image); - } - - @MonkeyRunnerExported(doc = "Given the name of a variable on the device, " + - "returns the variable's value", - args = {"key"}, - argDocs = {"The name of the variable. The available names are listed in " + - "http://developer.android.com/guide/topics/testing/monkeyrunner.html."}, - returns = "The variable's value") - public String getProperty(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - return impl.getProperty(ap.getString(0)); - } - - @MonkeyRunnerExported(doc = "Synonym for getProperty()", - args = {"key"}, - argDocs = {"The name of the system variable."}, - returns = "The variable's value.") - public String getSystemProperty(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - return impl.getSystemProperty(ap.getString(0)); - } - - @MonkeyRunnerExported(doc = "Sends a touch event at the specified location", - args = { "x", "y", "type" }, - argDocs = { "x coordinate in pixels", - "y coordinate in pixels", - "touch event type as returned by TouchPressType()"}) - public void touch(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - int x = ap.getInt(0); - int y = ap.getInt(1); - - TouchPressType type = TouchPressType.fromIdentifier(ap.getString(2)); - if (type == null) { - LOG.warning(String.format("Invalid TouchPressType specified (%s) default used instead", - ap.getString(2))); - type = TouchPressType.DOWN_AND_UP; - } - - impl.touch(x, y, type); - } - - @MonkeyRunnerExported(doc = "Simulates dragging (touch, hold, and move) on the device screen.", - args = { "start", "end", "duration", "steps"}, - argDocs = { "The starting point for the drag (a tuple (x,y) in pixels)", - "The end point for the drag (a tuple (x,y) in pixels", - "Duration of the drag in seconds (default is 1.0 seconds)", - "The number of steps to take when interpolating points. (default is 10)"}) - public void drag(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - PyObject startObject = ap.getPyObject(0); - if (!(startObject instanceof PyTuple)) { - throw Py.TypeError("Agrument 0 is not a tuple"); - } - PyObject endObject = ap.getPyObject(1); - if (!(endObject instanceof PyTuple)) { - throw Py.TypeError("Agrument 1 is not a tuple"); - } - - PyTuple start = (PyTuple) startObject; - PyTuple end = (PyTuple) endObject; - - int startx = (Integer) start.__getitem__(0).__tojava__(Integer.class); - int starty = (Integer) start.__getitem__(1).__tojava__(Integer.class); - int endx = (Integer) end.__getitem__(0).__tojava__(Integer.class); - int endy = (Integer) end.__getitem__(1).__tojava__(Integer.class); - - double seconds = JythonUtils.getFloat(ap, 2, 1.0); - long ms = (long) (seconds * 1000.0); - - int steps = ap.getInt(3, 10); - - impl.drag(startx, starty, endx, endy, steps, ms); - } - - @MonkeyRunnerExported(doc = "Send a key event to the specified key", - args = { "name", "type" }, - argDocs = { "the keycode of the key to press (see android.view.KeyEvent)", - "touch event type as returned by TouchPressType(). To simulate typing a key, " + - "send DOWN_AND_UP"}) - public void press(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String name = ap.getString(0); - String touchType = ap.getString(1, DOWN_AND_UP); - - // The old docs had this string, and so in favor of maintaining - // backwards compatibility, let's special case it to the new one. - if (touchType.equals("DOWN_AND_UP")){ - touchType = "downAndUp"; - } - TouchPressType type = TouchPressType.fromIdentifier(touchType); - - impl.press(name, type); - } - - @MonkeyRunnerExported(doc = "Types the specified string on the keyboard. This is " + - "equivalent to calling press(keycode,DOWN_AND_UP) for each character in the string.", - args = { "message" }, - argDocs = { "The string to send to the keyboard." }) - public void type(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String message = ap.getString(0); - impl.type(message); - } - - @MonkeyRunnerExported(doc = "Executes an adb shell command and returns the result, if any.", - args = { "cmd", "timeout"}, - argDocs = { "The adb shell command to execute.", - "This arg is optional. It specifies the maximum amount of time during which the" + - "command can go without any output. A value of 0 means the method" + - "will wait forever. The unit of the timeout is millisecond"}, - returns = "The output from the command.") - public String shell(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - String cmd = ap.getString(0); - - if (args.length == 2) { - return impl.shell(cmd, ap.getInt(1)); - } else { - return impl.shell(cmd); - } - } - - @MonkeyRunnerExported(doc = "Reboots the specified device into a specified bootloader.", - args = { "into" }, - argDocs = { "the bootloader to reboot into: bootloader, recovery, or None"}) - public void reboot(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String into = ap.getString(0, null); - - impl.reboot(into); - } - - @MonkeyRunnerExported(doc = "Installs the specified Android package (.apk file) " + - "onto the device. If the package already exists on the device, it is replaced.", - args = { "path" }, - argDocs = { "The package's path and filename on the host filesystem." }, - returns = "True if the install succeeded") - public boolean installPackage(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String path = ap.getString(0); - return impl.installPackage(path); - } - - @MonkeyRunnerExported(doc = "Deletes the specified package from the device, including its " + - "associated data and cache.", - args = { "package"}, - argDocs = { "The name of the package to delete."}, - returns = "True if remove succeeded") - public boolean removePackage(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String packageName = ap.getString(0); - return impl.removePackage(packageName); - } - - @MonkeyRunnerExported(doc = "Starts an Activity on the device by sending an Intent " + - "constructed from the specified parameters.", - args = { "uri", "action", "data", "mimetype", "categories", "extras", - "component", "flags" }, - argDocs = { "The URI for the Intent.", - "The action for the Intent.", - "The data URI for the Intent", - "The mime type for the Intent.", - "A Python iterable containing the category names for the Intent.", - "A dictionary of extras to add to the Intent. Types of these extras " + - "are inferred from the python types of the values.", - "The component of the Intent.", - "An iterable of flags for the Intent." + - "All arguments are optional. The default value for each argument is null." + - "(see android.content.Intent)"}) - - public void startActivity(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String uri = ap.getString(0, null); - String action = ap.getString(1, null); - String data = ap.getString(2, null); - String mimetype = ap.getString(3, null); - Collection<String> categories = Collections2.transform(JythonUtils.getList(ap, 4), - Functions.toStringFunction()); - Map<String, Object> extras = JythonUtils.getMap(ap, 5); - String component = ap.getString(6, null); - int flags = ap.getInt(7, 0); - - impl.startActivity(uri, action, data, mimetype, categories, extras, component, flags); - } - - @MonkeyRunnerExported(doc = "Sends a broadcast intent to the device.", - args = { "uri", "action", "data", "mimetype", "categories", "extras", - "component", "flags" }, - argDocs = { "The URI for the Intent.", - "The action for the Intent.", - "The data URI for the Intent", - "The mime type for the Intent.", - "An iterable of category names for the Intent.", - "A dictionary of extras to add to the Intent. Types of these extras " + - "are inferred from the python types of the values.", - "The component of the Intent.", - "An iterable of flags for the Intent." + - "All arguments are optional. " + "" + - "The default value for each argument is null." + - "(see android.content.Context.sendBroadcast(Intent))"}) - public void broadcastIntent(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String uri = ap.getString(0, null); - String action = ap.getString(1, null); - String data = ap.getString(2, null); - String mimetype = ap.getString(3, null); - Collection<String> categories = Collections2.transform(JythonUtils.getList(ap, 4), - Functions.toStringFunction()); - Map<String, Object> extras = JythonUtils.getMap(ap, 5); - String component = ap.getString(6, null); - int flags = ap.getInt(7, 0); - - impl.broadcastIntent(uri, action, data, mimetype, categories, extras, component, flags); - } - - @MonkeyRunnerExported(doc = "Run the specified package with instrumentation and return " + - "the output it generates. Use this to run a test package using " + - "InstrumentationTestRunner.", - args = { "className", "args" }, - argDocs = { "The class to run with instrumentation. The format is " + - "packagename/classname. Use packagename to specify the Android package " + - "to run, and classname to specify the class to run within that package. " + - "For test packages, this is usually " + - "testpackagename/InstrumentationTestRunner", - "A map of strings to objects containing the arguments to pass to this " + - "instrumentation (default value is None)." }, - returns = "A map of strings to objects for the output from the package. " + - "For a test package, contains a single key-value pair: the key is 'stream' " + - "and the value is a string containing the test output.") - - public PyDictionary instrument(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String packageName = ap.getString(0); - Map<String, Object> instrumentArgs = JythonUtils.getMap(ap, 1); - if (instrumentArgs == null) { - instrumentArgs = Collections.emptyMap(); - } - - Map<String, Object> result = impl.instrument(packageName, instrumentArgs); - return JythonUtils.convertMapToDict(result); - } - - @MonkeyRunnerExported(doc = "Wake up the screen on the device") - public void wake(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - impl.wake(); - } - - - @MonkeyRunnerExported(doc = "Retrieve the properties that can be queried") - public PyList getPropertyList(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - Collection<String> properties = impl.getPropertyList(); - return new PyList(properties); - } - - @MonkeyRunnerExported(doc = "Retrieve the view ids for the current application") - public PyList getViewIdList(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - Collection<String> viewIds = impl.getViewIdList(); - return new PyList(viewIds); - } - - //Because the pythonic way is to have flatter hierarchies, rather than doing the - //findView(By.id("foo")) style the java code uses, I'm going to expose them as individual - //method calls. This is similar to WebDriver's python bindings. - @MonkeyRunnerExported(doc = "Obtains the view with the specified id.", - args = {"id"}, - argDocs = {"The id of the view to retrieve."}, - returns = "The view object with the specified id.") - public MonkeyView getViewById(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - String id = ap.getString(0); - IChimpView view = impl.getView(By.id(id)); - return new MonkeyView(view); - } - - @MonkeyRunnerExported(doc = "Obtains the view with the specified accessibility ids.", - args = {"windowId", "accessibility id"}, - argDocs = {"The window id of the view to retrieve.", - "The accessibility id of the view to retrieve."}, - returns = "The view object with the specified id.") - public MonkeyView getViewByAccessibilityIds(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - int windowId = ap.getInt(0); - int accessibilityId = ap.getInt(1); - IChimpView view = impl.getView(By.accessibilityIds(windowId, accessibilityId)); - return new MonkeyView(view); - } - - @MonkeyRunnerExported(doc = "Obtains current root view", - returns = "The root view object") - public MonkeyView getRootView(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new MonkeyView(impl.getRootView()); - } - - @MonkeyRunnerExported(doc = "Obtains a list of views that contain the specified text.", - args = {"text"}, - argDocs = {"The text to search for"}, - returns = "A list of view objects that contain the specified text.") - public PyList getViewsByText(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - String text = ap.getString(0); - Collection<IChimpView> views = impl.getViews(By.text(text)); - PyList pyViews = new PyList(); - for (IChimpView view : views) { - pyViews.append(new MonkeyView(view)); - } - return pyViews; - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyFormatter.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyFormatter.java deleted file mode 100644 index c4a5362..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyFormatter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.collect.Maps; - -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; -import java.util.logging.Formatter; -import java.util.logging.Level; -import java.util.logging.LogRecord; - -/* - * Custom Logging Formatter for MonkeyRunner that generates all log - * messages on a single line. - */ -public class MonkeyFormatter extends Formatter { - public static final Formatter DEFAULT_INSTANCE = new MonkeyFormatter(); - - private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyMMdd HH:mm:ss.SSS"); - - private static Map<Level, String> LEVEL_TO_STRING_CACHE = Maps.newHashMap(); - - private static final String levelToString(Level level) { - String levelName = LEVEL_TO_STRING_CACHE.get(level); - if (levelName == null) { - levelName = level.getName().substring(0, 1); - LEVEL_TO_STRING_CACHE.put(level, levelName); - } - return levelName; - } - - private static String getHeader(LogRecord record) { - StringBuilder sb = new StringBuilder(); - - sb.append(FORMAT.format(new Date(record.getMillis()))).append(":"); - sb.append(levelToString(record.getLevel())).append(" "); - - sb.append("[").append(Thread.currentThread().getName()).append("] "); - - String loggerName = record.getLoggerName(); - if (loggerName != null) { - sb.append("[").append(loggerName).append("]"); - } - return sb.toString(); - } - - private class PrintWriterWithHeader extends PrintWriter { - private final ByteArrayOutputStream out; - private final String header; - - public PrintWriterWithHeader(String header) { - this(header, new ByteArrayOutputStream()); - } - - public PrintWriterWithHeader(String header, ByteArrayOutputStream out) { - super(out, true); - this.header = header; - this.out = out; - } - - @Override - public void println(Object x) { - print(header); - super.println(x); - } - - @Override - public void println(String x) { - print(header); - super.println(x); - } - - @Override - public String toString() { - return out.toString(); - } - } - - @Override - public String format(LogRecord record) { - Throwable thrown = record.getThrown(); - String header = getHeader(record); - - StringBuilder sb = new StringBuilder(); - sb.append(header); - sb.append(" ").append(formatMessage(record)); - sb.append("\n"); - - // Print the exception here if we caught it - if (thrown != null) { - - PrintWriter pw = new PrintWriterWithHeader(header); - thrown.printStackTrace(pw); - sb.append(pw.toString()); - } - - return sb.toString(); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java deleted file mode 100644 index bae6dc8..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.base.Preconditions; - -import com.android.chimpchat.core.IChimpImage; -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.PyInteger; -import org.python.core.PyObject; -import org.python.core.PyTuple; - -import java.util.logging.Logger; - -/** - * Jython object to encapsulate images that have been taken. - */ -@MonkeyRunnerExported(doc = "An image") -public class MonkeyImage extends PyObject implements ClassDictInit { - private static Logger LOG = Logger.getLogger(MonkeyImage.class.getCanonicalName()); - - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(MonkeyImage.class, dict); - } - - private final IChimpImage impl; - - public MonkeyImage(IChimpImage impl) { - this.impl = impl; - } - - public IChimpImage getImpl() { - return impl; - } - - - @MonkeyRunnerExported(doc = "Converts the MonkeyImage into a particular format and returns " + - "the result as a String. Use this to get access to the raw" + - "pixels in a particular format. String output is for better " + - "performance.", - args = {"format"}, - argDocs = { "The destination format (for example, 'png' for Portable " + - "Network Graphics format). The default is png." }, - returns = "The resulting image as a String.") - public byte[] convertToBytes(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String format = ap.getString(0, "png"); - return impl.convertToBytes(format); - } - - @MonkeyRunnerExported(doc = "Write the MonkeyImage to a file. If no " + - "format is specified, this method guesses the output format " + - "based on the extension of the provided file extension. If it is unable to guess the " + - "format, it uses PNG.", - args = {"path", "format"}, - argDocs = {"The output filename, optionally including its path", - "The destination format (for example, 'png' for " + - " Portable Network Graphics format." }, - returns = "boolean true if writing succeeded.") - public boolean writeToFile(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String path = ap.getString(0); - String format = ap.getString(1, null); - return impl.writeToFile(path, format); - } - - @MonkeyRunnerExported(doc = "Get a single ARGB (alpha, red, green, blue) pixel at location " + - "x,y. The arguments x and y are 0-based, expressed in pixel dimensions. X increases " + - "to the right, and Y increases towards the bottom. This method returns a tuple.", - args = { "x", "y" }, - argDocs = { "the x offset of the pixel", "the y offset of the pixel" }, - returns = "A tuple of (A, R, G, B) for the pixel. Each item in the tuple has the " + - "range 0-255.") - public PyObject getRawPixel(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - int x = ap.getInt(0); - int y = ap.getInt(1); - int pixel = impl.getPixel(x, y); - PyInteger a = new PyInteger((pixel & 0xFF000000) >> 24); - PyInteger r = new PyInteger((pixel & 0x00FF0000) >> 16); - PyInteger g = new PyInteger((pixel & 0x0000FF00) >> 8); - PyInteger b = new PyInteger((pixel & 0x000000FF) >> 0); - return new PyTuple(a, r, g ,b); - } - - @MonkeyRunnerExported(doc = "Get a single ARGB (alpha, red, green, blue) pixel at location " + - "x,y. The arguments x and y are 0-based, expressed in pixel dimensions. X increases " + - "to the right, and Y increases towards the bottom. This method returns an Integer.", - args = { "x", "y" }, - argDocs = { "the x offset of the pixel", "the y offset of the pixel" }, - returns = "An unsigned integer pixel for x,y. The 8 high-order bits are A, followed" + - "by 8 bits for R, 8 for G, and 8 for B.") - public int getRawPixelInt(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - int x = ap.getInt(0); - int y = ap.getInt(1); - return impl.getPixel(x, y); - } - - @MonkeyRunnerExported(doc = "Compare this MonkeyImage object to aother MonkeyImage object.", - args = {"other", "percent"}, - argDocs = {"The other MonkeyImage object.", - "A float in the range 0.0 to 1.0, indicating the percentage " + - "of pixels that need to be the same for the method to return 'true'. " + - "Defaults to 1.0."}, - returns = "boolean 'true' if the two objects contain the same image.") - public boolean sameAs(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - PyObject otherObject = ap.getPyObject(0); - IChimpImage other = ((MonkeyImage) otherObject.__tojava__(MonkeyImage.class)).getImpl(); - - double percent = JythonUtils.getFloat(ap, 1, 1.0); - - return impl.sameAs(other, percent); - } - - @MonkeyRunnerExported(doc = "Copy a rectangular region of the image.", - args = {"rect"}, - argDocs = {"A tuple (x, y, w, h) describing the region to copy. x and y specify " + - "upper lefthand corner of the region. w is the width of the region in " + - "pixels, and h is its height."}, - returns = "a MonkeyImage object representing the copied region.") - public MonkeyImage getSubImage(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - PyTuple rect = (PyTuple) ap.getPyObjectByType(0, PyTuple.TYPE); - int x = rect.__getitem__(0).asInt(); - int y = rect.__getitem__(1).asInt(); - int w = rect.__getitem__(2).asInt(); - int h = rect.__getitem__(3).asInt(); - - IChimpImage image = impl.getSubImage(x, y, w, h); - return new MonkeyImage(image); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java deleted file mode 100644 index 98b2ecc..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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.chimpchat.core.ChimpRect; - -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.PyInteger; -import org.python.core.PyList; -import org.python.core.PyObject; - -import java.util.List; -import java.util.LinkedList; -import java.util.logging.Logger; - -/* - * A Jython wrap for the ChimpRect class that stores coordinate information for views - */ -@MonkeyRunnerExported(doc = "Represents the coordinates of a rectangular object") -public class MonkeyRect extends PyObject implements ClassDictInit { - private static final Logger LOG = Logger.getLogger(MonkeyRect.class.getName()); - - private ChimpRect rect; - - @MonkeyRunnerExported(doc = "The x coordinate of the left side of the rectangle") - public int left; - @MonkeyRunnerExported(doc = "The y coordinate of the top side of the rectangle") - public int top; - @MonkeyRunnerExported(doc = "The x coordinate of the right side of the rectangle") - public int right; - @MonkeyRunnerExported(doc = "The y coordinate of the bottom side of the rectangle") - public int bottom; - - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(MonkeyRect.class, dict); - } - - public MonkeyRect(ChimpRect rect) { - this.rect = rect; - this.left = rect.left; - this.right = rect.right; - this.top = rect.top; - this.bottom = rect.bottom; - } - - @MonkeyRunnerExported(doc = "Returns the width of the rectangle", - returns = "The width of the rectangle as an integer") - public PyInteger getWidth() { - return new PyInteger(right-left); - } - - @MonkeyRunnerExported(doc = "Returns the height of the rectangle", - returns = "The height of the rectangle as an integer") - public PyInteger getHeight() { - return new PyInteger(bottom-top); - } - - @MonkeyRunnerExported(doc = "Returns a two item list that contains the x and y value of " + - "the center of the rectangle", - returns = "The center coordinates as a two item list of integers") - public PyList getCenter(){ - List<PyInteger> center = new LinkedList<PyInteger>(); - /* Center x coordinate */ - center.add(new PyInteger(left+(right-left)/2)); - /* Center y coordinate */ - center.add(new PyInteger(top+(bottom-top)/2)); - return new PyList(center); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java deleted file mode 100644 index d047052..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.base.Functions; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; - -import com.android.chimpchat.ChimpChat; -import com.android.chimpchat.core.IChimpBackend; -import com.android.chimpchat.core.IChimpDevice; -import com.android.chimpchat.core.IChimpImage; -import com.android.chimpchat.core.ChimpImageBase; -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.PyException; -import org.python.core.PyObject; - -import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.JOptionPane; - -/** - * This is the main interface class into the jython bindings. - */ -@MonkeyRunnerExported(doc = "Main entry point for MonkeyRunner") -public class MonkeyRunner extends PyObject implements ClassDictInit { - private static final Logger LOG = Logger.getLogger(MonkeyRunner.class.getCanonicalName()); - private static ChimpChat chimpchat; - - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(MonkeyRunner.class, dict); - } - - static void setChimpChat(ChimpChat chimp){ - chimpchat = chimp; - } - - - @MonkeyRunnerExported(doc = "Waits for the workstation to connect to the device.", - args = {"timeout", "deviceId"}, - argDocs = {"The timeout in seconds to wait. The default is to wait indefinitely.", - "A regular expression that specifies the device name. See the documentation " + - "for 'adb' in the Developer Guide to learn more about device names."}, - returns = "A ChimpDevice object representing the connected device.") - public static MonkeyDevice waitForConnection(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - long timeoutMs; - try { - double timeoutInSecs = JythonUtils.getFloat(ap, 0); - timeoutMs = (long) (timeoutInSecs * 1000.0); - } catch (PyException e) { - timeoutMs = Long.MAX_VALUE; - } - - IChimpDevice device = chimpchat.waitForConnection(timeoutMs, - ap.getString(1, ".*")); - MonkeyDevice chimpDevice = new MonkeyDevice(device); - return chimpDevice; - } - - @MonkeyRunnerExported(doc = "Pause the currently running program for the specified " + - "number of seconds.", - args = {"seconds"}, - argDocs = {"The number of seconds to pause."}) - public static void sleep(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - double seconds = JythonUtils.getFloat(ap, 0); - - long ms = (long) (seconds * 1000.0); - - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - LOG.log(Level.SEVERE, "Error sleeping", e); - } - } - - @MonkeyRunnerExported(doc = "Format and display the API reference for MonkeyRunner.", - args = { "format" }, - argDocs = {"The desired format for the output, either 'text' for plain text or " + - "'html' for HTML markup."}, - returns = "A string containing the help text in the desired format.") - public static String help(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String format = ap.getString(0, "text"); - - return MonkeyRunnerHelp.helpString(format); - } - - @MonkeyRunnerExported(doc = "Display an alert dialog to the process running the current " + - "script. The dialog is modal, so the script stops until the user dismisses the " + - "dialog.", - args = { "message", "title", "okTitle" }, - argDocs = { - "The message to display in the dialog.", - "The dialog's title. The default value is 'Alert'.", - "The text to use in the dialog button. The default value is 'OK'." - }) - public static void alert(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String message = ap.getString(0); - String title = ap.getString(1, "Alert"); - String buttonTitle = ap.getString(2, "OK"); - - alert(message, title, buttonTitle); - } - - @MonkeyRunnerExported(doc = "Display a dialog that accepts input. The dialog is ," + - "modal, so the script stops until the user clicks one of the two dialog buttons. To " + - "enter a value, the user enters the value and clicks the 'OK' button. To quit the " + - "dialog without entering a value, the user clicks the 'Cancel' button. Use the " + - "supplied arguments for this method to customize the text for these buttons.", - args = {"message", "initialValue", "title", "okTitle", "cancelTitle"}, - argDocs = { - "The prompt message to display in the dialog.", - "The initial value to supply to the user. The default is an empty string)", - "The dialog's title. The default is 'Input'", - "The text to use in the dialog's confirmation button. The default is 'OK'." + - "The text to use in the dialog's 'cancel' button. The default is 'Cancel'." - }, - returns = "The test entered by the user, or None if the user canceled the input;" - ) - public static String input(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String message = ap.getString(0); - String initialValue = ap.getString(1, ""); - String title = ap.getString(2, "Input"); - - return input(message, initialValue, title); - } - - @MonkeyRunnerExported(doc = "Display a choice dialog that allows the user to select a single " + - "item from a list of items.", - args = {"message", "choices", "title"}, - argDocs = { - "The prompt message to display in the dialog.", - "An iterable Python type containing a list of choices to display", - "The dialog's title. The default is 'Input'" }, - returns = "The 0-based numeric offset of the selected item in the iterable.") - public static int choice(PyObject[] args, String kws[]) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String message = ap.getString(0); - Collection<String> choices = Collections2.transform(JythonUtils.getList(ap, 1), - Functions.toStringFunction()); - String title = ap.getString(2, "Input"); - - return choice(message, title, choices); - } - - @MonkeyRunnerExported(doc = "Loads a MonkeyImage from a file.", - args = { "path" }, - argDocs = { - "The path to the file to load. This file path is in terms of the computer running " + - "MonkeyRunner and not a path on the Android Device. " }, - returns = "A new MonkeyImage representing the specified file") - public static MonkeyImage loadImageFromFile(PyObject[] args, String kws[]) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String path = ap.getString(0); - IChimpImage image = ChimpImageBase.loadImageFromFile(path); - return new MonkeyImage(image); - } - - /** - * Display an alert dialog. - * - * @param message the message to show. - * @param title the title of the dialog box. - * @param okTitle the title of the button. - */ - public static void alert(String message, String title, String okTitle) { - Object[] options = { okTitle }; - JOptionPane.showOptionDialog(null, message, title, JOptionPane.DEFAULT_OPTION, - JOptionPane.INFORMATION_MESSAGE, null, options, options[0]); - } - - /** - * Display a dialog allow the user to pick a choice from a list of choices. - * - * @param message the message to show. - * @param title the title of the dialog box. - * @param choices the list of the choices to display. - * @return the index of the selected choice, or -1 if nothing was chosen. - */ - public static int choice(String message, String title, Collection<String> choices) { - Object[] possibleValues = choices.toArray(); - Object selectedValue = JOptionPane.showInputDialog(null, message, title, - JOptionPane.QUESTION_MESSAGE, null, possibleValues, possibleValues[0]); - - for (int x = 0; x < possibleValues.length; x++) { - if (possibleValues[x].equals(selectedValue)) { - return x; - } - } - // Error - return -1; - } - - /** - * Display a dialog that allows the user to input a text string. - * - * @param message the message to show. - * @param initialValue the initial value to display in the dialog - * @param title the title of the dialog box. - * @return the entered string, or null if cancelled - */ - public static String input(String message, String initialValue, String title) { - return (String) JOptionPane.showInputDialog(null, message, title, - JOptionPane.QUESTION_MESSAGE, null, null, initialValue); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java deleted file mode 100644 index 746d240..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2010 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.google.clearsilver.jsilver.JSilver; -import com.google.clearsilver.jsilver.data.Data; -import com.google.clearsilver.jsilver.resourceloader.ClassLoaderResourceLoader; -import com.google.clearsilver.jsilver.resourceloader.ResourceLoader; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Set; - -/** - * Utility class for generating inline help documentation - */ -public final class MonkeyRunnerHelp { - private MonkeyRunnerHelp() { } - - private static final String HELP = "help"; - private static final String NAME = "name"; - private static final String DOC = "doc"; - private static final String ARGUMENT = "argument"; - private static final String RETURNS = "returns"; - private static final String TYPE = "type"; - - // Enum used to describe documented types. - private enum Type { - ENUM, FIELD, METHOD - } - - private static void getAllExportedClasses(Set<Field> fields, - Set<Method> methods, - Set<Constructor<?>> constructors, - Set<Class<?>> enums) { - final Set<Class<?>> classesVisited = Sets.newHashSet(); - Set<Class<?>> classesToVisit = Sets.newHashSet(); - classesToVisit.add(MonkeyRunner.class); - - Predicate<Class<?>> haventSeen = new Predicate<Class<?>>() { - public boolean apply(Class<?> clz) { - return !classesVisited.contains(clz); - } - }; - - while (!classesToVisit.isEmpty()) { - classesVisited.addAll(classesToVisit); - - List<Class<?>> newClasses = Lists.newArrayList(); - for (Class<?> clz : classesToVisit) { - // See if the class itself is annotated and is an enum - if (clz.isEnum() && clz.isAnnotationPresent(MonkeyRunnerExported.class)) { - enums.add(clz); - } - - // Constructors - for (Constructor<?> c : clz.getConstructors()) { - newClasses.addAll(Collections2.filter(Arrays.asList(c.getParameterTypes()), - haventSeen)); - if (c.isAnnotationPresent(MonkeyRunnerExported.class)) { - constructors.add(c); - } - } - - // Fields - for (Field f : clz.getFields()) { - if (haventSeen.apply(f.getClass())) { - newClasses.add(f.getClass()); - } - if (f.isAnnotationPresent(MonkeyRunnerExported.class)) { - fields.add(f); - } - } - - // Methods - for (Method m : clz.getMethods()) { - newClasses.addAll(Collections2.filter(Arrays.asList(m.getParameterTypes()), - haventSeen)); - if (haventSeen.apply(m.getReturnType())) { - newClasses.add(m.getReturnType()); - } - - if (m.isAnnotationPresent(MonkeyRunnerExported.class)) { - methods.add(m); - } - } - - // Containing classes - for (Class<?> toAdd : clz.getClasses()) { - if (haventSeen.apply(toAdd)) { - newClasses.add(toAdd); - } - } - } - - classesToVisit.clear(); - classesToVisit.addAll(newClasses); - } - } - - private static Comparator<Member> MEMBER_SORTER = new Comparator<Member>() { - public int compare(Member o1, Member o2) { - return o1.getName().compareTo(o2.getName()); - } - }; - - private static Comparator<Class<?>> CLASS_SORTER = new Comparator<Class<?>>() { - public int compare(Class<?> o1, Class<?> o2) { - return o1.getName().compareTo(o2.getName()); - } - }; - - public static String helpString(String format) { - ResourceLoader resourceLoader = new ClassLoaderResourceLoader( - MonkeyRunner.class.getClassLoader(), "com/android/monkeyrunner"); - JSilver jsilver = new JSilver(resourceLoader); - - // Quick check for support formats - if ("html".equals(format) || "text".equals(format) || "sdk-docs".equals(format)) { - try { - Data hdf = buildHelpHdf(jsilver); - return jsilver.render(format + ".cs", hdf); - } catch (IOException e) { - return ""; - } - } else if ("hdf".equals(format)) { - Data hdf = buildHelpHdf(jsilver); - return hdf.toString(); - } - return ""; - } - - /** - * Parse the value string into paragraphs and put them into the - * HDF under this specified prefix. Each paragraph will appear - * numbered under the prefix. For example: - * - * paragraphsIntoHDF("a.b.c", ....) - * - * Will create paragraphs under "a.b.c.0", "a.b.c.1", etc. - * - * @param prefix The prefix to put the values under. - * @param value the value to parse paragraphs from. - * @param hdf the HDF to add the entries to. - */ - private static void paragraphsIntoHDF(String prefix, String value, Data hdf) { - String paragraphs[] = value.split("\n"); - int x = 0; - for (String para : paragraphs) { - hdf.setValue(prefix + "." + x, para); - x++; - } - } - - private static Data buildHelpHdf(JSilver jsilver) { - Data hdf = jsilver.createData(); - int outputItemCount = 0; - - Set<Field> fields = Sets.newTreeSet(MEMBER_SORTER); - Set<Method> methods = Sets.newTreeSet(MEMBER_SORTER); - Set<Constructor<?>> constructors = Sets.newTreeSet(MEMBER_SORTER); - Set<Class<?>> classes = Sets.newTreeSet(CLASS_SORTER); - getAllExportedClasses(fields, methods, constructors, classes); - - for (Class<?> clz : classes) { - String prefix = HELP + "." + outputItemCount + "."; - - hdf.setValue(prefix + NAME, clz.getCanonicalName()); - MonkeyRunnerExported annotation = clz.getAnnotation(MonkeyRunnerExported.class); - paragraphsIntoHDF(prefix + DOC, annotation.doc(), hdf); - hdf.setValue(prefix + TYPE, Type.ENUM.name()); - - // Now go through the enumeration constants - Object[] constants = clz.getEnumConstants(); - String[] argDocs = annotation.argDocs(); - if (constants.length > 0) { - for (int x = 0; x < constants.length; x++) { - String argPrefix = prefix + ARGUMENT + "." + x + "."; - hdf.setValue(argPrefix + NAME, constants[x].toString()); - if (argDocs.length > x) { - paragraphsIntoHDF(argPrefix + DOC, argDocs[x], hdf); - } - } - } - outputItemCount++; - } - - for (Method m : methods) { - String prefix = HELP + "." + outputItemCount + "."; - - MonkeyRunnerExported annotation = m.getAnnotation(MonkeyRunnerExported.class); - String className = m.getDeclaringClass().getCanonicalName(); - String methodName = className + "." + m.getName(); - hdf.setValue(prefix + NAME, methodName); - paragraphsIntoHDF(prefix + DOC, annotation.doc(), hdf); - if (annotation.args().length > 0) { - String[] argDocs = annotation.argDocs(); - String[] aargs = annotation.args(); - for (int x = 0; x < aargs.length; x++) { - String argPrefix = prefix + ARGUMENT + "." + x + "."; - - hdf.setValue(argPrefix + NAME, aargs[x]); - if (argDocs.length > x) { - paragraphsIntoHDF(argPrefix + DOC, argDocs[x], hdf); - } - } - } - if (!"".equals(annotation.returns())) { - paragraphsIntoHDF(prefix + RETURNS, annotation.returns(), hdf); - } - outputItemCount++; - } - - return hdf; - } - - public static Collection<String> getAllDocumentedClasses() { - Set<Field> fields = Sets.newTreeSet(MEMBER_SORTER); - Set<Method> methods = Sets.newTreeSet(MEMBER_SORTER); - Set<Constructor<?>> constructors = Sets.newTreeSet(MEMBER_SORTER); - Set<Class<?>> classes = Sets.newTreeSet(CLASS_SORTER); - getAllExportedClasses(fields, methods, constructors, classes); - - // The classes object only captures classes that are specifically exporter, which isn't - // good enough. So go through all the fields, methods, etc. and collect those classes as - // as well - Set<Class<?>> allClasses = Sets.newHashSet(); - allClasses.addAll(classes); - for (Field f : fields) { - allClasses.add(f.getDeclaringClass()); - } - for (Method m : methods) { - allClasses.add(m.getDeclaringClass()); - } - for (Constructor<?> constructor : constructors) { - allClasses.add(constructor.getDeclaringClass()); - } - - // And transform that collection into a list of simple names. - return Collections2.transform(allClasses, new Function<Class<?>, String>() { - @Override - public String apply(Class<?> clz) { - return clz.getName(); - } - }); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerOptions.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerOptions.java deleted file mode 100644 index 33daccd..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerOptions.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.collect.ImmutableList; - -import java.io.File; -import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class MonkeyRunnerOptions { - private static final Logger LOG = Logger.getLogger(MonkeyRunnerOptions.class.getName()); - private static String DEFAULT_MONKEY_SERVER_ADDRESS = "127.0.0.1"; - private static int DEFAULT_MONKEY_PORT = 12345; - - private final int port; - private final String hostname; - private final File scriptFile; - private final String backend; - private final Collection<File> plugins; - private final Collection<String> arguments; - private final Level logLevel; - - private MonkeyRunnerOptions(String hostname, int port, File scriptFile, String backend, - Level logLevel, Collection<File> plugins, Collection<String> arguments) { - this.hostname = hostname; - this.port = port; - this.scriptFile = scriptFile; - this.backend = backend; - this.logLevel = logLevel; - this.plugins = plugins; - this.arguments = arguments; - } - - public int getPort() { - return port; - } - - public String getHostname() { - return hostname; - } - - public File getScriptFile() { - return scriptFile; - } - - public String getBackendName() { - return backend; - } - - public Collection<File> getPlugins() { - return plugins; - } - - public Collection<String> getArguments() { - return arguments; - } - - public Level getLogLevel() { - return logLevel; - } - - private static void printUsage(String message) { - System.out.println(message); - 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(" -v MonkeyServer Logging level (ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF)"); - System.out.println(""); - System.out.println(""); - } - - /** - * Process the command-line options - * - * @return the parsed options, or null if there was an error. - */ - public static MonkeyRunnerOptions processOptions(String[] args) { - // parse command line parameters. - int index = 0; - - String hostname = DEFAULT_MONKEY_SERVER_ADDRESS; - File scriptFile = null; - int port = DEFAULT_MONKEY_PORT; - String backend = "adb"; - Level logLevel = Level.SEVERE; - - ImmutableList.Builder<File> pluginListBuilder = ImmutableList.builder(); - ImmutableList.Builder<String> argumentBuilder = ImmutableList.builder(); - while (index < args.length) { - String argument = args[index++]; - - if ("-s".equals(argument)) { - if (index == args.length) { - printUsage("Missing Server after -s"); - return null; - } - hostname = args[index++]; - - } else if ("-p".equals(argument)) { - // quick check on the next argument. - if (index == args.length) { - printUsage("Missing Server port after -p"); - return null; - } - port = Integer.parseInt(args[index++]); - - } else if ("-v".equals(argument)) { - // quick check on the next argument. - if (index == args.length) { - printUsage("Missing Log Level after -v"); - return null; - } - - logLevel = Level.parse(args[index++]); - } else if ("-be".equals(argument)) { - // quick check on the next argument. - if (index == args.length) { - printUsage("Missing backend name after -be"); - return null; - } - backend = args[index++]; - } else if ("-plugin".equals(argument)) { - // quick check on the next argument. - if (index == args.length) { - printUsage("Missing plugin path after -plugin"); - return null; - } - File plugin = new File(args[index++]); - if (!plugin.exists()) { - printUsage("Plugin file doesn't exist"); - return null; - } - - if (!plugin.canRead()) { - printUsage("Can't read plugin file"); - return null; - } - - pluginListBuilder.add(plugin); - } else if ("-u".equals(argument)){ - // This is asking for unbuffered input. We can ignore this. - } else if (argument.startsWith("-") && - // Once we have the scriptfile, the rest of the arguments go to jython. - scriptFile == null) { - // we have an unrecognized argument. - printUsage("Unrecognized argument: " + argument + "."); - return null; - } else { - if (scriptFile == null) { - // get the filepath of the script to run. - // This will be the last undashed argument. - scriptFile = new File(argument); - if (!scriptFile.exists()) { - printUsage("Can't open specified script file"); - return null; - } - if (!scriptFile.canRead()) { - printUsage("Can't open specified script file"); - return null; - } - } else { - argumentBuilder.add(argument); - } - } - }; - - return new MonkeyRunnerOptions(hostname, port, scriptFile, backend, logLevel, - pluginListBuilder.build(), argumentBuilder.build()); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerStarter.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerStarter.java deleted file mode 100644 index dd7aec9..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerStarter.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableMap; - -import com.android.chimpchat.ChimpChat; - -import org.python.util.PythonInterpreter; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Enumeration; -import java.util.Map; -import java.util.TreeMap; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.Logger; - -/** - * 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. This class bootstraps - * MonkeyRunner. - */ -public class MonkeyRunnerStarter { - private static final Logger LOG = Logger.getLogger(MonkeyRunnerStarter.class.getName()); - private static final String MONKEY_RUNNER_MAIN_MANIFEST_NAME = "MonkeyRunnerStartupRunner"; - - private final ChimpChat chimp; - private final MonkeyRunnerOptions options; - - public MonkeyRunnerStarter(MonkeyRunnerOptions options) { - Map<String, String> chimp_options = new TreeMap<String, String>(); - chimp_options.put("backend", options.getBackendName()); - this.options = options; - this.chimp = ChimpChat.getInstance(chimp_options); - MonkeyRunner.setChimpChat(chimp); - } - - - - private int run() { - // This system property gets set by the included starter script - String monkeyRunnerPath = System.getProperty("com.android.monkeyrunner.bindir") + - File.separator + "monkeyrunner"; - - Map<String, Predicate<PythonInterpreter>> plugins = handlePlugins(); - if (options.getScriptFile() == null) { - ScriptRunner.console(monkeyRunnerPath); - chimp.shutdown(); - return 0; - } else { - int error = ScriptRunner.run(monkeyRunnerPath, options.getScriptFile().getAbsolutePath(), - options.getArguments(), plugins); - chimp.shutdown(); - return error; - } - } - - private Predicate<PythonInterpreter> handlePlugin(File f) { - JarFile jarFile; - try { - jarFile = new JarFile(f); - } catch (IOException e) { - LOG.log(Level.SEVERE, "Unable to open plugin file. Is it a jar file? " + - f.getAbsolutePath(), e); - return Predicates.alwaysFalse(); - } - Manifest manifest; - try { - manifest = jarFile.getManifest(); - } catch (IOException e) { - LOG.log(Level.SEVERE, "Unable to get manifest file from jar: " + - f.getAbsolutePath(), e); - return Predicates.alwaysFalse(); - } - Attributes mainAttributes = manifest.getMainAttributes(); - String pluginClass = mainAttributes.getValue(MONKEY_RUNNER_MAIN_MANIFEST_NAME); - if (pluginClass == null) { - // No main in this plugin, so it always succeeds. - return Predicates.alwaysTrue(); - } - URL url; - try { - url = f.toURI().toURL(); - } catch (MalformedURLException e) { - LOG.log(Level.SEVERE, "Unable to convert file to url " + f.getAbsolutePath(), - e); - return Predicates.alwaysFalse(); - } - URLClassLoader classLoader = new URLClassLoader(new URL[] { url }, - ClassLoader.getSystemClassLoader()); - Class<?> clz; - try { - clz = Class.forName(pluginClass, true, classLoader); - } catch (ClassNotFoundException e) { - LOG.log(Level.SEVERE, "Unable to load the specified plugin: " + pluginClass, e); - return Predicates.alwaysFalse(); - } - Object loadedObject; - try { - loadedObject = clz.newInstance(); - } catch (InstantiationException e) { - LOG.log(Level.SEVERE, "Unable to load the specified plugin: " + pluginClass, e); - return Predicates.alwaysFalse(); - } catch (IllegalAccessException e) { - LOG.log(Level.SEVERE, "Unable to load the specified plugin " + - "(did you make it public?): " + pluginClass, e); - return Predicates.alwaysFalse(); - } - // Cast it to the right type - if (loadedObject instanceof Runnable) { - final Runnable run = (Runnable) loadedObject; - return new Predicate<PythonInterpreter>() { - public boolean apply(PythonInterpreter i) { - run.run(); - return true; - } - }; - } else if (loadedObject instanceof Predicate<?>) { - return (Predicate<PythonInterpreter>) loadedObject; - } else { - LOG.severe("Unable to coerce object into correct type: " + pluginClass); - return Predicates.alwaysFalse(); - } - } - - private Map<String, Predicate<PythonInterpreter>> handlePlugins() { - ImmutableMap.Builder<String, Predicate<PythonInterpreter>> builder = ImmutableMap.builder(); - for (File f : options.getPlugins()) { - builder.put(f.getAbsolutePath(), handlePlugin(f)); - } - return builder.build(); - } - - /* Similar to above, when this fails, it no longer throws a - * runtime exception, but merely will log the failure. - */ - - - private static final void replaceAllLogFormatters(Formatter form, Level level) { - LogManager mgr = LogManager.getLogManager(); - Enumeration<String> loggerNames = mgr.getLoggerNames(); - while (loggerNames.hasMoreElements()) { - String loggerName = loggerNames.nextElement(); - Logger logger = mgr.getLogger(loggerName); - for (Handler handler : logger.getHandlers()) { - handler.setFormatter(form); - handler.setLevel(level); - } - } - } - - public static void main(String[] args) { - MonkeyRunnerOptions options = MonkeyRunnerOptions.processOptions(args); - - if (options == null) { - return; - } - - // logging property files are difficult - replaceAllLogFormatters(MonkeyFormatter.DEFAULT_INSTANCE, options.getLogLevel()); - - MonkeyRunnerStarter runner = new MonkeyRunnerStarter(options); - int error = runner.run(); - - // This will kill any background threads as well. - System.exit(error); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java deleted file mode 100644 index 8c1edb8..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2011 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.google.common.base.Preconditions; - -import com.android.chimpchat.core.IChimpView; - -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.PyBoolean; -import org.python.core.PyInteger; -import org.python.core.PyList; -import org.python.core.PyObject; -import org.python.core.PyString; - -import java.util.List; -import java.util.logging.Logger; - -/* - * Jython wrapper for the ChimpView class - */ -@MonkeyRunnerExported(doc = "Represents a view object.") -public class MonkeyView extends PyObject implements ClassDictInit { - private static final Logger LOG = Logger.getLogger(MonkeyView.class.getName()); - - private IChimpView impl; - - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(MonkeyView.class, dict); - } - - public MonkeyView(IChimpView impl) { - this.impl = impl; - } - - @MonkeyRunnerExported(doc = "Get the checked status of the view", - returns = "A boolean value for whether the item is checked or not") - public PyBoolean getChecked(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyBoolean(impl.getChecked()); - } - - @MonkeyRunnerExported(doc = "Returns the class name of the view", - returns = "The class name of the view as a string") - public PyString getViewClass(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyString(impl.getViewClass()); - } - - @MonkeyRunnerExported(doc = "Returns the text contained by the view", - returns = "The text contained in the view") - public PyString getText(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyString(impl.getText()); - } - - @MonkeyRunnerExported(doc = "Returns the location of the view in the form of a MonkeyRect", - returns = "The location of the view as a MonkeyRect object") - public MonkeyRect getLocation(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new MonkeyRect(impl.getLocation()); - } - - @MonkeyRunnerExported(doc = "Returns the enabled status of the view", - returns = "The enabled status of the view as a boolean") - public PyBoolean getEnabled(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyBoolean(impl.getEnabled()); - } - - @MonkeyRunnerExported(doc = "Returns the selected status of the view", - returns = "The selected status of the view as a boolean") - public PyBoolean getSelected(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyBoolean(impl.getSelected()); - } - - @MonkeyRunnerExported(doc = "Sets the selected status of the view", - args = {"selected"}, - argDocs = { "The boolean value to set selected to" }) - public void setSelected(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - PyBoolean pySelected = (PyBoolean) ap.getPyObject(0, new PyBoolean(false)); - boolean selected = (Boolean) pySelected.__tojava__(Boolean.class); - impl.setSelected(selected); - } - - @MonkeyRunnerExported(doc = "Returns the focused status of the view", - returns = "The focused status of the view as a boolean") - public PyBoolean getFocused(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - return new PyBoolean(impl.getFocused()); - } - - @MonkeyRunnerExported(doc = "Sets the focused status of the view", - args = {"focused"}, - argDocs = { "The boolean value to set focused to" }) - public void setFocused(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - PyBoolean pyFocused = (PyBoolean) ap.getPyObject(0, new PyBoolean(false)); - boolean focused = (Boolean) pyFocused.__tojava__(Boolean.class); - impl.setFocused(focused); - } - - @MonkeyRunnerExported(doc = "Returns the parent of the current view", - returns = "The parent of the view as a MonkeyView object") - public MonkeyView getParent(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - MonkeyView parent = new MonkeyView(impl.getParent()); - return parent; - } - - @MonkeyRunnerExported(doc = "Returns the children of the current view", - returns = "The children of the view as a list of MonkeyView objects") - public PyList getChildren(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - List<IChimpView> chimpChildren = impl.getChildren(); - PyList children = new PyList(); - for (IChimpView child : chimpChildren) { - children.append(new MonkeyView(child)); - } - return children; - } - - @MonkeyRunnerExported(doc = "Returns the accessibility ids of the current view", - returns = "The accessibility ids of the view as a list of ints") - public PyList getAccessibilityIds(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - int[] ids = impl.getAccessibilityIds(); - PyList pyIds = new PyList(); - for (int i = 0; i < ids.length; i++) { - pyIds.append(new PyInteger(ids[i])); - } - return pyIds; - } - -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java b/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java deleted file mode 100644 index 3c96eeb..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2010 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.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; -import com.google.common.collect.Lists; - -import org.python.core.Py; -import org.python.core.PyException; -import org.python.core.PyJavaPackage; -import org.python.core.PyList; -import org.python.core.PyObject; -import org.python.core.PyString; -import org.python.core.PySystemState; -import org.python.util.InteractiveConsole; -import org.python.util.JLineConsole; -import org.python.util.PythonInterpreter; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * Runs Jython based scripts. - */ -public class ScriptRunner { - private static final Logger LOG = Logger.getLogger(MonkeyRunnerOptions.class.getName()); - - /** 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. - * - * @param scriptfilename the name of the file to run. - * @param args the arguments passed in (excluding the filename). - * @param plugins a list of plugins to load. - * @return the error code from running the script. - */ - public static int run(String executablePath, String scriptfilename, - Collection<String> args, Map<String, - Predicate<PythonInterpreter>> plugins) { - // Add the current directory of the script to the python.path search path. - File f = new File(scriptfilename); - - // Adjust the classpath so jython can access the classes in the specified classpath. - Collection<String> classpath = Lists.newArrayList(f.getParent()); - classpath.addAll(plugins.keySet()); - - String[] argv = new String[args.size() + 1]; - argv[0] = f.getAbsolutePath(); - int x = 1; - for (String arg : args) { - argv[x++] = arg; - } - - initPython(executablePath, classpath, argv); - - PythonInterpreter python = new PythonInterpreter(); - - // Now let the mains run. - for (Map.Entry<String, Predicate<PythonInterpreter>> entry : plugins.entrySet()) { - boolean success; - try { - success = entry.getValue().apply(python); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Plugin Main through an exception.", e); - continue; - } - if (!success) { - LOG.severe("Plugin Main returned error for: " + entry.getKey()); - } - } - - // Bind __name__ to __main__ so mains will run - python.set("__name__", "__main__"); - // Also find __file__ - python.set("__file__", scriptfilename); - - try { - python.execfile(scriptfilename); - } catch (PyException e) { - if (Py.SystemExit.equals(e.type)) { - // Then recover the error code so we can pass it on - return (Integer) e.value.__tojava__(Integer.class); - } - // Then some other kind of exception was thrown. Log it and return error; - LOG.log(Level.SEVERE, "Script terminated due to an exception", e); - return 1; - } - return 0; - } - - public static void runString(String executablePath, String script) { - initPython(executablePath); - PythonInterpreter python = new PythonInterpreter(); - python.exec(script); - } - - public static Map<String, PyObject> runStringAndGet(String executablePath, - String script, String... names) { - return runStringAndGet(executablePath, script, Arrays.asList(names)); - } - - public static Map<String, PyObject> runStringAndGet(String executablePath, - String script, Collection<String> names) { - initPython(executablePath); - final PythonInterpreter python = new PythonInterpreter(); - python.exec(script); - - Builder<String, PyObject> builder = ImmutableMap.builder(); - for (String name : names) { - builder.put(name, python.get(name)); - } - return builder.build(); - } - - private static void initPython(String executablePath) { - List<String> arg = Collections.emptyList(); - initPython(executablePath, arg, new String[] {""}); - } - - private static void initPython(String executablePath, - Collection<String> pythonPath, String[] argv) { - Properties props = new Properties(); - - // Build up the python.path - StringBuilder sb = new StringBuilder(); - sb.append(System.getProperty("java.class.path")); - for (String p : pythonPath) { - sb.append(":").append(p); - } - props.setProperty("python.path", sb.toString()); - - /** Initialize the python interpreter. */ - // Default is 'message' which displays sys-package-mgr bloat - // Choose one of error,warning,message,comment,debug - props.setProperty("python.verbose", "error"); - - // This needs to be set for sys.executable to function properly - props.setProperty("python.executable", executablePath); - - PythonInterpreter.initialize(System.getProperties(), props, argv); - - String frameworkDir = System.getProperty("java.ext.dirs"); - File monkeyRunnerJar = new File(frameworkDir, "monkeyrunner.jar"); - if (monkeyRunnerJar.canRead()) { - PySystemState.packageManager.addJar(monkeyRunnerJar.getAbsolutePath(), false); - } - } - - /** - * Start an interactive python interpreter. - */ - public static void console(String executablePath) { - initPython(executablePath); - InteractiveConsole python = new JLineConsole(); - python.interact(); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyController.java b/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyController.java deleted file mode 100644 index 6fc4ea6..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyController.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2010 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.controller; - -import com.android.chimpchat.ChimpChat; -import com.android.chimpchat.core.IChimpDevice; - -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.logging.Logger; -import java.util.Map; -import java.util.TreeMap; - -import javax.swing.JFrame; -import javax.swing.SwingUtilities; - -/** - * Application that can control an attached device using the network monkey. It has a window - * that shows what the current screen looks like and allows the user to click in it. Clicking in - * the window sends touch events to the attached device. It also supports keyboard input for - * typing and has buttons to press to simulate physical buttons on the device. - */ -public class MonkeyController extends JFrame { - private static final Logger LOG = Logger.getLogger(MonkeyController.class.getName()); - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - Map<String, String> options = new TreeMap<String, String>(); - options.put("backend", "adb"); - ChimpChat chimpchat = ChimpChat.getInstance(options); - final IChimpDevice device = chimpchat.waitForConnection(); - MonkeyControllerFrame mf = new MonkeyControllerFrame(device); - mf.setVisible(true); - mf.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - device.dispose(); - } - }); - } - }); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyControllerFrame.java b/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyControllerFrame.java deleted file mode 100644 index 8bb2513..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/controller/MonkeyControllerFrame.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2010 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.controller; - -import com.android.chimpchat.core.PhysicalButton; -import com.android.chimpchat.core.TouchPressType; -import com.android.chimpchat.core.IChimpImage; -import com.android.chimpchat.core.IChimpDevice; - -import java.awt.KeyEventDispatcher; -import java.awt.KeyboardFocusManager; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.logging.Logger; - -import javax.swing.AbstractAction; -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JToolBar; -import javax.swing.SwingUtilities; -import javax.swing.Timer; - -/** - * Main window for MonkeyController. - */ -public class MonkeyControllerFrame extends JFrame { - private static final Logger LOG = Logger.getLogger(MonkeyControllerFrame.class.getName()); - - private final JButton refreshButton = new JButton("Refresh"); - private final JButton variablesButton = new JButton("Variable"); - private final JLabel imageLabel = new JLabel(); - private final VariableFrame variableFrame; - - private final IChimpDevice device; - private BufferedImage currentImage; - - private final TouchPressType DOWN_AND_UP = TouchPressType.DOWN_AND_UP; - - private final Timer timer = new Timer(1000, new ActionListener() { - public void actionPerformed(ActionEvent e) { - updateScreen(); - } - }); - - private class PressAction extends AbstractAction { - private final PhysicalButton button; - - public PressAction(PhysicalButton button) { - this.button = button; - } - /* When this fails, it no longer throws a runtime exception, - * but merely will log the failure. - */ - public void actionPerformed(ActionEvent event) { - device.press(button.getKeyName(), DOWN_AND_UP); - updateScreen(); - } - } - - private JButton createToolbarButton(PhysicalButton hardButton) { - JButton button = new JButton(new PressAction(hardButton)); - button.setText(hardButton.getKeyName()); - return button; - } - - public MonkeyControllerFrame(IChimpDevice chimpDevice) { - super("MonkeyController"); - this.device = chimpDevice; - - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); - JToolBar toolbar = new JToolBar(); - - toolbar.add(createToolbarButton(PhysicalButton.HOME)); - toolbar.add(createToolbarButton(PhysicalButton.BACK)); - toolbar.add(createToolbarButton(PhysicalButton.SEARCH)); - toolbar.add(createToolbarButton(PhysicalButton.MENU)); - - add(toolbar); - add(refreshButton); - add(variablesButton); - add(imageLabel); - - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - updateScreen(); - } - }); - - variableFrame = new VariableFrame(); - variablesButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - variableFrame.setVisible(true); - } - }); - - /* Similar to above, when the following two methods fail, they - * no longer throw a runtime exception, but merely will log the failure. - */ - imageLabel.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - device.touch(event.getX(), event.getY(), DOWN_AND_UP); - updateScreen(); - } - - }); - - KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - focusManager.addKeyEventDispatcher(new KeyEventDispatcher() { - public boolean dispatchKeyEvent(KeyEvent event) { - if (KeyEvent.KEY_TYPED == event.getID()) { - device.type(Character.toString(event.getKeyChar())); - } - return false; - } - }); - - SwingUtilities.invokeLater(new Runnable(){ - public void run() { - init(); - variableFrame.init(device); - } - }); - - pack(); - } - - private void updateScreen() { - IChimpImage snapshot = device.takeSnapshot(); - currentImage = snapshot.createBufferedImage(); - imageLabel.setIcon(new ImageIcon(currentImage)); - - pack(); - } - - private void init() { - updateScreen(); - timer.start(); - } - -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/controller/VariableFrame.java b/monkeyrunner/src/com/android/monkeyrunner/controller/VariableFrame.java deleted file mode 100644 index f9c6ef3..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/controller/VariableFrame.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2010 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.controller; - -import com.google.common.collect.Sets; - -import com.android.chimpchat.core.IChimpDevice; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.Collection; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JTable; -import javax.swing.SwingUtilities; -import javax.swing.WindowConstants; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; -import javax.swing.table.AbstractTableModel; - -/** - * Swing Frame that displays all the variables that the monkey exposes on the device. - */ -public class VariableFrame extends JFrame { - private static final Logger LOG = Logger.getLogger(VariableFrame.class.getName()); - private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); - private IChimpDevice device; - - private static class VariableHolder implements Comparable<VariableHolder> { - private final String key; - private final String value; - - public VariableHolder(String key, String value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return key; - } - - public String getValue() { - return value; - } - - public int compareTo(VariableHolder o) { - return key.compareTo(o.key); - } - } - - private static <E> E getNthElement(Set<E> set, int offset) { - int current = 0; - for (E elem : set) { - if (current == offset) { - return elem; - } - current++; - } - return null; - } - - private class VariableTableModel extends AbstractTableModel { - private final TreeSet<VariableHolder> set = Sets.newTreeSet(); - - public void refresh() { - Collection<String> variables; - variables = device.getPropertyList(); - for (final String variable : variables) { - EXECUTOR.execute(new Runnable() { - public void run() { - String value; - value = device.getProperty(variable); - if (value == null) { - value = ""; - } - synchronized (set) { - set.add(new VariableHolder(variable, value)); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - VariableTableModel.this.fireTableDataChanged(); - } - }); - - } - } - }); - } - } - - public int getColumnCount() { - return 2; - } - - public int getRowCount() { - synchronized (set) { - return set.size(); - } - } - - public Object getValueAt(int rowIndex, int columnIndex) { - VariableHolder nthElement; - synchronized (set) { - nthElement = getNthElement(set, rowIndex); - } - if (columnIndex == 0) { - return nthElement.getKey(); - } - return nthElement.getValue(); - } - } - - public VariableFrame() { - super("Variables"); - setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); - setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); - - final VariableTableModel tableModel = new VariableTableModel(); - - JButton refreshButton = new JButton("Refresh"); - add(refreshButton); - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - tableModel.refresh(); - } - }); - - - JTable table = new JTable(tableModel); - add(table); - - tableModel.addTableModelListener(new TableModelListener() { - public void tableChanged(TableModelEvent e) { - pack(); - } - }); - - this.addWindowListener(new WindowAdapter() { - @Override - public void windowOpened(WindowEvent e) { - tableModel.refresh(); - } - }); - - pack(); - } - - public void init(IChimpDevice device) { - this.device = device; - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/doc/MonkeyRunnerExported.java b/monkeyrunner/src/com/android/monkeyrunner/doc/MonkeyRunnerExported.java deleted file mode 100644 index 33da2dd..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/doc/MonkeyRunnerExported.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 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.doc; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates that the annotated method is a public API to expose to the - * scripting interface. Can be used to generate documentation of what - * methods are exposed and also can be used to enforce visibility of - * these methods in the scripting environment. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR, - ElementType.TYPE, ElementType.FIELD }) -public @interface MonkeyRunnerExported { - /** - * A documentation string for this method. - */ - String doc(); - - /** - * The list of names for the keywords in this method in their proper positional order. - * - * For example: - * - * @MonkeyRunnerExported(args={"one", "two"}) - * public void foo(); - * - * would allow calls like this: - * foo(one=1, two=2) - * foo(1, 2) - */ - String[] args() default {}; - - /** - * The list of documentation for the arguments. - */ - String[] argDocs() default {}; - - /** - * The documentation for the return type of this method. - */ - String returns() default "returns nothing."; -}
\ No newline at end of file diff --git a/monkeyrunner/src/com/android/monkeyrunner/easy/By.java b/monkeyrunner/src/com/android/monkeyrunner/easy/By.java deleted file mode 100644 index d9891c6..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/easy/By.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 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.easy; - -import com.google.common.base.Preconditions; - -import com.android.chimpchat.hierarchyviewer.HierarchyViewer; -import com.android.hierarchyviewerlib.models.ViewNode; -import com.android.monkeyrunner.JythonUtils; -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.PyObject; - -/** - * Select a view object based on some criteria. - * - * Currently supports the By.id criteria to search for an element by id. - * In the future it will support other criteria such as: - * By.classid - search by class. - * By.hash - search by hashcode - * and recursively searching under an already selected object. - * - * WARNING: This API is under development, expect the interface to change - * without notice. - * - * TODO: Implement other selectors, like classid, hash, and so on. - * TODO: separate java-only core from jython wrapper - */ -public class By extends PyObject implements ClassDictInit { - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(By.class, dict); - } - - private String id; - - By(String id) { - this.id = id; - } - - @MonkeyRunnerExported(doc = "Select an object by id.", - args = { "id" }, - argDocs = { "The identifier of the object." }) - public static By id(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - String id = ap.getString(0); - return new By(id); - } - - public static By id(String id) { - return new By(id); - } - - public ViewNode findView(HierarchyViewer viewer) { - return viewer.findViewById(id); - } - - -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/easy/EasyMonkeyDevice.java b/monkeyrunner/src/com/android/monkeyrunner/easy/EasyMonkeyDevice.java deleted file mode 100644 index 439718f..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/easy/EasyMonkeyDevice.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2011 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.easy; - -import com.google.common.base.Preconditions; - -import com.android.chimpchat.core.TouchPressType; -import com.android.chimpchat.hierarchyviewer.HierarchyViewer; -import com.android.hierarchyviewerlib.models.ViewNode; -import com.android.monkeyrunner.JythonUtils; -import com.android.monkeyrunner.MonkeyDevice; -import com.android.monkeyrunner.doc.MonkeyRunnerExported; - -import org.eclipse.swt.graphics.Point; -import org.python.core.ArgParser; -import org.python.core.ClassDictInit; -import org.python.core.Py; -import org.python.core.PyException; -import org.python.core.PyInteger; -import org.python.core.PyObject; -import org.python.core.PyTuple; - -import java.util.Set; - -/** - * Extends {@link MonkeyDevice} to support looking up views using a 'selector'. - * Currently, only identifiers can be used as a selector. All methods on - * MonkeyDevice can be used on this class in Python. - * - * WARNING: This API is under development, expect the interface to change - * without notice. - */ -@MonkeyRunnerExported(doc = "MonkeyDevice with easier methods to refer to objects.") -public class EasyMonkeyDevice extends PyObject implements ClassDictInit { - public static void classDictInit(PyObject dict) { - JythonUtils.convertDocAnnotationsForClass(EasyMonkeyDevice.class, dict); - } - - private MonkeyDevice mDevice; - private HierarchyViewer mHierarchyViewer; - - private static final Set<String> EXPORTED_METHODS = - JythonUtils.getMethodNames(EasyMonkeyDevice.class); - - @MonkeyRunnerExported(doc = "Creates EasyMonkeyDevice with an underlying MonkeyDevice.", - args = { "device" }, - argDocs = { "MonkeyDevice to extend." }) - public EasyMonkeyDevice(MonkeyDevice device) { - this.mDevice = device; - this.mHierarchyViewer = device.getImpl().getHierarchyViewer(); - } - - @MonkeyRunnerExported(doc = "Sends a touch event to the selected object.", - args = { "selector", "type" }, - argDocs = { - "The selector identifying the object.", - "The event type as returned by TouchPressType()." }) - public void touch(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - String tmpType = ap.getString(1); - TouchPressType type = TouchPressType.fromIdentifier(tmpType); - Preconditions.checkNotNull(type, "Invalid touch type: " + tmpType); - // TODO: try catch rethrow PyExc - touch(selector, type); - } - - public void touch(By selector, TouchPressType type) { - Point p = getElementCenter(selector); - mDevice.getImpl().touch(p.x, p.y, type); - } - - @MonkeyRunnerExported(doc = "Types a string into the specified object.", - args = { "selector", "text" }, - argDocs = { - "The selector identifying the object.", - "The text to type into the object." }) - public void type(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - String text = ap.getString(1); - type(selector, text); - } - - public void type(By selector, String text) { - Point p = getElementCenter(selector); - mDevice.getImpl().touch(p.x, p.y, TouchPressType.DOWN_AND_UP); - mDevice.getImpl().type(text); - } - - @MonkeyRunnerExported(doc = "Locates the coordinates of the selected object.", - args = { "selector" }, - argDocs = { "The selector identifying the object." }, - returns = "Tuple containing (x,y,w,h) location and size.") - public PyTuple locate(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - - ViewNode node = selector.findView(mHierarchyViewer); - Point p = HierarchyViewer.getAbsolutePositionOfView(node); - PyTuple tuple = new PyTuple( - new PyInteger(p.x), - new PyInteger(p.y), - new PyInteger(node.width), - new PyInteger(node.height)); - return tuple; - } - - @MonkeyRunnerExported(doc = "Checks if the specified object exists.", - args = { "selector" }, - returns = "True if the object exists.", - argDocs = { "The selector identifying the object." }) - public boolean exists(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - return exists(selector); - } - - public boolean exists(By selector) { - ViewNode node = selector.findView(mHierarchyViewer); - return node != null; - } - - @MonkeyRunnerExported(doc = "Checks if the specified object is visible.", - args = { "selector" }, - returns = "True if the object is visible.", - argDocs = { "The selector identifying the object." }) - public boolean visible(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - return visible(selector); - } - - public boolean visible(By selector) { - ViewNode node = selector.findView(mHierarchyViewer); - return mHierarchyViewer.visible(node); - } - - @MonkeyRunnerExported(doc = "Obtain the text in the selected input box.", - args = { "selector" }, - argDocs = { "The selector identifying the object." }, - returns = "Text in the selected input box.") - public String getText(PyObject[] args, String[] kws) { - ArgParser ap = JythonUtils.createArgParser(args, kws); - Preconditions.checkNotNull(ap); - - By selector = getSelector(ap, 0); - return getText(selector); - } - - public String getText(By selector) { - ViewNode node = selector.findView(mHierarchyViewer); - return mHierarchyViewer.getText(node); - } - - @MonkeyRunnerExported(doc = "Gets the id of the focused window.", - returns = "The symbolic id of the focused window or None.") - public String getFocusedWindowId(PyObject[] args, String[] kws) { - return getFocusedWindowId(); - } - - public String getFocusedWindowId() { - return mHierarchyViewer.getFocusedWindowName(); - } - - /** - * Forwards unknown methods to the original MonkeyDevice object. - */ - @Override - public PyObject __findattr_ex__(String name) { - if (!EXPORTED_METHODS.contains(name)) { - return mDevice.__findattr_ex__(name); - } - return super.__findattr_ex__(name); - } - - /** - * Get the selector object from the argument parser. - * - * @param ap argument parser to get it from. - * @param i argument index. - * @return selector object. - */ - private By getSelector(ArgParser ap, int i) { - return (By)ap.getPyObject(i).__tojava__(By.class); - } - - /** - * Get the coordinates of the element's center. - * - * @param selector the element selector - * @return the (x,y) coordinates of the center - */ - private Point getElementCenter(By selector) { - ViewNode node = selector.findView(mHierarchyViewer); - if (node == null) { - throw new PyException(Py.ValueError, - String.format("View not found: %s", selector)); - } - - Point p = HierarchyViewer.getAbsoluteCenterOfView(node); - return p; - } - -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/easy/README b/monkeyrunner/src/com/android/monkeyrunner/easy/README deleted file mode 100644 index 239bedd..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/easy/README +++ /dev/null @@ -1,27 +0,0 @@ -com.android.monkeyrunner.easy contains classes intended to make it easier -to interact with applications using the MonkeyRunner framework. Instead of -referencing a button or input box by x,y coordinate, they can be referenced -by identifier, as in the following Python example: - -############################################################################## - -from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice -from com.android.monkeyrunner.easy import EasyMonkeyDevice -from com.android.monkeyrunner.easy import By - -# Connect to the current device. -device = MonkeyRunner.waitForConnection() - -# Use the EasyMonkey API, all methods on device are available in easy_device. -easy_device = EasyMonkeyDevice(device) - -if not easy_device.visible(By.id('id/all_apps_button')): - raise Error('Could not find the "all apps" button') - -print "Location of element:", easy_device.locate(By.id('id/all_apps_button')) - -easy_device.touch(By.id('id/all_apps_button'), 'DOWN_AND_UP') - -############################################################################## - -WARNING: This API is under development and may change without notice. diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/ActionListModel.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/ActionListModel.java deleted file mode 100644 index 5e0b7e7..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/ActionListModel.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder; - -import com.google.common.collect.Lists; - -import com.android.monkeyrunner.recorder.actions.Action; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.util.List; - -import javax.swing.AbstractListModel; - -/** - * List model for managing actions. - */ -public class ActionListModel extends AbstractListModel { - private List<Action> actionList = Lists.newArrayList(); - - /** - * Add the specified action to the end of the list - * @param a the action to add. - */ - public void add(Action a) { - actionList.add(a); - int newIndex = actionList.size() - 1; - this.fireIntervalAdded(this, newIndex, newIndex); - } - - @Override - public Object getElementAt(int arg0) { - return actionList.get(arg0).getDisplayName(); - } - - - @Override - public int getSize() { - return actionList.size(); - } - - /** - * Serialize all the stored actions to the specified file. - * - * @param selectedFile the file to write to - * @throws FileNotFoundException if the file can't be created. - */ - public void export(File selectedFile) throws FileNotFoundException { - PrintWriter out = new PrintWriter(selectedFile); - for (Action a : actionList) { - out.println(a.serialize()); - } - out.close(); - } -}
\ No newline at end of file diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorder.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorder.java deleted file mode 100644 index c8b4553..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorder.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder; - -import com.android.chimpchat.ChimpChat; -import com.android.chimpchat.core.IChimpDevice; -import com.android.monkeyrunner.MonkeyDevice; - -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.WindowConstants; - -/** - * Helper entry point for MonkeyRecorder. - */ -public class MonkeyRecorder { - private static final Logger LOG = Logger.getLogger(MonkeyRecorder.class.getName()); - // This lock is used to keep the python process blocked while the frame is runing. - private static final Object LOCK = new Object(); - - /** - * Jython entry point for MonkeyRecorder. Meant to be called like this: - * - * <code> - * from com.android.monkeyrunner import MonkeyRunner as mr - * from com.android.monkeyrunner import MonkeyRecorder - * MonkeyRecorder.start(mr.waitForConnection()) - * </code> - * - * @param device - */ - public static void start(final MonkeyDevice device) { - start(device.getImpl()); - } - - /* package */static void start(final IChimpDevice device) { - MonkeyRecorderFrame frame = new MonkeyRecorderFrame(device); - // TODO: this is a hack until the window listener works. - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - device.dispose(); - synchronized (LOCK) { - LOCK.notifyAll(); - } - } - }); - - frame.setVisible(true); - synchronized (LOCK) { - try { - LOCK.wait(); - } catch (InterruptedException e) { - LOG.log(Level.SEVERE, "Unexpected Exception", e); - } - } - } - - public static void main(String[] args) { - ChimpChat chimp = ChimpChat.getInstance(); - MonkeyRecorder.start(chimp.waitForConnection()); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorderFrame.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorderFrame.java deleted file mode 100644 index 394b895..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/MonkeyRecorderFrame.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder; - -import com.android.monkeyrunner.MonkeyDevice; -import com.android.chimpchat.core.IChimpImage; -import com.android.chimpchat.core.IChimpDevice; -import com.android.monkeyrunner.recorder.actions.Action; -import com.android.monkeyrunner.recorder.actions.DragAction; -import com.android.monkeyrunner.recorder.actions.DragAction.Direction; -import com.android.monkeyrunner.recorder.actions.PressAction; -import com.android.monkeyrunner.recorder.actions.TouchAction; -import com.android.monkeyrunner.recorder.actions.TypeAction; -import com.android.monkeyrunner.recorder.actions.WaitAction; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.io.FileNotFoundException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.Timer; - -/** - * MainFrame for MonkeyRecorder. - */ -public class MonkeyRecorderFrame extends JFrame { - private static final Logger LOG = - Logger.getLogger(MonkeyRecorderFrame.class.getName()); - - private final IChimpDevice device; - - private static final long serialVersionUID = 1L; - private JPanel jContentPane = null; - private JLabel display = null; - private JScrollPane historyPanel = null; - private JPanel actionPanel = null; - private JButton waitButton = null; - private JButton pressButton = null; - private JButton typeButton = null; - private JButton flingButton = null; - private JButton exportActionButton = null; - - private JButton refreshButton = null; - - private BufferedImage currentImage; // @jve:decl-index=0: - private BufferedImage scaledImage = new BufferedImage(320, 480, - BufferedImage.TYPE_INT_ARGB); // @jve:decl-index=0: - - private JList historyList; - private ActionListModel actionListModel; - - private final Timer refreshTimer = new Timer(1000, new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - refreshDisplay(); // @jve:decl-index=0: - } - }); - - /** - * This is the default constructor - */ - public MonkeyRecorderFrame(IChimpDevice device) { - this.device = device; - initialize(); - } - - private void initialize() { - this.setSize(400, 600); - this.setContentPane(getJContentPane()); - this.setTitle("MonkeyRecorder"); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - refreshDisplay(); - }}); - refreshTimer.start(); - } - - private void refreshDisplay() { - IChimpImage snapshot = device.takeSnapshot(); - currentImage = snapshot.createBufferedImage(); - - Graphics2D g = scaledImage.createGraphics(); - g.drawImage(currentImage, 0, 0, - scaledImage.getWidth(), scaledImage.getHeight(), - null); - g.dispose(); - - display.setIcon(new ImageIcon(scaledImage)); - - pack(); - } - - /** - * This method initializes jContentPane - * - * @return javax.swing.JPanel - */ - private JPanel getJContentPane() { - if (jContentPane == null) { - display = new JLabel(); - jContentPane = new JPanel(); - jContentPane.setLayout(new BorderLayout()); - jContentPane.add(display, BorderLayout.CENTER); - jContentPane.add(getHistoryPanel(), BorderLayout.EAST); - jContentPane.add(getActionPanel(), BorderLayout.NORTH); - - display.setPreferredSize(new Dimension(320, 480)); - - display.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - touch(event); - } - }); - } - return jContentPane; - } - - /** - * This method initializes historyPanel - * - * @return javax.swing.JScrollPane - */ - private JScrollPane getHistoryPanel() { - if (historyPanel == null) { - historyPanel = new JScrollPane(); - historyPanel.getViewport().setView(getHistoryList()); - } - return historyPanel; - } - - private JList getHistoryList() { - if (historyList == null) { - actionListModel = new ActionListModel(); - historyList = new JList(actionListModel); - } - return historyList; - } - - /** - * This method initializes actionPanel - * - * @return javax.swing.JPanel - */ - private JPanel getActionPanel() { - if (actionPanel == null) { - actionPanel = new JPanel(); - actionPanel.setLayout(new BoxLayout(getActionPanel(), BoxLayout.X_AXIS)); - actionPanel.add(getWaitButton(), null); - actionPanel.add(getPressButton(), null); - actionPanel.add(getTypeButton(), null); - actionPanel.add(getFlingButton(), null); - actionPanel.add(getExportActionButton(), null); - actionPanel.add(getRefreshButton(), null); - } - return actionPanel; - } - - /** - * This method initializes waitButton - * - * @return javax.swing.JButton - */ - private JButton getWaitButton() { - if (waitButton == null) { - waitButton = new JButton(); - waitButton.setText("Wait"); - waitButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent e) { - String howLongStr = JOptionPane.showInputDialog("How many seconds to wait?"); - if (howLongStr != null) { - float howLong = Float.parseFloat(howLongStr); - addAction(new WaitAction(howLong)); - } - } - }); - } - return waitButton; - } - - /** - * This method initializes pressButton - * - * @return javax.swing.JButton - */ - private JButton getPressButton() { - if (pressButton == null) { - pressButton = new JButton(); - pressButton.setText("Press a Button"); - pressButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent e) { - JPanel panel = new JPanel(); - JLabel text = new JLabel("What button to press?"); - JComboBox keys = new JComboBox(PressAction.KEYS); - keys.setEditable(true); - JComboBox direction = new JComboBox(PressAction.DOWNUP_FLAG_MAP.values().toArray()); - panel.add(text); - panel.add(keys); - panel.add(direction); - - int result = JOptionPane.showConfirmDialog(null, panel, "Input", JOptionPane.OK_CANCEL_OPTION); - if (result == JOptionPane.OK_OPTION) { - // Look up the "flag" value for the press choice - Map<String, String> lookupMap = PressAction.DOWNUP_FLAG_MAP.inverse(); - String flag = lookupMap.get(direction.getSelectedItem()); - addAction(new PressAction((String) keys.getSelectedItem(), flag)); - } - } - }); - } - return pressButton; - } - - /** - * This method initializes typeButton - * - * @return javax.swing.JButton - */ - private JButton getTypeButton() { - if (typeButton == null) { - typeButton = new JButton(); - typeButton.setText("Type Something"); - typeButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent e) { - String whatToType = JOptionPane.showInputDialog("What to type?"); - if (whatToType != null) { - addAction(new TypeAction(whatToType)); - } - } - }); - } - return typeButton; - } - - /** - * This method initializes flingButton - * - * @return javax.swing.JButton - */ - private JButton getFlingButton() { - if (flingButton == null) { - flingButton = new JButton(); - flingButton.setText("Fling"); - flingButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent e) { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - panel.add(new JLabel("Which Direction to fling?")); - JComboBox directionChooser = new JComboBox(DragAction.Direction.getNames()); - panel.add(directionChooser); - panel.add(new JLabel("How long to drag (in ms)?")); - JTextField ms = new JTextField(); - ms.setText("1000"); - panel.add(ms); - panel.add(new JLabel("How many steps to do it in?")); - JTextField steps = new JTextField(); - steps.setText("10"); - panel.add(steps); - - - - int result = JOptionPane.showConfirmDialog(null, panel, "Input", JOptionPane.OK_CANCEL_OPTION); - if (result == JOptionPane.OK_OPTION) { - DragAction.Direction dir = - DragAction.Direction.valueOf((String) directionChooser.getSelectedItem()); - long millis = Long.parseLong(ms.getText()); - int numSteps = Integer.parseInt(steps.getText()); - - addAction(newFlingAction(dir, numSteps, millis)); - } - } - }); - } - return flingButton; - } - - private DragAction newFlingAction(Direction dir, int numSteps, long millis) { - int width = Integer.parseInt(device.getProperty("display.width")); - int height = Integer.parseInt(device.getProperty("display.height")); - - // Adjust the w/h to a pct of the total size, so we don't hit things on the "outside" - width = (int) (width * 0.8f); - height = (int) (height * 0.8f); - int minW = (int) (width * 0.2f); - int minH = (int) (height * 0.2f); - - int midWidth = width / 2; - int midHeight = height / 2; - - int startx = minW; - int starty = minH; - int endx = minW; - int endy = minH; - - switch (dir) { - case NORTH: - startx = endx = midWidth; - starty = height; - break; - case SOUTH: - startx = endx = midWidth; - endy = height; - break; - case EAST: - starty = endy = midHeight; - endx = width; - break; - case WEST: - starty = endy = midHeight; - startx = width; - break; - } - - return new DragAction(dir, startx, starty, endx, endy, numSteps, millis); - } - - /** - * This method initializes exportActionButton - * - * @return javax.swing.JButton - */ - private JButton getExportActionButton() { - if (exportActionButton == null) { - exportActionButton = new JButton(); - exportActionButton.setText("Export Actions"); - exportActionButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent ev) { - JFileChooser fc = new JFileChooser(); - if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { - try { - actionListModel.export(fc.getSelectedFile()); - } catch (FileNotFoundException e) { - LOG.log(Level.SEVERE, "Unable to save file", e); - } - } - } - }); - } - return exportActionButton; - } - - /** - * This method initializes refreshButton - * - * @return javax.swing.JButton - */ - private JButton getRefreshButton() { - if (refreshButton == null) { - refreshButton = new JButton(); - refreshButton.setText("Refresh Display"); - refreshButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent e) { - refreshDisplay(); - } - }); - } - return refreshButton; - } - - private void touch(MouseEvent event) { - int x = event.getX(); - int y = event.getY(); - - // Since we scaled the image down, our x/y are scaled as well. - double scalex = ((double) currentImage.getWidth()) / ((double) scaledImage.getWidth()); - double scaley = ((double) currentImage.getHeight()) / ((double) scaledImage.getHeight()); - - x = (int) (x * scalex); - y = (int) (y * scaley); - - switch (event.getID()) { - case MouseEvent.MOUSE_CLICKED: - addAction(new TouchAction(x, y, MonkeyDevice.DOWN_AND_UP)); - break; - case MouseEvent.MOUSE_PRESSED: - addAction(new TouchAction(x, y, MonkeyDevice.DOWN)); - break; - case MouseEvent.MOUSE_RELEASED: - addAction(new TouchAction(x, y, MonkeyDevice.UP)); - break; - } - } - - public void addAction(Action a) { - actionListModel.add(a); - try { - a.execute(device); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Unable to execute action!", e); - } - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/Action.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/Action.java deleted file mode 100644 index 905f1f1..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/Action.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.android.chimpchat.core.IChimpDevice; - -/** - * All actions that can be recorded must implement this interface. - */ -public interface Action { - /** - * Serialize this action into a string. This method is called to put the list of actions into - * a file. - * - * @return the serialized string - */ - String serialize(); - - /** - * Get the printable name for this action. This method is used to show the Action in the UI. - * - * @return the display name - */ - String getDisplayName(); - - /** - * Execute the given action. - * - * @param device the device to execute the action on. - */ - void execute(IChimpDevice device) throws Exception; -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/DragAction.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/DragAction.java deleted file mode 100644 index 498bc6b..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/DragAction.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.android.chimpchat.core.IChimpDevice; - -/** - * Action to drag the "finger" across the device. - */ -public class DragAction implements Action { - private final long timeMs; - private final int steps; - private final int startx; - private final int starty; - private final int endx; - private final int endy; - private final Direction dir; - - public enum Direction { - NORTH, SOUTH, EAST, WEST; - - private static String[] names; - static { - Direction[] values = Direction.values(); - names = new String[values.length]; - for (int x = 0; x < values.length; x++) { - names[x] = values[x].name(); - } - } - - public static String[] getNames() { - return names; - } - } - - public DragAction(Direction dir, - int startx, int starty, int endx, int endy, - int numSteps, long millis) { - this.dir = dir; - this.startx = startx; - this.starty = starty; - this.endx = endx; - this.endy = endy; - steps = numSteps; - timeMs = millis; - } - - @Override - public String getDisplayName() { - return String.format("Fling %s", dir.name().toLowerCase()); - } - - @Override - public String serialize() { - float duration = timeMs / 1000.0f; - - String pydict = PyDictUtilBuilder.newBuilder(). - addTuple("start", startx, starty). - addTuple("end", endx, endy). - add("duration", duration). - add("steps", steps). - build(); - return "DRAG|" + pydict; - } - - @Override - public void execute(IChimpDevice device) { - device.drag(startx, starty, endx, endy, steps, timeMs); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PressAction.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PressAction.java deleted file mode 100644 index 4245736..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PressAction.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; - -import com.android.monkeyrunner.MonkeyDevice; -import com.android.chimpchat.core.IChimpDevice; -import com.android.chimpchat.core.TouchPressType; - -/** - * Action to press a certain button. - */ -public class PressAction implements Action { - public static String[] KEYS = { - "MENU", "HOME", "SEARCH", - }; - - public static final BiMap<String, String> DOWNUP_FLAG_MAP = - ImmutableBiMap.of(MonkeyDevice.DOWN_AND_UP, "Press", - MonkeyDevice.DOWN, "Down", - MonkeyDevice.UP, "Up"); - - private final String key; - private final String downUpFlag; - - public PressAction(String key, String downUpFlag) { - this.key = key; - this.downUpFlag = downUpFlag; - } - - public PressAction(String key) { - this(key, MonkeyDevice.DOWN_AND_UP); - } - - @Override - public String getDisplayName() { - return String.format("%s button %s", - DOWNUP_FLAG_MAP.get(downUpFlag), key); - } - - @Override - public String serialize() { - String pydict = PyDictUtilBuilder.newBuilder(). - add("name", key). - add("type", downUpFlag).build(); - return "PRESS|" + pydict; - } - - @Override - public void execute(IChimpDevice device) { - device.press(key, TouchPressType.fromIdentifier(downUpFlag)); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PyDictUtilBuilder.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PyDictUtilBuilder.java deleted file mode 100644 index 0cfbabe..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/PyDictUtilBuilder.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -/** - * Utility class to create Python Dictionary Strings. - * - * {'key': 'value'} - */ -public class PyDictUtilBuilder { - private StringBuilder sb = new StringBuilder(); - - public PyDictUtilBuilder() { - sb.append("{"); - } - - public static PyDictUtilBuilder newBuilder() { - return new PyDictUtilBuilder(); - } - - private void addHelper(String key, String value) { - sb.append("'").append(key).append("'"); - sb.append(":").append(value).append(","); - } - - public PyDictUtilBuilder add(String key, int value) { - addHelper(key, Integer.toString(value)); - return this; - } - - public PyDictUtilBuilder add(String key, float value) { - addHelper(key, Float.toString(value)); - return this; - } - - public PyDictUtilBuilder add(String key, String value) { - addHelper(key, "'" + value + "'"); - return this; - } - - public String build() { - sb.append("}"); - return sb.toString(); - } - - public PyDictUtilBuilder addTuple(String key, int x, int y) { - String valuestr = new StringBuilder().append("(").append(x).append(",").append(y).append(")").toString(); - addHelper(key, valuestr); - return this; - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TouchAction.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TouchAction.java deleted file mode 100644 index 146bb55..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TouchAction.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; - -import com.android.monkeyrunner.MonkeyDevice; -import com.android.chimpchat.core.IChimpDevice; -import com.android.chimpchat.core.TouchPressType; - -/** - * Action to touch the touchscreen at a certain location. - */ -public class TouchAction implements Action { - public static final BiMap<String, String> DOWNUP_FLAG_MAP = - ImmutableBiMap.of(MonkeyDevice.DOWN_AND_UP, "Tap", - MonkeyDevice.DOWN, "Down", - MonkeyDevice.UP, "Up"); - - private final int x; - private final int y; - private final String direction; - - public TouchAction(int x, int y, String direction) { - this.x = x; - this.y = y; - this.direction = direction; - } - - @Override - public String getDisplayName() { - return String.format("%s touchscreen at (%d, %d)", - DOWNUP_FLAG_MAP.get(direction), x, y); - } - - @Override - public void execute(IChimpDevice device) throws Exception { - device.touch(x, y, TouchPressType.fromIdentifier(direction)); - } - - @Override - public String serialize() { - String pydict = PyDictUtilBuilder.newBuilder(). - add("x", x). - add("y", y). - add("type", direction).build(); - return "TOUCH|" + pydict; - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TypeAction.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TypeAction.java deleted file mode 100644 index fd5f786..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/TypeAction.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.android.chimpchat.core.IChimpDevice; - -/** - * Action to type in a string on the device. - */ -public class TypeAction implements Action { - private final String whatToType; - - public TypeAction(String whatToType) { - this.whatToType = whatToType; - } - - @Override - public String getDisplayName() { - return String.format("Type \"%s\"", whatToType); - } - - @Override - public String serialize() { - String pydict = PyDictUtilBuilder.newBuilder() - .add("message", whatToType).build(); - return "TYPE|" + pydict; - } - - @Override - public void execute(IChimpDevice device) { - device.type(whatToType); - } -} diff --git a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/WaitAction.java b/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/WaitAction.java deleted file mode 100644 index d61570b..0000000 --- a/monkeyrunner/src/com/android/monkeyrunner/recorder/actions/WaitAction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2010 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.recorder.actions; - -import com.android.chimpchat.core.IChimpDevice; - -/** - * Action that specifies to wait for a certain amount of time. - */ -public class WaitAction implements Action { - private final float howLongSeconds; - - public WaitAction(float howLongSeconds) { - this.howLongSeconds = howLongSeconds; - } - - public String getDisplayName() { - return String.format("Wait for %g seconds", this.howLongSeconds); - } - - public String serialize() { - String pydict = PyDictUtilBuilder.newBuilder().add("seconds", howLongSeconds).build(); - return "WAIT|" + pydict; - } - - public void execute(IChimpDevice device) throws Exception { - long ms = (long) (1000.0f * howLongSeconds); - Thread.sleep(ms); - } -} |