1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.monkeyrunner.easy; 18 19import com.google.common.base.Preconditions; 20 21import com.android.chimpchat.core.TouchPressType; 22import com.android.chimpchat.hierarchyviewer.HierarchyViewer; 23import com.android.hierarchyviewerlib.device.ViewNode; 24import com.android.monkeyrunner.JythonUtils; 25import com.android.monkeyrunner.MonkeyDevice; 26import com.android.monkeyrunner.doc.MonkeyRunnerExported; 27 28import org.eclipse.swt.graphics.Point; 29import org.python.core.ArgParser; 30import org.python.core.ClassDictInit; 31import org.python.core.Py; 32import org.python.core.PyException; 33import org.python.core.PyInteger; 34import org.python.core.PyObject; 35import org.python.core.PyTuple; 36 37import java.util.Set; 38 39/** 40 * Extends {@link MonkeyDevice} to support looking up views using a 'selector'. 41 * Currently, only identifiers can be used as a selector. All methods on 42 * MonkeyDevice can be used on this class in Python. 43 * 44 * WARNING: This API is under development, expect the interface to change 45 * without notice. 46 */ 47@MonkeyRunnerExported(doc = "MonkeyDevice with easier methods to refer to objects.") 48public class EasyMonkeyDevice extends PyObject implements ClassDictInit { 49 public static void classDictInit(PyObject dict) { 50 JythonUtils.convertDocAnnotationsForClass(EasyMonkeyDevice.class, dict); 51 } 52 53 private MonkeyDevice mDevice; 54 private HierarchyViewer mHierarchyViewer; 55 56 private static final Set<String> EXPORTED_METHODS = 57 JythonUtils.getMethodNames(EasyMonkeyDevice.class); 58 59 @MonkeyRunnerExported(doc = "Creates EasyMonkeyDevice with an underlying MonkeyDevice.", 60 args = { "device" }, 61 argDocs = { "MonkeyDevice to extend." }) 62 public EasyMonkeyDevice(MonkeyDevice device) { 63 this.mDevice = device; 64 this.mHierarchyViewer = device.getImpl().getHierarchyViewer(); 65 } 66 67 @MonkeyRunnerExported(doc = "Sends a touch event to the selected object.", 68 args = { "selector", "type" }, 69 argDocs = { 70 "The selector identifying the object.", 71 "The event type as returned by TouchPressType()." }) 72 public void touch(PyObject[] args, String[] kws) { 73 ArgParser ap = JythonUtils.createArgParser(args, kws); 74 Preconditions.checkNotNull(ap); 75 76 By selector = getSelector(ap, 0); 77 String tmpType = ap.getString(1); 78 TouchPressType type = TouchPressType.fromIdentifier(tmpType); 79 Preconditions.checkNotNull(type, "Invalid touch type: " + tmpType); 80 // TODO: try catch rethrow PyExc 81 touch(selector, type); 82 } 83 84 public void touch(By selector, TouchPressType type) { 85 Point p = getElementCenter(selector); 86 mDevice.getImpl().touch(p.x, p.y, type); 87 } 88 89 @MonkeyRunnerExported(doc = "Types a string into the specified object.", 90 args = { "selector", "text" }, 91 argDocs = { 92 "The selector identifying the object.", 93 "The text to type into the object." }) 94 public void type(PyObject[] args, String[] kws) { 95 ArgParser ap = JythonUtils.createArgParser(args, kws); 96 Preconditions.checkNotNull(ap); 97 98 By selector = getSelector(ap, 0); 99 String text = ap.getString(1); 100 type(selector, text); 101 } 102 103 public void type(By selector, String text) { 104 Point p = getElementCenter(selector); 105 mDevice.getImpl().touch(p.x, p.y, TouchPressType.DOWN_AND_UP); 106 mDevice.getImpl().type(text); 107 } 108 109 @MonkeyRunnerExported(doc = "Locates the coordinates of the selected object.", 110 args = { "selector" }, 111 argDocs = { "The selector identifying the object." }, 112 returns = "Tuple containing (x,y,w,h) location and size.") 113 public PyTuple locate(PyObject[] args, String[] kws) { 114 ArgParser ap = JythonUtils.createArgParser(args, kws); 115 Preconditions.checkNotNull(ap); 116 117 By selector = getSelector(ap, 0); 118 119 ViewNode node = selector.findView(mHierarchyViewer); 120 Point p = HierarchyViewer.getAbsolutePositionOfView(node); 121 PyTuple tuple = new PyTuple( 122 new PyInteger(p.x), 123 new PyInteger(p.y), 124 new PyInteger(node.width), 125 new PyInteger(node.height)); 126 return tuple; 127 } 128 129 @MonkeyRunnerExported(doc = "Checks if the specified object exists.", 130 args = { "selector" }, 131 returns = "True if the object exists.", 132 argDocs = { "The selector identifying the object." }) 133 public boolean exists(PyObject[] args, String[] kws) { 134 ArgParser ap = JythonUtils.createArgParser(args, kws); 135 Preconditions.checkNotNull(ap); 136 137 By selector = getSelector(ap, 0); 138 return exists(selector); 139 } 140 141 public boolean exists(By selector) { 142 ViewNode node = selector.findView(mHierarchyViewer); 143 return node != null; 144 } 145 146 @MonkeyRunnerExported(doc = "Checks if the specified object is visible.", 147 args = { "selector" }, 148 returns = "True if the object is visible.", 149 argDocs = { "The selector identifying the object." }) 150 public boolean visible(PyObject[] args, String[] kws) { 151 ArgParser ap = JythonUtils.createArgParser(args, kws); 152 Preconditions.checkNotNull(ap); 153 154 By selector = getSelector(ap, 0); 155 return visible(selector); 156 } 157 158 public boolean visible(By selector) { 159 ViewNode node = selector.findView(mHierarchyViewer); 160 return mHierarchyViewer.visible(node); 161 } 162 163 @MonkeyRunnerExported(doc = "Obtain the text in the selected input box.", 164 args = { "selector" }, 165 argDocs = { "The selector identifying the object." }, 166 returns = "Text in the selected input box.") 167 public String getText(PyObject[] args, String[] kws) { 168 ArgParser ap = JythonUtils.createArgParser(args, kws); 169 Preconditions.checkNotNull(ap); 170 171 By selector = getSelector(ap, 0); 172 return getText(selector); 173 } 174 175 public String getText(By selector) { 176 ViewNode node = selector.findView(mHierarchyViewer); 177 return mHierarchyViewer.getText(node); 178 } 179 180 @MonkeyRunnerExported(doc = "Gets the id of the focused window.", 181 returns = "The symbolic id of the focused window or None.") 182 public String getFocusedWindowId(PyObject[] args, String[] kws) { 183 return getFocusedWindowId(); 184 } 185 186 public String getFocusedWindowId() { 187 return mHierarchyViewer.getFocusedWindowName(); 188 } 189 190 /** 191 * Forwards unknown methods to the original MonkeyDevice object. 192 */ 193 @Override 194 public PyObject __findattr_ex__(String name) { 195 if (!EXPORTED_METHODS.contains(name)) { 196 return mDevice.__findattr_ex__(name); 197 } 198 return super.__findattr_ex__(name); 199 } 200 201 /** 202 * Get the selector object from the argument parser. 203 * 204 * @param ap argument parser to get it from. 205 * @param i argument index. 206 * @return selector object. 207 */ 208 private By getSelector(ArgParser ap, int i) { 209 return (By)ap.getPyObject(i).__tojava__(By.class); 210 } 211 212 /** 213 * Get the coordinates of the element's center. 214 * 215 * @param selector the element selector 216 * @return the (x,y) coordinates of the center 217 */ 218 private Point getElementCenter(By selector) { 219 ViewNode node = selector.findView(mHierarchyViewer); 220 if (node == null) { 221 throw new PyException(Py.ValueError, 222 String.format("View not found: %s", selector)); 223 } 224 225 Point p = HierarchyViewer.getAbsoluteCenterOfView(node); 226 return p; 227 } 228 229} 230