How to use setDisplayToScreenCoords method in fMBT

Best Python code snippet using fMBT_python

fmbtwindows.py

Source:fmbtwindows.py Github

copy

Full Screen

...1161 screenWidth, screenHeight = self.screenSize()1162 self._conn.setScreenToDisplayCoords(1163 lambda x, y: (x * width / screenWidth,1164 y * height / screenHeight))1165 self._conn.setDisplayToScreenCoords(1166 lambda x, y: (x * screenWidth / width,1167 y * screenHeight / height))1168 def setForegroundWindow(self, window):1169 """1170 Set a window with the title as a foreground window1171 Parameters:1172 window (title (string) or hwnd (integer):1173 title or handle of the window to be raised1174 foreground.1175 Returns True if the window was brought to the foreground,1176 otherwise False.1177 Notes: calls SetForegroundWindow in user32.dll.1178 """1179 return self.existingConnection().sendSetForegroundWindow(window)1180 def setRefreshViewDefaults(self, **kwargs):1181 """Set new default arguments for refreshView() calls1182 Parameters:1183 **kwargs (keyword arguments)1184 new default values for optional refreshView() parameters.1185 Note: default arguments are overridden by arguments given1186 directly in refreshView calls.1187 Note: setViewSource() can change the default arguments.1188 Example:1189 setRefreshViewDefaults(window="My app title",1190 viewSource="uiautomation/content")1191 """1192 self._refreshViewDefaults = kwargs1193 def findRegistry(self, rootKey, key=None, valueName=None, limit=1):1194 """Search for key and/or valueName from the registry.1195 Returns a list of matching (fullKeyPath, valueName) pairs1196 found under the rootKey. The list has at most limit items, the1197 default is 1.1198 Parameters:1199 rootKey (string):1200 root key path for the search. Example:1201 "HKEY_LOCAL_MACHINE".1202 key (string, optional):1203 key name to be searched for under the rootKey.1204 The key is a regular expression that is searched for1205 from full key path. Use "\\name$" to require exact1206 match.1207 If not given, valueName should be defined.1208 valueName (string, optional):1209 value name to be searched for under the rootKey.1210 The value can be a regular expression.1211 If not given, key should be defined and1212 returned valueName will be None.1213 limit (integer, optional):1214 maximum number of matches to be returned. The1215 default is 1. limit=None returns all matching1216 pairs.1217 Example:1218 findRegistry("HKEY_LOCAL_MACHINE", key="\\Windows$")1219 """1220 if key == None and valueName == None:1221 raise ValueError("either key or valueName must be provided")1222 return self.existingConnection().evalPython(1223 'findRegistry(%s, key=%s, valueName=%s, limit=%s)' % (1224 repr(rootKey), repr(key), repr(valueName), repr(limit)))1225 def setRegistry(self, key, valueName, value, valueType=None):1226 """1227 Set Windows registry value.1228 Parameters:1229 key (string):1230 full key name.1231 valueName (string):1232 name of the value to be set.1233 value (string):1234 string that specifies the new value.1235 valueType (string, optional for str and int values):1236 REG_BINARY, REG_DWORD, REG_DWORD_LITTLE_ENDIAN,1237 REG_DWORD_BIG_ENDIAN, REG_EXPAND_SZ, REG_LINK,1238 REG_MULTI_SZ, REG_NONE, REG_RESOURCE_LIST or REG_SZ.1239 Default types for storing str and int values1240 are REG_SZ and REG_DWORD.1241 Example:1242 setRegistry(r"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet"1243 "\Control\Session Manager\Environment",1244 "PATH", r"C:\MyExecutables", "REG_EXPAND_SZ")1245 Returns True on success.1246 """1247 return self.existingConnection().evalPython(1248 "setRegistry(%s,%s,%s,%s)" % (repr(key), repr(valueName),1249 repr(value), repr(valueType)))1250 def getRegistry(self, key, valueName):1251 """1252 Return Windows registry value and type1253 Parameters:1254 key (string):1255 full key name.1256 valueName (string):1257 name of the value to be read.1258 Returns a pair (value, valueType)1259 Example:1260 getRegistry(r"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet"1261 "\Control\Session Manager\Environment", "PATH")1262 """1263 return self.existingConnection().evalPython(1264 "getRegistry(%s,%s)" % (repr(key), repr(valueName)))1265 def processList(self):1266 """1267 Return list of processes running on the device.1268 Returns list of dictionaries with keys:1269 "pid": process ID, and1270 "ProcessImageFileName": full path to the executable in win32 format.1271 """1272 return self.existingConnection().evalPython("processList()")1273 def processStatus(self, pid):1274 """1275 Return status of a process1276 Parameters:1277 pid (integer):1278 Process ID of the process1279 Returns properties in a dictionary.1280 Example:1281 print "Memory usage:", processStatus(4242)["WorkingSetSize"]1282 """1283 return self.existingConnection().evalPython(1284 "processStatus(%s)" % (repr(pid),))1285 def productList(self):1286 """1287 Return list of products installed or advertised in the system1288 Returns list of dictionaries, each containing properties of a product.1289 """1290 return self.existingConnection().evalPython("products()")1291 def pycosh(self, command):1292 """1293 Run command in pycosh shell on the device.1294 Parameters:1295 command (string):1296 pycosh command to be executed. Pycosh implements1297 stripped-down versions of zip, tar, find, md5sum, diff,1298 grep, head, tail, curl,... the usual handy shell utils.1299 For information on pycosh commands, try1300 device.pycosh("help") or run in shell:1301 echo help | python -m pycosh.1302 """1303 return self.existingConnection().pycosh(command)1304 def setScreenshotSize(self, size):1305 """1306 Force screenshots from device to use given resolution.1307 Overrides detected monitor resolution on device.1308 Parameters:1309 size (pair of integers: (width, height)):1310 width and height of screenshot.1311 """1312 self._conn.setScreenshotSize(size)1313 def setTopWindow(self, window):1314 """1315 Set a window as a foreground window and bring it to front.1316 Parameters:1317 window (title (string) or hwnd (integer):1318 title or handle of the window to be raised1319 foreground.1320 Returns True if the window was brought to the foreground,1321 otherwise False.1322 Notes: calls SetForegroundWindow in user32.dll.1323 """1324 return self.existingConnection().sendSetTopWindow(window)1325 def setViewSource(self, source, properties=None):1326 """1327 Set default view source for refreshView()1328 Parameters:1329 source (string):1330 default source, "enumchildwindow" or "uiautomation",1331 "uiautomation/raw", "uiautomation/control",1332 "uiautomation/content".1333 properties (string or list of strings, optional):1334 set list of view item properties to be read.1335 "all" reads all available properties for each item.1336 "fast" reads a set of preselected properties.1337 list of strings reads properties in the list.1338 The default is "all".1339 Returns None.1340 See also refreshView(), viewSource(), refreshViewDefaults().1341 """1342 if not source in _g_viewSources:1343 raise ValueError(1344 'invalid view source "%s", expected one of: "%s"' %1345 (source, '", "'.join(_g_viewSources)))1346 if properties != None:1347 self._refreshViewDefaults["properties"] = properties1348 self._refreshViewDefaults["viewSource"] = source1349 def shell(self, command):1350 """1351 Execute command in Windows.1352 Parameters:1353 command (string or list of strings):1354 command to be executed. Will be forwarded directly1355 to subprocess.check_output. If command is a string,1356 then it will be executed in subshell, otherwise without1357 shell.1358 Returns what is printed by the command.1359 If you wish to receive exitstatus or standard output and error1360 separated from command, refer to shellSOE().1361 """1362 return self._conn.evalPython('shell(%s)' % (repr(command),))1363 def shellSOE(self, command, asyncStatus=None, asyncOut=None,1364 asyncError=None, cwd=None, timeout=None):1365 """Execute command on Windows.1366 Parameters:1367 command (string or list of strings):1368 command to be executed. If command is a list of1369 string, it will be executed without shell1370 (subprocess.check_output with shell=False).1371 If command is a single-line string, it will be1372 executed in shell (subprocess.check_output with1373 shell=True).1374 If command is a multiline string, it will be written1375 to a BAT file and executed as a script.1376 asyncStatus (string, True or None)1377 filename (on device) to which the status of1378 asynchronously executed shellCommand will be1379 written. If True, the command will be executed1380 asynchronously but exit status will not be1381 saved. The default is None, that is, command will be1382 run synchronously, and status will be returned in1383 the tuple.1384 asyncOut (string, True or None)1385 filename (on device) to which the standard output of1386 asynchronously executed shellCommand will be1387 written. If True, the command will be executed1388 asynchronously but output will not saved. The1389 default is None.1390 asyncError (string, True or None)1391 filename (on device) to which the standard error of1392 asynchronously executed shellCommand will be1393 written. If True, the command will be executed1394 asynchronously but standard error will not be1395 saved. The default is None.1396 cwd (string, optional)1397 current working directory in which the command1398 will be executed. If not given, the cwd defaults1399 to the current working directory of the pythonshare1400 server process on the device, or the cwd of the Python1401 process if executed on host without pythonshare-server.1402 timeout (float, optional)1403 forcefully kill child processes and return after1404 given time (in seconds). If timed out, returned output1405 and error strings contain what was printed until processes1406 were killed. Returned status is a fmbtwindows.Timeout1407 instance. Asynchronous executions cannot be timed out.1408 The default is None (no timeout).1409 Returns triplet: exit status, standard output and standard error1410 (int, str, str) from the command.1411 If executing command fails, returns (None, None, None).1412 If execution is timed out, returns (fmbtwindows.Timeout, str, str)1413 or (fmbtwindows.Timeout, None, None) if outputs could not be read.1414 """1415 if (timeout != None and1416 (asyncStatus, asyncOut, asyncError) != (None, None, None)):1417 raise NotImplementedError(1418 "timeout for asynchronous execution is not supported")1419 s, o, e = self._conn.evalPython(1420 'shellSOE(%s, asyncStatus=%s, asyncOut=%s, asyncError=%s, '1421 'cwd=%s, timeout=%s)'1422 % (repr(command),1423 repr(asyncStatus), repr(asyncOut), repr(asyncError),1424 repr(cwd), repr(timeout)))1425 if isinstance(s, str) and s.startswith("TIMEOUT"):1426 s = Timeout(command=command[:1024*8],1427 pid=int(s.split()[-1]))1428 return s, o, e1429 def showWindow(self, window, showCmd=SW_NORMAL):1430 """1431 Send showCmd to window.1432 Parameters:1433 window (window title (string) or handle (integer)):1434 window to which the command will be sent.1435 showCmd (integer or string):1436 command to be sent. Valid commands are 0..11:1437 SW_HIDE, SW_NORMAL, SW_MINIMIZED, SW_MAXIMIZE,1438 SW_NOACTIVATE, SW_SHOW SW_MINIMIZE, SW_MINNOACTIVE,1439 SW_SHOWNA, SW_RESTORE, SW_DEFAULT, SW_FORCEMINIMIZE.1440 Returns True if the window was previously visible,1441 otherwise False.1442 Notes: calls ShowWindow in user32.dll.1443 """1444 return self.existingConnection().sendShowWindow(window, showCmd)1445 def tapText(self, text, partial=False, **tapKwArgs):1446 """1447 Find an item with given text from the latest view, and tap it.1448 Parameters:1449 partial (boolean, optional):1450 refer to verifyText documentation. The default is1451 False.1452 tapPos (pair of floats (x, y)):1453 refer to tapItem documentation.1454 button, long, hold, count, delayBetweenTaps (optional):1455 refer to tap documentation.1456 Returns True if successful, otherwise False.1457 """1458 items = self.existingView().findItemsByText(text, partial=partial, count=1, onScreen=True)1459 if len(items) == 0: return False1460 return self.tapItem(items[0], **tapKwArgs)1461 def topWindow(self):1462 """1463 Returns a handle to the window.1464 """1465 return self.existingConnection().evalPython(1466 "ctypes.windll.user32.GetForegroundWindow()")1467 def topWindowProperties(self):1468 """1469 Return properties of the top window as a dictionary1470 """1471 return self._conn.recvTopWindowProperties()1472 def verifyText(self, text, partial=False):1473 """1474 Verify that the last view has at least one item with given1475 text.1476 Parameters:1477 text (string):1478 text to be searched for in items.1479 partial (boolean, optional):1480 if True, match items if item text contains given1481 text, otherwise match only if item text is equal to1482 the given text. The default is False (exact match).1483 """1484 assert self._lastView != None, "View required."1485 return self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True) != []1486 def viewSource(self):1487 """1488 Returns current default view source.1489 See also refreshView(), setViewSource().1490 """1491 return self._refreshViewDefaults.get(1492 "viewSource", self._defaultViewSource)1493 def windowList(self):1494 """1495 Return list of properties of windows (dictionaries)1496 Example: list window handles and titles:1497 for props in d.windowList():1498 print props["hwnd"], props["title"]1499 """1500 return self._conn.recvWindowList()1501 def windowProperties(self, window):1502 """1503 Returns properties of a window.1504 Parameters:1505 window (title (string) or hwnd (integer):1506 The window whose properties will be returned.1507 Returns properties in a dictionary.1508 """1509 return self.existingConnection().recvWindowProperties(window)1510 def windowStatus(self, window):1511 """1512 Returns status of a window.1513 Parameters:1514 window (title (string) or hwnd (integer):1515 The window whose properties will be returned.1516 Returns status in a dictionary.1517 """1518 return self.existingConnection().recvWindowStatus(window)1519 def view(self):1520 return self._lastView1521 def viewStats(self):1522 return self._lastViewStats1523class _NoPythonshareConnection(object):1524 """Fake Pythonshare connection, evaluate everything locally"""1525 def __init__(self, namespace="default"):1526 self._namespaces = {}1527 self._ns = namespace1528 def exec_in(self, ns, code):1529 if not ns in self._namespaces:1530 self._namespaces[ns] = {}1531 exec code in self._namespaces[ns]1532 def eval_in(self, ns, expr):1533 if not ns in self._namespaces:1534 self._namespaces[ns] = {}1535 return eval(expr, self._namespaces[ns])1536 def namespace(self):1537 return self._ns1538class WindowsConnection(fmbtgti.GUITestConnection):1539 def __init__(self, connspec, password, device):1540 fmbtgti.GUITestConnection.__init__(self)1541 self._device = device1542 self._screenshotSize = (None, None) # autodetect1543 self._pycosh_sent_to_dut = False1544 if connspec != None:1545 self._agent = pythonshare.connect(connspec, password=password)1546 else:1547 if os.name != "nt":1548 raise ValueError("connecting to host works only on Windows")1549 self._agent = _NoPythonshareConnection()1550 self._agent_ns = self._agent.namespace()1551 agentFilename = os.path.join(1552 os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),1553 "fmbtwindows_agent.py")1554 self._agent.exec_in(self._agent_ns, file(agentFilename).read())1555 self.setScreenToDisplayCoords(lambda x, y: (x, y))1556 self.setDisplayToScreenCoords(lambda x, y: (x, y))1557 def pycosh(self, command):1558 if not self._pycosh_sent_to_dut:1559 # upload pycosh module to DUT1560 try:1561 self.evalPython("len(_g_pycosh_source)")1562 except pythonshare.RemoteEvalError:1563 self.execPython(file(inspect.getsourcefile(pycosh)).read())1564 self._pycosh_sent_to_dut = True1565 return self.evalPython("pycosh_eval(%s)" % (repr(command),))1566 def setScreenshotSize(self, screenshotSize):1567 self._screenshotSize = screenshotSize1568 screenW, screenH = self._screenshotSize1569 inputW, inputH = self._agent.eval_in(self._agent_ns, "_mouse_input_area")1570 self.setScreenToDisplayCoords(1571 lambda x, y: (x * inputW / screenW, y * inputH / screenH))1572 self.setDisplayToScreenCoords(1573 lambda x, y: (x * screenW / inputW, y * screenH / inputH))1574 def execPython(self, code):1575 return self._agent.exec_in(self._agent_ns, code)1576 def evalPython(self, code):1577 return self._agent.eval_in(self._agent_ns, code)1578 def recvFile(self, remoteFilename, localFilename=None, compress=False):1579 if compress:1580 if isinstance(compress, int):1581 compressLevel = compress1582 else:1583 compressLevel = 31584 data_b64_z = self._agent.eval_in(1585 self._agent_ns,1586 "base64.b64encode(zlib.compress(file(%s, 'rb').read(), %s))" % (1587 repr(remoteFilename), compressLevel))1588 data = zlib.decompress(base64.b64decode(data_b64_z))1589 else:1590 data_b64 = self._agent.eval_in(1591 self._agent_ns,1592 "base64.b64encode(file(%s, 'rb').read())" % (repr(remoteFilename),))1593 data = base64.b64decode(data_b64)1594 if localFilename:1595 file(localFilename, "wb").write(data)1596 return True1597 else:1598 return data1599 def sendFile(self, localFilename, remoteFilepath, data=None):1600 sendBlockMaxLen = 10 * 1024 * 1024 # Send at most 10 MB at a time1601 sendDataFromFile = False1602 if data == None:1603 fileSize = os.stat(localFilename).st_size1604 if fileSize < sendBlockMaxLen:1605 data = open(localFilename, "rb").read()1606 else:1607 data = ""1608 dataFile = open(localFilename, "rb")1609 sendDataFromFile = True1610 if localFilename:1611 basename = os.path.basename(localFilename)1612 else:1613 basename = localFilename1614 if sendDataFromFile:1615 dataLen = fileSize1616 else:1617 dataLen = len(data)1618 sendIndex = 01619 while sendIndex < dataLen or dataLen == 0:1620 if sendDataFromFile:1621 sendData = dataFile.read(sendBlockMaxLen)1622 else:1623 sendData = data[sendIndex:sendIndex + sendBlockMaxLen]1624 rv = self.evalPython(1625 'saveFile(%s, %s, base64.b64decode(%s), append=%s)' %1626 (repr(basename),1627 repr(remoteFilepath),1628 repr(base64.b64encode(sendData)),1629 repr(sendIndex != 0)))1630 sendIndex += sendBlockMaxLen1631 if not rv or dataLen == 0:1632 break1633 if sendDataFromFile:1634 dataFile.close()1635 return rv1636 def recvMatchingPaths(self, pathnamePattern):1637 filepaths = self._agent.eval_in(1638 self._agent_ns,1639 "glob.glob(%s)" % (repr(pathnamePattern),))1640 if "/" in pathnamePattern:1641 # Unix-style directory naming in input,1642 # stick with it and fix mixed / and \ that might1643 # come out from glob.glob.1644 return [p.replace('\\', '/') for p in filepaths]1645 else:1646 # use glob output as it is1647 return filepaths1648 def recvScreenshot(self, filename, screenshotSize=(None, None)):1649 ppmfilename = filename + ".ppm"1650 if screenshotSize == (None, None):1651 screenshotSize = self._screenshotSize1652 width, height, zdata = self._agent.eval_in(1653 self._agent_ns, "screenshotZYBGR(%s)" % (repr(screenshotSize),))1654 data = zlib.decompress(zdata)1655 fmbtgti.eye4graphics.wbgr2rgb(data, width, height)1656 if fmbtpng != None:1657 file(filename, "wb").write(1658 fmbtpng.raw2png(data, width, height, 8, "RGB"))1659 else:1660 ppm_header = "P6\n%d %d\n%d\n" % (width, height, 255)1661 f = file(filename + ".ppm", "wb")1662 f.write(ppm_header)1663 f.write(data)1664 f.close()1665 _run([fmbt_config.imagemagick_convert, ppmfilename, filename], expectedExitStatus=[0])1666 os.remove(ppmfilename)1667 return True1668 def recvTopWindowProperties(self):1669 return self.evalPython("topWindowProperties()")1670 def recvWindowProperties(self, window):1671 hwnd = self._window2hwnd(window)1672 return self.evalPython("windowProperties(%s)" % (hwnd,))1673 def recvWindowStatus(self, window):1674 hwnd = self._window2hwnd(window)1675 return self.evalPython("windowStatus(%s)" % (hwnd,))1676 def recvViewData(self, window=None):1677 rv = None1678 if window == None:1679 rv = self.evalPython("topWindowWidgets()")1680 elif isinstance(window, int):1681 rv = self.evalPython("windowWidgets(%s)" % (repr(window),))1682 elif isinstance(window, str) or isinstance(window, unicode):1683 wlist = self.evalPython("windowList()")1684 for w in wlist:1685 if w["title"] == window:1686 rv = self.evalPython("windowWidgets(%s)" % (repr(w["hwnd"]),))1687 break1688 else:1689 raise ValueError('no window with title "%s"' % (window,))1690 else:1691 raise ValueError('illegal window "%s", expected integer or string (hWnd or title)' % (window,))1692 return rv1693 def _parseDumps(self, dumps, dump_suffix, error_template):1694 dumpFilename = self._device.getDumpFilename(dump_suffix) + '.log'1695 error_message = ''1696 rv = []1697 prop_data = {}1698 items = None1699 with open(dumpFilename, 'w') as f:1700 for dump in dumps:1701 f.write(dump + '\n')1702 for line in dump.split('\0'):1703 if line.startswith('!'):1704 error_message = line[1:]1705 continue1706 if line.startswith('#'): # It's a comment / debug output: skip it!1707 continue1708 if line == '[':1709 items = []1710 continue1711 if line == ']':1712 rv.append(items)1713 continue1714 if items is not None:1715 items.append(line)1716 if "=" not in line:1717 continue1718 prop_name, prop_value = line.split("=", 1)1719 if prop_name == "hash" and prop_data:1720 rv.append(prop_data)1721 prop_data = {}1722 prop_data[prop_name] = prop_value.replace(r"\r\n", "\n").replace(r"\\", "\\")1723 if prop_data:1724 rv.append(prop_data)1725 if error_message:1726 raise FMBTWindowsError(error_template % error_message)1727 return rv1728 def recvViewUIAutomation(self, window=None, items=[], properties=None, area=None, walker="raw",1729 filterType="none", filterCondition="", dumpChildClass="", dumpChildName="", doNotDump=False):1730 """returns list of dictionaries, each of which contains properties of1731 an item"""1732 if not walker in ["raw", "control", "content"]:1733 raise ValueError('invalid walker %r' % walker)1734 hwnd = self._window2hwnd(window) if window else None1735 if properties is None:1736 properties = []1737 else:1738 # make sure certain properties are always included1739 properties = list(frozenset(properties) | frozenset(["BoundingRectangle"]))1740 dumps = []1741 if items:1742 for item in items:1743 dumps.append(self.evalPython("dumpUIAutomationElements(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r)" % (1744 hwnd,1745 [str(item.id()) for item in item.branch()],1746 properties,1747 area,1748 walker,1749 filterType,1750 filterCondition,1751 dumpChildClass,1752 dumpChildName,1753 doNotDump)))1754 else:1755 dumps.append(self.evalPython("dumpUIAutomationElements(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r)" % (1756 hwnd,1757 [],1758 properties,1759 area,1760 walker,1761 filterType,1762 filterCondition,1763 dumpChildClass,1764 dumpChildName,1765 doNotDump)))1766 return self._parseDumps(dumps, "dumpUIAutomationElements",1767 "view is not available. An error happened while collecting UI elements with refreshView().\n%s")1768 def sendSetCacheMode(self, mode):1769 dump = self.evalPython("serverSetCacheMode(%r)" % mode)1770 self._parseDumps([dump], "serverSetCacheMode",1771 "An error happened while setting the cache mode.\n%s")1772 def sendClearCache(self):1773 dump = self.evalPython("serverClearCache()")1774 self._parseDumps([dump], "serverClearCache",1775 "An error happened while clearing the cache.\n%s")1776 def sendSetFocus(self, eltHash):1777 dump = self.evalPython("setAutomationElementFocus(%s)" % eltHash)1778 self._parseDumps([dump], "setAutomationElementFocus",1779 "An error happened while setting the focus.\n%s")1780 def sendCollapse(self, eltHash):1781 dump = self.evalPython("AutomationElementCollapse(%s)" % eltHash)1782 self._parseDumps([dump], "AutomationElementCollapse",1783 "An error happened while collapsing the viewitem.\n%s")1784 def sendExpand(self, eltHash):1785 dump = self.evalPython("AutomationElementExpand(%s)" % eltHash)1786 self._parseDumps([dump], "AutomationElementExpand",1787 "An error happened while expanding the viewitem.\n%s")1788 def recvViewCachedItem(self, eltHash):1789 dump = self.evalPython("getCachedAutomationElement(%s)" % eltHash)1790 return self._parseDumps([dump], "getCachedAutomationElement",1791 "viewitem is not available. An error happened while dumping it with cachedElement().\n%s")1792 def recvViewItemPatterns(self, eltHash):1793 dump = self.evalPython("getAutomationElementPatterns(%s)" % eltHash)1794 return self._parseDumps([dump], "getAutomationElementPatterns",1795 "viewitem patterns are not available. An error happened while collecting them with patterns().\n%s")1796 def recvViewItemProperties(self, eltHash):1797 dump = self.evalPython("getAutomationElementProperties(%s)" % eltHash)1798 return self._parseDumps([dump], "getAutomationElementProperties",1799 "viewitem properties are not available. An error happened while collecting them with refresh().\n%s")1800 def recvViewItemItems(self, eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren):1801 dump = self.evalPython("getAutomationElementItems(%s, %r, %r, %r, %r)" % (1802 eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren))1803 return self._parseDumps([dump], "getAutomationElementItems",1804 "viewitem items aren't available. An error happened while getting it with items().\n%s")1805 def recvViewItemContainerItems(self, eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren, scroll):1806 dump = self.evalPython("getAutomationElementContainerItems(%s, %r, %r, %r, %r, %r)" % (1807 eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren, scroll))1808 return self._parseDumps([dump], "getAutomationElementContainerItems",1809 "viewitem items aren't available. An error happened while getting it with containerItems().\n%s")1810 def recvViewItemSelectedItems(self, eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren, scroll):1811 dump = self.evalPython("getAutomationElementSelectedItems(%s, %r, %r, %r, %r, %r)" % (1812 eltHash, propertyName, separator, filterSubChildClassName, maxSubChildren, scroll))1813 return self._parseDumps([dump], "getAutomationElementSelectedItems",1814 "viewitem selected items aren't available. An error happened while getting it with selectedItems().\n%s")1815 def recvViewItemText(self, eltHash, maxLength):1816 dump = self.evalPython("getAutomationElementText(%s, %s)" % (eltHash, maxLength))1817 return self._parseDumps([dump], "getAutomationElementText",1818 "viewitem text isn't available. An error happened while getting it with longText().\n%s")1819 def recvViewItemSetValue(self, eltHash, value):1820 dump = self.evalPython("setAutomationElementValue(%s, %r)" % (eltHash, value))1821 return self._parseDumps([dump], "setAutomationElementValue",1822 "viewitem value isn't editable. An error happened while setting it with setValue().\n%s")1823 def recvWindowList(self):1824 return self.evalPython("windowList()")1825 def _window2hwnd(self, window):1826 if isinstance(window, str) or isinstance(window, unicode):1827 windowList = self.recvWindowList()1828 hwndList = [w["hwnd"] for w in windowList if w["title"] == window]1829 if not hwndList:1830 raise ValueError('no window with title "%s"' % (window,))1831 hwnd = hwndList[0]1832 elif isinstance(window, dict) and "hwnd" in window:1833 hwnd = window["hwnd"]1834 elif isinstance(window, int) or isinstance(window, long):1835 hwnd = window1836 else:1837 raise ValueError('invalid window "%s", string, integer or dict with "hwnd" key expected' % (window,))1838 return hwnd1839 def sendCloseWindow(self, window):1840 hwnd = self._window2hwnd(window)1841 return self.evalPython("closeWindow(%s)" % (repr(hwnd),))1842 def sendSetForegroundWindow(self, window):1843 hwnd = self._window2hwnd(window)1844 return 0 != self.evalPython("ctypes.windll.user32.SetForegroundWindow(%s)" %1845 (repr(hwnd),))1846 def sendSetTopWindow(self, window):1847 hwnd = self._window2hwnd(window)1848 return 0 != self.evalPython("setTopWindow(%s)" %1849 (repr(hwnd),))1850 def sendShowWindow(self, window, showCmd):1851 hwnd = self._window2hwnd(window)1852 return self.evalPython("showWindow(%s, %s)" % (repr(hwnd), repr(showCmd)))1853 def sendType(self, text):1854 command = 'sendType(%s)' % (repr(text),)1855 self._agent.eval_in(self._agent_ns, command)1856 return True1857 def sendPress(self, keyCode, modifiers=None):1858 if modifiers == None:1859 command = 'sendKey(%r,[])' % (keyCode,)1860 else:1861 command = 'sendKey(%r,%s)' % (keyCode, repr(modifiers))1862 self._agent.eval_in(self._agent_ns, command)1863 return True1864 def sendKeyDown(self, keyCode, modifiers=None):1865 if modifiers == None:1866 command = 'sendKeyDown(%r,[])' % (keyCode,)1867 else:1868 command = 'sendKeyDown(%r,%s)' % (keyCode, repr(modifiers))1869 self._agent.eval_in(self._agent_ns, command)1870 return True1871 def sendKeyUp(self, keyCode, modifiers=None):1872 if modifiers == None:1873 command = 'sendKeyUp(%r,[])' % (keyCode,)1874 else:1875 command = 'sendKeyUp(%r,%s)' % (keyCode, repr(modifiers))1876 self._agent.eval_in(self._agent_ns, command)1877 return True1878 def sendTap(self, x, y, button=None):1879 x, y = self._screenToDisplay(x, y)1880 if button == None:1881 command = "sendTap(%s, %s)" % (x, y)1882 else:1883 command = "sendClick(%s, %s, %s)" % (x, y, button)1884 self._agent.eval_in(self._agent_ns, command)1885 return True1886 def sendTouchDown(self, x, y, button=None):1887 x, y = self._screenToDisplay(x, y)1888 if button == None:1889 command = "sendTouchDown(%s, %s)" % (x, y)1890 else:1891 command = "(sendMouseMove(%s, %s), sendMouseDown(%s))" % (x, y, button)1892 self._agent.eval_in(self._agent_ns, command)1893 return True1894 def sendTouchMove(self, x, y, button=None):1895 x, y = self._screenToDisplay(x, y)1896 if button == None:1897 command = "sendTouchMove(%s, %s)" % (x, y)1898 else:1899 command = "sendMouseMove(%s, %s, %s)" % (x, y, button)1900 self._agent.eval_in(self._agent_ns, command)1901 return True1902 def sendTouchUp(self, x, y, button=None):1903 x, y = self._screenToDisplay(x, y)1904 if button == None:1905 command = "sendTouchUp(%s, %s)" % (x, y)1906 else:1907 command = "(sendMouseMove(%s, %s, %s), sendMouseUp(%s))" % (1908 x, y, button, button)1909 self._agent.eval_in(self._agent_ns, command)1910 return True1911 def sendPinch(self, *args):1912 self.evalPython("touchPinch%s" % (args,))1913 return True1914 def setScreenToDisplayCoords(self, screenToDisplayFunction):1915 self._screenToDisplay = screenToDisplayFunction1916 def setDisplayToScreenCoords(self, displayToScreenFunction):1917 self._displayToScreen = displayToScreenFunction...

Full Screen

Full Screen

fmbtandroid.py

Source:fmbtandroid.py Github

copy

Full Screen

...524 screenWidth, screenHeight = self.screenSize()525 self._conn.setScreenToDisplayCoords(526 lambda x, y: (x * width / screenWidth,527 y * height / screenHeight))528 self._conn.setDisplayToScreenCoords(529 lambda x, y: (x * screenWidth / width,530 y * screenHeight / height))531 def shell(self, shellCommand):532 """533 Execute shellCommand in adb shell.534 shellCommand is a string (arguments separated by whitespace).535 Returns output of "adb shell" command.536 If you wish to receive exitstatus or standard output and error537 separated from shellCommand, refer to shellSOE().538 """539 return self._conn._runAdb(["shell", shellCommand])[1]540 def shellSOE(self, shellCommand):541 """542 Execute shellCommand in adb shell.543 shellCommand is a string (arguments separated by whitespace).544 Returns tuple (exitStatus, standardOutput, standardError).545 Requires tar and uuencode to be available on the device.546 """547 return self._conn.shellSOE(shellCommand)548 def smsNumber(self, number, message):549 """550 Send message using SMS to given number.551 Parameters:552 number (string)553 phone number to which the SMS will be sent554 message (string)555 the message to be sent.556 Returns True on success, otherwise False.557 """558 smsCommand = ('am start -a android.intent.action.SENDTO ' +559 '-d sms:%s --es sms_body "%s"' +560 ' --ez exit_on_sent true') % (number, message)561 status, out, err = self.shellSOE(smsCommand)562 if status != 0:563 _logFailedCommand("sms", smsCommand, status, out, err)564 return False565 _adapterLog("SMS command returned %s" % (out + err,))566 time.sleep(2)567 self.pressKey("KEYCODE_DPAD_RIGHT")568 time.sleep(1)569 self.pressKey("KEYCODE_ENTER")570 return True571 def supportsView(self):572 """573 Check if connected device supports reading view data.574 View data is needed by refreshView(), view(), verifyText() and575 waitText(). It is produced by Android window dump.576 Returns True if view data can be read, otherwise False.577 """578 try:579 self._conn.recvViewData()580 return True581 except AndroidConnectionError:582 return False583 def systemProperty(self, propertyName):584 """585 Returns Android Monkey Device properties, such as586 "clock.uptime", refer to Android Monkey documentation.587 """588 return self._conn.recvVariable(propertyName)589 def tapId(self, viewItemId, **tapKwArgs):590 """591 Find an item with given id from the latest view, and tap it.592 """593 assert self._lastView != None, "View required."594 items = self._lastView.findItemsById(viewItemId, count=1)595 if len(items) > 0:596 return self.tapItem(items[0], **tapKwArgs)597 else:598 _adapterLog("tapItemById(%s): no items found" % (viewItemId,))599 return False600 def tapText(self, text, partial=False, **tapKwArgs):601 """602 Find an item with given text from the latest view, and tap it.603 Parameters:604 partial (boolean, optional):605 refer to verifyText documentation. The default is606 False.607 tapPos (pair of floats (x, y)):608 refer to tapItem documentation.609 long, hold, count, delayBetweenTaps (optional):610 refer to tap documentation.611 Returns True if successful, otherwise False.612 """613 assert self._lastView != None, "View required."614 items = self._lastView.findItemsByText(text, partial=partial, count=1)615 if len(items) == 0: return False616 return self.tapItem(items[0], **tapKwArgs)617 def topApp(self):618 """619 Returns the name of the top application.620 """621 return self._conn.recvTopAppWindow()[0]622 def topWindow(self):623 """624 Returns the name of the top window.625 """626 # the top window may be None during transitions, therefore627 # retry a couple of times if necessary.628 timeout = 0.5629 pollDelay = 0.2630 start = time.time()631 tw = self._conn.recvTopAppWindow()[1]632 while tw == None and (time.time() - start < timeout):633 time.sleep(pollDelay)634 tw = self._conn.recvTopAppWindow()[1]635 return tw636 def verifyText(self, text, partial=False):637 """638 Verify that the last view has at least one item with given639 text.640 Parameters:641 text (string):642 text to be searched for in items.643 partial (boolean, optional):644 if True, match items if item text contains given645 text, otherwise match only if item text is equal to646 the given text. The default is False (exact match).647 """648 assert self._lastView != None, "View required."649 return self._lastView.findItemsByText(text, partial=partial, count=1) != []650 def view(self):651 """652 Returns the last view (the most recently refreshed view).653 """654 return self._lastView655 def waitText(self, text, partial=False, **waitKwArgs):656 """657 Wait until text appears in any view item.658 Parameters:659 text (string):660 text to be waited for.661 partial (boolean, optional):662 refer to verifyText. The default is False.663 waitTime, pollDelay (float, optional):664 refer to wait.665 Returns True if text appeared within given time limit,666 otherwise False.667 Updates the last view.668 """669 return self.wait(self.refreshView,670 self.verifyText, (text,), {'partial': partial},671 **waitKwArgs)672 def wake(self):673 """674 Force the device to wake up.675 """676 return self._conn.sendWake()677 def _loadDeviceAndTestINIs(self, homeDir, deviceName, iniFile):678 if deviceName != None:679 _deviceIniFilename = homeDir + os.sep + "etc" + os.sep + deviceName + ".ini"680 self.loadConfig(_deviceIniFilename, override=True, level="device")681 if iniFile:682 self.loadConfig(iniFile, override=True, level="test")683class Ini:684 """685 Container for device configuration loaded from INI files.686 INI file syntax:687 [section1]688 key1 = value1689 ; commented = out690 # commented = out691 """692 def __init__(self, iniFile=None):693 """694 Initialise the container, optionally with an initial configuration.695 Parameters:696 iniFile (file object, optional):697 load the initial configuration from iniFile.698 The default is None: start with empty configuration.699 """700 # _conf is a dictionary:701 # (section, key) -> value702 self._conf = {}703 if iniFile:704 self.addFile(iniFile)705 def addFile(self, iniFile, override=True):706 """707 Add values from a file to the current configuration.708 Parameters:709 iniFile (file object):710 load values from this file object.711 override (boolean, optional):712 If True, loaded values override existing values.713 Otherwise, only currently undefined values are714 loaded. The default is True.715 """716 for line in iniFile:717 line = line.strip()718 if line.startswith('[') and line.endswith(']'):719 section = line[1:-1].strip()720 elif line.startswith(";") or line.startswith("#"):721 continue722 elif '=' in line:723 key, value = line.split('=', 1)724 if override or (section, key.strip()) not in self._conf:725 self._conf[(section, key.strip())] = value.strip()726 def sections(self):727 """728 Returns list of sections in the current configuration.729 """730 return list(set([k[0] for k in self._conf.keys()]))731 def keys(self, section):732 """733 Returns list of keys in a section in the current configuration.734 Parameters:735 section (string):736 the name of the section.737 """738 return [k[1] for k in self._conf.keys() if k[0] == section]739 def dump(self):740 """741 Returns the current configuration as a single string in the742 INI format.743 """744 lines = []745 for section in sorted(self.sections()):746 lines.append("[%s]" % (section,))747 for key in sorted(self.keys(section)):748 lines.append("%-16s = %s" % (key, self._conf[(section, key)]))749 lines.append("")750 return "\n".join(lines)751 def set(self, section, key, value):752 """753 Set new value for a key in a section.754 Parameters:755 section, key (strings):756 the section, the key.757 value (string):758 the new value. If not string already, it will be759 converted to string, and it will be loaded as a760 string when loaded from file object.761 """762 self._conf[(section, key)] = str(value)763 def value(self, section, key, default=""):764 """765 Returns the value (string) associated with a key in a section.766 Parameters:767 section, key (strings):768 the section and the key.769 default (string, optional):770 the default value to be used and stored if there is771 no value associated to the key in the section. The772 default is the empty string.773 Reading a value of an undefined key in an undefined section774 adds the key and the section to the configuration with the775 returned (the default) value. This makes all returned values776 visible in dump().777 """778 if not (section, key) in self._conf:779 self._conf[(section, key)] = default780 return self._conf[(section, key)]781# For backward compatibility, someone might be using old _DeviceConf782_DeviceConf = Ini783class ViewItem(fmbtgti.GUIItem):784 """785 ViewItem holds the information of a single GUI element.786 """787 def __init__(self, className, code, indent, properties, parent, rawProps, dumpFilename, displayToScreen):788 self._p = properties789 self._parent = parent790 self._className = className791 self._code = code792 self._indent = indent793 self._children = []794 self._rawProps = ""795 if not "scrolling:mScrollX" in self._p:796 self._p["scrolling:mScrollX"] = 0797 self._p["scrolling:mScrollY"] = 0798 fmbtgti.GUIItem.__init__(self, className, self._calculateBbox(displayToScreen), dumpFilename)799 def addChild(self, child): self._children.append(child)800 def _calculateBbox(self, displayToScreen):801 left = int(self._p["layout:mLeft"])802 top = int(self._p["layout:mTop"])803 parent = self._parent804 while parent:805 pp = parent._p806 left += int(pp["layout:mLeft"]) - int(pp["scrolling:mScrollX"])807 top += int(pp["layout:mTop"]) - int(pp["scrolling:mScrollY"])808 parent = parent._parent809 height = int(self._p["layout:getHeight()"])810 width = int(self._p["layout:getWidth()"])811 screenLeft, screenTop = displayToScreen(left, top)812 screenRight, screenBottom = displayToScreen(left + width, top + height)813 return (screenLeft, screenTop, screenRight, screenBottom)814 def children(self): return self._children815 def className(self): return self._className816 def code(self): return self._code817 def indent(self): return self._indent818 def id(self): return self.property("mID")819 def parent(self): return self._parent820 def properties(self): return self._p821 def property(self, propertyName):822 return self._p.get(propertyName, None)823 def text(self): return self.property("text:mText")824 def visible(self):825 return self._p.get("getVisibility()", "") == "VISIBLE"826 def dump(self):827 p = self._p828 return ("ViewItem(\n\tchildren = %d\n\tclassName = '%s'\n\tcode = '%s'\n\t" +829 "indent = %d\n\tproperties = {\n\t\t%s\n\t})") % (830 len(self._children), self._className, self._code, self._indent,831 '\n\t\t'.join(['"%s": %s' % (key, p[key]) for key in sorted(p.keys())]))832 def __str__(self):833 return ("ViewItem(className='%s', id=%s, bbox=%s)" % (834 self._className, self.id(), self.bbox()))835class View(object):836 """837 View provides interface to screen dumps from Android. It parses838 the dump to a hierarchy of ViewItems. find* methods enable searching839 for ViewItems based on their properties.840 """841 def __init__(self, screenshotDir, serialNumber, dump, displayToScreen=None):842 self.screenshotDir = screenshotDir843 self.serialNumber = serialNumber844 self._viewItems = []845 self._errors = []846 self._lineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>[0-9A-Fa-f]{8} )(?P<properties>.*)")847 self._olderAndroidLineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>\w)(?P<properties>.*)")848 self._propRegEx = re.compile("(?P<prop>(?P<name>[^=]+)=(?P<len>\d+),)(?P<data>[^\s]* ?)")849 self._dump = dump850 self._rawDumpFilename = self.screenshotDir + os.sep + fmbtgti._filenameTimestamp() + "-" + self.serialNumber + ".view"851 file(self._rawDumpFilename, "w").write(self._dump)852 if displayToScreen == None:853 displayToScreen = lambda x, y: (x, y)854 try: self._parseDump(dump, self._rawDumpFilename, displayToScreen)855 except Exception, e:856 self._errors.append((-1, "", "Parser error"))857 def viewItems(self): return self._viewItems858 def errors(self): return self._errors859 def dumpRaw(self): return self._dump860 def dumpItems(self, itemList = None):861 if itemList == None: itemList = self._viewItems862 l = []863 for i in itemList:864 l.append(self._dumpItem(i))865 return '\n'.join(l)866 def dumpTree(self, rootItem = None):867 l = []868 if rootItem != None:869 l.extend(self._dumpSubTree(rootItem, 0))870 else:871 for i in self._viewItems:872 if i._indent == 0:873 l.extend(self._dumpSubTree(i, 0))874 return '\n'.join(l)875 def _dumpSubTree(self, viewItem, indent):876 l = []877 i = viewItem878 l.append(" "*indent + self._dumpItem(viewItem))879 for i in viewItem.children():880 l.extend(self._dumpSubTree(i, indent + 4))881 return l882 def _dumpItem(self, viewItem):883 i = viewItem884 if i.text() != None: t = '"%s"' % (i.text(),)885 else: t = None886 return "id=%s cls=%s text=%s bbox=%s" % (887 i.id(), i.className(), t, i.bbox())888 def findItems(self, comparator, count=-1, searchRootItem=None, searchItems=None):889 foundItems = []890 if count == 0: return foundItems891 if searchRootItem != None:892 # find from searchRootItem and its children893 if comparator(searchRootItem):894 foundItems.append(searchRootItem)895 for c in searchRootItem.children():896 foundItems.extend(self.findItems(comparator, count=count-len(foundItems), searchRootItem=c))897 else:898 if searchItems != None:899 # find from listed items only900 searchDomain = searchItems901 else:902 # find from all items903 searchDomain = self._viewItems904 for i in searchDomain:905 if comparator(i):906 foundItems.append(i)907 if count > 0 and len(foundItems) >= count:908 break909 return foundItems910 def findItemsByText(self, text, partial=False, count=-1, searchRootItem=None, searchItems=None):911 """912 Searches the GUI hiearhy for a object with a given text913 """914 if partial:915 c = lambda item: (916 item.properties().get("text:mText", "").find(text) != -1 )917 else:918 c = lambda item: (919 item.properties().get("text:mText", None) == text )920 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems)921 def findItemsById(self, id, count=-1, searchRootItem=None, searchItems=None):922 c = lambda item: item.properties().get("mID", "") == id923 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems)924 def findItemsByClass(self, className, partial=True, count=-1, searchRootItem=None, searchItems=None):925 if partial: c = lambda item: item.className().find(className) != -1926 else: c = lambda item: item.className() == className927 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems)928 def findItemsByIdAndClass(self, id, className, partial=True, count=-1, searchRootItem=None, searchItems=None):929 idOk = self.findItemsById(id, count=-1, searchRootItem=searchRootItem)930 return self.findItemsByClass(className, partial=partial, count=count, searchItems=idOk)931 def findItemsByRawProps(self, s, count=-1, searchRootItem=None, searchItems=None):932 c = lambda item: item._rawProps.find(s) != -1933 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems)934 def save(self, fileOrDirName):935 shutil.copy(self._rawDumpFilename, fileOrDirName)936 def _parseDump(self, dump, rawDumpFilename, displayToScreen):937 """938 Process the raw dump data and create a tree of ViewItems939 """940 # This code originates from tema-android-adapter-3.2,941 # AndroidAdapter/guireader.py.942 self._viewItems = []943 cellLayout = ""944 parent = None945 previousItem = None946 currentIndent = 0947 visible = True948 self.TOP_PAGED_VIEW = ""949 for lineIndex, line in enumerate(dump.splitlines()):950 if line == "DONE.":951 break952 # separate indent, class and properties for each GUI object953 # TODO: branch here according to self._androidVersion954 matcher = self._lineRegEx.match(line)955 if not matcher:956 # FIXME: this hack falls back to old format,957 # should branch according to self._androidVersion!958 matcher = self._olderAndroidLineRegEx.match(line)959 if not matcher:960 self._errors.append((lineIndex + 1, line, "Illegal line"))961 continue # skip this line962 className = matcher.group("class")963 # Indent specifies the hierarchy level of the object964 indent = len(matcher.group("indent"))965 # If the indent is bigger that previous, this object is a966 # child for the previous object967 if indent > currentIndent:968 parent = self._viewItems[-1]969 elif indent < currentIndent:970 for tmp in range(0, currentIndent - indent):971 parent = parent.parent()972 currentIndent = indent973 propertiesData = matcher.group("properties")974 properties = {}975 index = 0976 x = 0977 y = 0978 # Process the properties of each GUI object979 while index < len(propertiesData):980 # Separate name and value for each property [^=]*=981 propMatch = self._propRegEx.match(propertiesData[index:-1])982 if not propMatch or len(propMatch.group("data")) < int(propMatch.group("len")):983 if not propMatch.group("data"):984 self._errors.append((lineIndex, propertiesData[index:-1], "Illegal property"))985 return None986 startFrom = index + propertiesData[index:-1].find(propMatch.group("data"))987 currFixedData = propertiesData[startFrom:(startFrom + int(propMatch.group("len")))]988 length = int(propMatch.group("len"))989 # [^=]+=?, == data990 properties[propMatch.group("name")] = currFixedData[0:length].lstrip()991 else:992 length = int(propMatch.group("len"))993 # [^=]+=?, == data994 properties[propMatch.group("name")] = propMatch.group("data")[0:length].lstrip()995 index += len(propMatch.group("prop")) + length + 1996 self._viewItems.append(ViewItem(matcher.group("class"), matcher.group("id"), indent, properties, parent, matcher.group("properties"), self._rawDumpFilename, displayToScreen))997 if parent:998 parent.addChild(self._viewItems[-1])999 return self._viewItems1000 def __str__(self):1001 return 'View(items=%s, dump="%s")' % (1002 len(self._viewItems), self._rawDumpFilename)1003class _AndroidDeviceConnection:1004 """1005 Connection to the Android Device being tested.1006 """1007 _m_host = 'localhost'1008 _m_port = random.randint(20000, 29999)1009 _w_host = 'localhost'1010 _w_port = _m_port + 11011 def __init__(self, serialNumber, stopOnError=True):1012 self._serialNumber = serialNumber1013 self._stopOnError = stopOnError1014 self._shellSupportsTar = False1015 self.setScreenToDisplayCoords(lambda x, y: (x, y))1016 self.setDisplayToScreenCoords(lambda x, y: (x, y))1017 self._detectFeatures()1018 try:1019 self._resetMonkey()1020 self._resetWindow()1021 finally:1022 # Next _AndroidDeviceConnection instance will use different ports1023 self._w_port = _AndroidDeviceConnection._w_port1024 self._m_port = _AndroidDeviceConnection._m_port1025 _AndroidDeviceConnection._w_port += 1001026 _AndroidDeviceConnection._m_port += 1001027 def __del__(self):1028 try: self._monkeySocket.close()1029 except: pass1030 def target(self):1031 return self._serialNumber1032 def _cat(self, remoteFilename):1033 fd, filename = tempfile.mkstemp("fmbtandroid-cat-")1034 os.close(fd)1035 self._runAdb(["pull", remoteFilename, filename], 0)1036 contents = file(filename).read()1037 os.remove(filename)1038 return contents1039 def _runAdb(self, command, expectedExitStatus=0, timeout=None):1040 if not self._stopOnError:1041 expect = None1042 else:1043 expect = expectedExitStatus1044 if type(command) == list:1045 command = ["adb", "-s", self._serialNumber] + command1046 else:1047 command = ["adb", "-s", self._serialNumber, command]1048 return _run(command, expectedExitStatus=expect, timeout=timeout)1049 def _runSetupCmd(self, cmd, expectedExitStatus = 0):1050 _adapterLog('setting up connections: "%s"' % (cmd,))1051 try:1052 self._runAdb(cmd, expectedExitStatus)1053 except (FMBTAndroidRunError, AndroidDeviceNotFound), e:1054 _adapterLog("connection setup problem: %s" % (e,))1055 return False1056 return True1057 def _detectFeatures(self):1058 # check supported features1059 outputLines = self._runAdb(["shell", "id"])[1].splitlines()1060 if len(outputLines) == 1 and "uid=0" in outputLines[0]:1061 self._shellUid0 = True1062 else:1063 self._shellUid0 = False1064 outputLines = self._runAdb(["shell", "su", "root", "id"])[1].splitlines()1065 if len(outputLines) == 1 and "uid=0" in outputLines[0]:1066 self._shellSupportsSu = True1067 else:1068 self._shellSupportsSu = False1069 outputLines = self._runAdb(["shell", "tar"])[1].splitlines()1070 if len(outputLines) == 1 and "bin" in outputLines[0]:1071 self._shellSupportsTar = False1072 else:1073 self._shellSupportsTar = True1074 def _resetWindow(self):1075 setupCommands = [["shell", "service" , "call", "window", "1", "i32", "4939"],1076 ["forward", "tcp:"+str(self._w_port), "tcp:4939"]]1077 for c in setupCommands:1078 self._runSetupCmd(c)1079 def _resetMonkey(self, timeout=3, pollDelay=.25):1080 tryKillingMonkeyOnFailure = 11081 failureCountSinceKill = 01082 endTime = time.time() + timeout1083 if self._shellUid0:1084 monkeyLaunch = ["monkey"]1085 elif self._shellSupportsSu:1086 monkeyLaunch = ["su", "root", "monkey"]1087 else:1088 monkeyLaunch = ["monkey"]1089 while time.time() < endTime:1090 if not self._runSetupCmd(["shell"] + monkeyLaunch + ["--port", "1080"], None):1091 time.sleep(pollDelay)1092 failureCountSinceKill += 11093 continue1094 time.sleep(pollDelay)1095 if not self._runSetupCmd(["forward", "tcp:"+str(self._m_port), "tcp:1080"]):1096 time.sleep(pollDelay)1097 failureCountSinceKill += 11098 continue1099 try:1100 self._monkeySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)1101 self._monkeySocket.connect((self._m_host, self._m_port))1102 self._monkeySocket.setblocking(0)1103 self._monkeySocket.settimeout(1.0)1104 self._platformVersion = self._monkeyCommand("getvar build.version.release", retry=0)[1]1105 if len(self._platformVersion) > 0:1106 self._monkeySocket.settimeout(5.0)1107 return True1108 except Exception, e:1109 failureCountSinceKill += 11110 time.sleep(pollDelay)1111 if failureCountSinceKill > 2 and tryKillingMonkeyOnFailure > 0:1112 if self._shellSupportsSu:1113 self._runSetupCmd(["shell", "su", "root", "pkill", "monkey"])1114 else:1115 self._runSetupCmd(["shell", "pkill", "monkey"])1116 tryKillingMonkeyOnFailure -= 11117 failureCountSinceKill = 01118 time.sleep(pollDelay)1119 if self._stopOnError:1120 msg = 'Android monkey error: cannot connect to "adb shell monkey --port 1080" to device %s' % (self._serialNumber)1121 _adapterLog(msg)1122 raise AndroidConnectionError(msg)1123 else:1124 return False1125 def _monkeyCommand(self, command, retry=3):1126 try:1127 self._monkeySocket.sendall(command + "\n")1128 data = self._monkeySocket.recv(4096).strip()1129 if len(data) == 0 and retry > 0:1130 return self._monkeyCommand(command, retry-1)1131 if data == "OK":1132 return True, None1133 elif data.startswith("OK:"):1134 return True, data.split("OK:")[1]1135 _adapterLog("monkeyCommand failing... command: '%s' response: '%s'" % (command, data))1136 return False, None1137 except socket.error:1138 try: self._monkeySocket.close()1139 except: pass1140 if retry > 0:1141 self._resetMonkey()1142 return self._monkeyCommand(command, retry=retry-1)1143 else:1144 raise AndroidConnectionError('Android monkey socket connection lost while sending command "%s"' % (command,))1145 def reboot(self, reconnect, firstBootAfterFlashing, timeout):1146 if firstBootAfterFlashing:1147 self._runAdb("root")1148 time.sleep(2)1149 self._runAdb(["shell", "rm", "/data/data/com.android.launcher/shared_prefs/com.android.launcher2.prefs.xml"])1150 self._runAdb("reboot")1151 _adapterLog("rebooting " + self._serialNumber)1152 if reconnect:1153 time.sleep(2)1154 endTime = time.time() + timeout1155 status, _, _ = self._runAdb("wait-for-device", expectedExitStatus=None, timeout=timeout)1156 if status != 0:1157 raise AndroidDeviceNotFound('"timeout %s adb wait-for-device" status %s' % (timeout, status))1158 self._detectFeatures()1159 while time.time() < endTime:1160 try:1161 if self._resetMonkey(timeout=1, pollDelay=1):1162 break1163 except AndroidConnectionError:1164 pass1165 time.sleep(1)1166 else:1167 msg = "reboot: reconnecting to " + self._serialNumber + " failed"1168 _adapterLog(msg)1169 raise AndroidConnectionError(msg)1170 self._resetWindow()1171 return True1172 def recvVariable(self, variableName):1173 ok, value = self._monkeyCommand("getvar " + variableName)1174 if ok: return value1175 else:1176 # LOG: getvar variableName failed1177 return None1178 def recvScreenSize(self):1179 try:1180 height = int(self.recvVariable("display.height"))1181 width = int(self.recvVariable("display.width"))1182 except TypeError:1183 return None, None1184 return width, height1185 def recvTopAppWindow(self):1186 _, output, _ = self._runAdb(["shell", "dumpsys", "window"], 0)1187 if self._platformVersion >= "4.2":1188 s = re.findall("mCurrentFocus=Window\{(#?[0-9A-Fa-f]{8})( [^ ]*)? (?P<winName>[^}]*)\}", output)1189 else:1190 s = re.findall("mCurrentFocus=Window\{(#?[0-9A-Fa-f]{8}) (?P<winName>[^ ]*) [^ ]*\}", output)1191 if s and len(s[-1][-1].strip()) > 1:1192 topWindowName = s[-1][-1]1193 if len(s) > 0:1194 _adapterLog('recvTopAppWindow warning: several mCurrentFocus windows: "%s"'1195 % ('", "'.join([w[-1] for w in s]),))1196 else: topWindowName = None1197 s = re.findall("mFocusedApp=AppWindowToken.*ActivityRecord\{#?[0-9A-Fa-f]{8}( [^ ]*)? (?P<appName>[^}]*)\}", output)1198 if s and len(s[0][-1].strip()) > 1:1199 topAppName = s[0][-1].strip()1200 else:1201 topAppName = None1202 return topAppName, topWindowName1203 def sendTap(self, xCoord, yCoord):1204 xCoord, yCoord = self._screenToDisplay(xCoord, yCoord)1205 return self._monkeyCommand("tap " + str(xCoord) + " " + str(yCoord))[0]1206 def sendKeyUp(self, key):1207 return self._monkeyCommand("key up " + key)[0]1208 def sendKeyDown(self, key):1209 return self._monkeyCommand("key down " + key)[0]1210 def sendTouchUp(self, xCoord, yCoord):1211 xCoord, yCoord = self._screenToDisplay(xCoord, yCoord)1212 return self._monkeyCommand("touch up " + str(xCoord) + " " + str(yCoord))[0]1213 def sendTouchDown(self, xCoord, yCoord):1214 xCoord, yCoord = self._screenToDisplay(xCoord, yCoord)1215 return self._monkeyCommand("touch down " + str(xCoord) + " " + str(yCoord))[0]1216 def sendTouchMove(self, xCoord, yCoord):1217 xCoord, yCoord = self._screenToDisplay(xCoord, yCoord)1218 return self._monkeyCommand("touch move " + str(xCoord) + " " + str(yCoord))[0]1219 def sendTrackBallMove(self, dx, dy):1220 dx, dy = self._screenToDisplay(dx, dy)1221 return self._monkeyCommand("trackball " + str(dx) + " " + str(dy))[0]1222 def sendPress(self, key):1223 return self._monkeyCommand("press " + key)[0]1224 def sendType(self, text):1225 for lineIndex, line in enumerate(text.split('\n')):1226 if lineIndex > 0: self.sendPress("KEYCODE_ENTER")1227 for wordIndex, word in enumerate(line.split(' ')):1228 if wordIndex > 0: self.sendPress("KEYCODE_SPACE")1229 if len(word) > 0 and not self._monkeyCommand("type " + word)[0]:1230 _adapterLog('sendType("%s") failed when sending word "%s"' %1231 (text, word))1232 return False1233 return True1234 def sendWake(self):1235 return self._monkeyCommand("wake")[0]1236 def recvScreenshot(self, filename, retry=2, retryDelay=1.0):1237 """1238 Capture a screenshot and copy the image file to given path or1239 system temp folder.1240 Returns True on success, otherwise False.1241 """1242 remotefile = '/sdcard/' + os.path.basename(filename)1243 self._runAdb(['shell', 'screencap', '-p', remotefile], 0)1244 status, out, err = self._runAdb(['pull', remotefile, filename], [0, 1])1245 if status != 0:1246 raise FMBTAndroidError("Failed to fetch screenshot from the device: %s. SD card required." % ((out + err).strip(),))1247 status, _, _ = self._runAdb(['shell', 'rm', remotefile], 0)1248 if os.path.getsize(filename) == 0:1249 _adapterLog("received screenshot of size 0")1250 if retry > 0:1251 time.sleep(retryDelay)1252 return self.recvScreenshot(filename, retry-1, retryDelay)1253 else:1254 raise FMBTAndroidError("Screenshot file size 0")1255 return True1256 def setScreenToDisplayCoords(self, screenToDisplayFunction):1257 self._screenToDisplay = screenToDisplayFunction1258 def setDisplayToScreenCoords(self, displayToScreenFunction):1259 self._displayToScreen = displayToScreenFunction1260 def shellSOE(self, shellCommand):1261 fd, filename = tempfile.mkstemp(prefix="fmbtandroid-shellcmd-")1262 remotename = '/sdcard/' + os.path.basename(filename)1263 os.write(fd, shellCommand + "\n")1264 os.close(fd)1265 self._runAdb(["push", filename, remotename], 0)1266 cmd = "source %s >%s.out 2>%s.err; echo $? > %s.status" % ((remotename,)*4)1267 if self._shellSupportsTar:1268 # do everything we can in one command to minimise adb1269 # commands: execute command, record results, package,1270 # print uuencoded package and remove remote temp files1271 cmd += "; cd %s; tar czf - %s.out %s.err %s.status | uuencode %s.tar.gz; rm -f %s*" % (1272 (os.path.dirname(remotename),) + ((os.path.basename(remotename),) * 5))...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run fMBT automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful