Best Python code snippet using fMBT_python
fmbtwindows.py
Source:fmbtwindows.py  
...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...fmbtandroid.py
Source:fmbtandroid.py  
...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))...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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
