/* * 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.device.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; } }