How to use sendUserRotation method in fMBT

Best Python code snippet using fMBT_python

fmbtandroid.py

Source:fmbtandroid.py Github

copy

Full Screen

...1044 rotation = ROTATION_DEGS.index(rotation)1045 else:1046 raise ValueError('invalid rotation "%s"' % (rotation,))1047 if self._conn:1048 return self._conn.sendUserRotation(rotation)1049 else:1050 return False1051 def shell(self, shellCommand, timeout=None):1052 """1053 Execute shellCommand in adb shell.1054 Parameters:1055 shellCommand (string):1056 command to be executed in adb shell.1057 Arguments separated by whitespace.1058 timeout (optional, integer):1059 time in seconds after which the command1060 will timeout. The default is None (no timeout).1061 Returns output of "adb shell" command, or None if timed out.1062 If you wish to receive exitstatus or standard output and error1063 separated from shellCommand, refer to shellSOE().1064 """1065 try:1066 output = self.existingConnection()._runAdb(1067 ["shell", shellCommand],1068 expectedExitStatus=EXITSTATUS_ANY,1069 timeout=timeout)[1]1070 except FMBTAndroidRunError:1071 output = None1072 return output1073 def shellSOE(self, shellCommand, timeout=None):1074 """1075 Execute shellCommand in adb shell.1076 Parameters:1077 shellCommand (string):1078 command to be executed in adb shell.1079 Arguments separated by whitespace.1080 timeout (optional, integer):1081 time in seconds after which the command1082 will timeout. The default is None (no timeout).1083 Returns tuple (exitStatus, standardOutput, standardError)1084 or (None, None, None) if timed out.1085 Requires tar and uuencode to be available on the device.1086 """1087 return self.existingConnection().shellSOE(shellCommand, timeout)1088 def smsNumber(self, number, message):1089 """1090 Send message using SMS to given number.1091 Parameters:1092 number (string)1093 phone number to which the SMS will be sent1094 message (string)1095 the message to be sent.1096 Returns True on success, otherwise False.1097 """1098 smsCommand = ('am start -a android.intent.action.SENDTO ' +1099 '-d sms:%s --es sms_body "%s"' +1100 ' --ez exit_on_sent true') % (number, message)1101 status, out, err = self.shellSOE(smsCommand)1102 if status != 0:1103 _logFailedCommand("sms", smsCommand, status, out, err)1104 return False1105 _adapterLog("SMS command returned %s" % (out + err,))1106 time.sleep(2)1107 if 'talk' in self.topWindow():1108 _adapterLog("Messaging app is Hangouts")1109 self.pressKey("KEYCODE_ENTER")1110 time.sleep(1)1111 self.pressKey("KEYCODE_BACK")1112 time.sleep(1)1113 self.pressKey("KEYCODE_BACK")1114 else:1115 self.pressKey("KEYCODE_DPAD_RIGHT")1116 time.sleep(1)1117 self.pressKey("KEYCODE_ENTER")1118 return True1119 def statusBarVisible(self):1120 """1121 Returns True if the status bar is showing, otherwise False.1122 """1123 return self.existingConnection().recvStatusBarVisible()1124 def supportsView(self):1125 """1126 Check if connected device supports reading view data.1127 View data is needed by refreshView(), view(), verifyText() and1128 waitText(). It is produced by Android window dump.1129 Returns True if view data can be read, otherwise False.1130 """1131 if self._supportsView == None:1132 try:1133 if self.uiautomatorDump():1134 if self.existingConnection().recvUiautomatorDump():1135 self._supportsView = True1136 else:1137 self._supportsView = False1138 else:1139 self.existingConnection().recvViewData()1140 self._supportsView = True1141 except AndroidConnectionError:1142 self._supportsView = False1143 return self._supportsView1144 def swipeText(self, text, direction, partial=False, **swipeKwArgs):1145 """1146 Find an item with given text from the latest view, and swipe it.1147 Parameters:1148 text (string):1149 text to be swiped.1150 direction (string or integer):1151 refer to swipe documentation1152 distance (float, optional):1153 refer to swipe documentation1154 partial (boolean, optional):1155 refer to verifyText documentation. The default is1156 False.1157 startPos1158 refer to swipeItem documentation.1159 delayBeforeMoves, delayBetweenMoves, delayAfterMoves,1160 movePoints1161 refer to drag documentation.1162 Returns True if successful, otherwise False.1163 """1164 assert self._lastView != None, "View required."1165 items = self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True)1166 if len(items) == 0: return False1167 return self.swipeItem(items[0], direction, **swipeKwArgs)1168 def systemProperty(self, propertyName):1169 """1170 Returns Android Monkey Device properties, such as1171 "clock.uptime", refer to Android Monkey documentation.1172 """1173 return self.existingConnection().recvVariable(propertyName)1174 def tapId(self, viewItemId, **tapKwArgs):1175 """1176 Find an item with given id from the latest view, and tap it.1177 """1178 assert self._lastView != None, "View required."1179 items = self._lastView.findItemsById(viewItemId, count=1, onScreen=True)1180 if len(items) > 0:1181 return self.tapItem(items[0], **tapKwArgs)1182 else:1183 _adapterLog("tapItemById(%s): no items found" % (viewItemId,))1184 return False1185 def tapText(self, text, partial=False, **tapKwArgs):1186 """1187 Find an item with given text from the latest view, and tap it.1188 Parameters:1189 partial (boolean, optional):1190 refer to verifyText documentation. The default is1191 False.1192 tapPos (pair of floats (x, y), optional):1193 refer to tapItem documentation.1194 long, hold, count, delayBetweenTaps (optional):1195 refer to tap documentation.1196 Returns True if successful, otherwise False.1197 """1198 assert self._lastView != None, "View required."1199 items = self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True)1200 if len(items) == 0: return False1201 return self.tapItem(items[0], **tapKwArgs)1202 def tapContentDesc(self, contentDesc, **tapKwArgs):1203 """1204 Find an item with given content description, and tap it.1205 Parameters:1206 contentDesc (string):1207 content description of the item to be tapped.1208 tapPos (pair of floats (x, y), optional):1209 refer to tapItem documentation.1210 long, hold, count, delayBetweenTaps (optional):1211 refer to tap documentation.1212 Returns True if successful, otherwise False.1213 Note: Requires that the latest refreshView used the uiautomator1214 backend for fetching the view data. Example:1215 d.refreshView(uiautomatorDump=True)1216 d.tapContentDesc("Apps")1217 """1218 assert self._lastView != None, "View required."1219 items = self._lastView.findItemsByContentDesc(contentDesc)1220 if len(items) == 0: return False1221 return self.tapItem(items[0], **tapKwArgs)1222 def topApp(self):1223 """1224 Returns the name of the top application.1225 """1226 if not self._conn:1227 return None1228 else:1229 return self._conn.recvTopAppWindow()[0]1230 def topWindow(self):1231 """1232 Returns the name of the top window.1233 """1234 # the top window may be None during transitions, therefore1235 # retry a couple of times if necessary.1236 if not self._conn:1237 return None1238 timeout = 0.51239 pollDelay = 0.21240 start = time.time()1241 tw = self.existingConnection().recvTopAppWindow()[1]1242 while tw == None and (time.time() - start < timeout):1243 time.sleep(pollDelay)1244 tw = self.existingConnection().recvTopAppWindow()[1]1245 return tw1246 def topWindowStack(self):1247 """1248 Returns window names in the stack of the top fullscreen application.1249 The topmost window is the last one in the list.1250 """1251 return self.existingConnection().recvTopWindowStack()1252 def uiautomatorDump(self):1253 """1254 Returns whether or not uiautomator is used for refreshView()1255 """1256 return self._uiautomatorDump1257 def uninstall(self, apkname, keepData=False):1258 """1259 Uninstall a package from the device.1260 Parameters:1261 package (string):1262 the package to be uninstalled.1263 keepData (boolean, optional):1264 keep app data and cache.1265 Corresponds to adb uninstall "-k".1266 The default is False.1267 Returns True on success, otherwise False.1268 Example:1269 d.uninstall("com.android.python27")1270 """1271 if self._conn:1272 return self._conn.uninstall(apkname, keepData)1273 else:1274 return False1275 def userRotation(self):1276 """1277 Returns rotation set with setUserRotation.1278 """1279 return self.existingConnection().recvUserRotation()1280 def verifyText(self, text, partial=False):1281 """1282 Verify that the last view has at least one item with given1283 text.1284 Parameters:1285 text (string):1286 text to be searched for in items.1287 partial (boolean, optional):1288 if True, match items if item text contains given1289 text, otherwise match only if item text is equal to1290 the given text. The default is False (exact match).1291 """1292 assert self._lastView != None, "View required."1293 return self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True) != []1294 def view(self):1295 """1296 Returns the last view (the most recently refreshed view).1297 """1298 return self._lastView1299 def waitAnyText(self, listOfTexts, partial=False, uiautomatorDump=False, **waitKwArgs):1300 """1301 Wait until any of texts is on the screen.1302 Parameters:1303 listOfTexts (list of string):1304 texts to be waited for.1305 partial (boolean, optional):1306 refer to verifyText. The default is False.1307 uiautomatorDump (boolean, optional):1308 use uiautomator to read view dump from the device.1309 If not given, uiautomatorDump() default will be used.1310 waitTime, pollDelay, beforeRefresh, afterRefresh (optional):1311 refer to wait documentation.1312 Returns list of texts that appear in the first refreshed view1313 that contains at least one of the texts. If none of the texts1314 appear within the time limit, returns empty list.1315 If any of texts is not found from the latest refreshed1316 view, waitAnyText will update the view in pollDelay interval until1317 waitTime is exceeded.1318 """1319 if listOfTexts == []: return []1320 if not self._lastView: self.refreshView(uiautomatorDump=uiautomatorDump)1321 waitArgs, rest = fmbtgti._takeWaitArgs(waitKwArgs)1322 foundTexts = []1323 def observe():1324 for text in listOfTexts:1325 if self.verifyText(text, partial=partial):1326 foundTexts.append(text)1327 return foundTexts != []1328 self.wait(1329 lambda: self.refreshView(uiautomatorDump=uiautomatorDump),1330 observe, **waitArgs)1331 return foundTexts1332 def waitText(self, text, *waitAnyTextArgs, **waitAnyTextKwArgs):1333 """1334 Wait until text appears in any view item.1335 Parameters:1336 text (string):1337 text to be waited for.1338 partial (boolean, optional):1339 refer to verifyText. The default is False.1340 uiautomatorDump (boolean, optional):1341 use uiautomator to read view dump from the device.1342 If not given, uiautomatorDump() default will be used.1343 waitTime, pollDelay, beforeRefresh, afterRefresh (optional):1344 refer to wait documentation.1345 Returns True if text appeared within given time limit,1346 otherwise False.1347 Updates the last view if the text is not found in the latest view1348 and waitTime > 0.1349 """1350 return self.waitAnyText(1351 [text], *waitAnyTextArgs, **waitAnyTextKwArgs) != []1352 def wake(self):1353 """1354 Force the device to wake up.1355 """1356 return self.existingConnection().sendWake()1357 def _loadDeviceAndTestINIs(self, homeDir, deviceName, iniFile):1358 if deviceName != None:1359 _deviceIniFilename = homeDir + os.sep + "etc" + os.sep + deviceName + ".ini"1360 self.loadConfig(_deviceIniFilename, override=True, level="device")1361 if iniFile:1362 self.loadConfig(iniFile, override=True, level="test")1363class Ini:1364 """1365 Container for device configuration loaded from INI files.1366 INI file syntax:1367 [section1]1368 key1 = value11369 ; commented = out1370 # commented = out1371 """1372 def __init__(self, iniFile=None):1373 """1374 Initialise the container, optionally with an initial configuration.1375 Parameters:1376 iniFile (file object, optional):1377 load the initial configuration from iniFile.1378 The default is None: start with empty configuration.1379 """1380 # _conf is a dictionary:1381 # (section, key) -> value1382 self._conf = {}1383 if iniFile:1384 self.addFile(iniFile)1385 def addFile(self, iniFile, override=True):1386 """1387 Add values from a file to the current configuration.1388 Parameters:1389 iniFile (file object):1390 load values from this file object.1391 override (boolean, optional):1392 If True, loaded values override existing values.1393 Otherwise, only currently undefined values are1394 loaded. The default is True.1395 """1396 for line in iniFile:1397 line = line.strip()1398 if line.startswith('[') and line.endswith(']'):1399 section = line[1:-1].strip()1400 elif line.startswith(";") or line.startswith("#"):1401 continue1402 elif '=' in line:1403 key, value = line.split('=', 1)1404 if override or (section, key.strip()) not in self._conf:1405 self._conf[(section, key.strip())] = value.strip()1406 def sections(self):1407 """1408 Returns list of sections in the current configuration.1409 """1410 return list(set([k[0] for k in self._conf.keys()]))1411 def keys(self, section):1412 """1413 Returns list of keys in a section in the current configuration.1414 Parameters:1415 section (string):1416 the name of the section.1417 """1418 return [k[1] for k in self._conf.keys() if k[0] == section]1419 def dump(self):1420 """1421 Returns the current configuration as a single string in the1422 INI format.1423 """1424 lines = []1425 for section in sorted(self.sections()):1426 lines.append("[%s]" % (section,))1427 for key in sorted(self.keys(section)):1428 lines.append("%-16s = %s" % (key, self._conf[(section, key)]))1429 lines.append("")1430 return "\n".join(lines)1431 def set(self, section, key, value):1432 """1433 Set new value for a key in a section.1434 Parameters:1435 section, key (strings):1436 the section, the key.1437 value (string):1438 the new value. If not string already, it will be1439 converted to string, and it will be loaded as a1440 string when loaded from file object.1441 """1442 self._conf[(section, key)] = str(value)1443 def value(self, section, key, default=""):1444 """1445 Returns the value (string) associated with a key in a section.1446 Parameters:1447 section, key (strings):1448 the section and the key.1449 default (string, optional):1450 the default value to be used and stored if there is1451 no value associated to the key in the section. The1452 default is the empty string.1453 Reading a value of an undefined key in an undefined section1454 adds the key and the section to the configuration with the1455 returned (the default) value. This makes all returned values1456 visible in dump().1457 """1458 if not (section, key) in self._conf:1459 self._conf[(section, key)] = default1460 return self._conf[(section, key)]1461# For backward compatibility, someone might be using old _DeviceConf1462_DeviceConf = Ini1463class ViewItem(fmbtgti.GUIItem):1464 """1465 ViewItem holds the information of a single GUI element.1466 """1467 _boundsRegEx = re.compile(r'\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]')1468 def __init__(self, className, code, indent, properties, parent, rawProps, dumpFilename, displayToScreen):1469 self._p = properties1470 self._parent = parent1471 self._className = className1472 self._code = code1473 self._indent = indent1474 self._children = []1475 self._parentsVisible = True1476 if "resource-id" in self._p:1477 self._id = self._p["resource-id"].split(":", 1)[-1]1478 else:1479 self._id = self.property("mID")1480 self._rawProps = ""1481 if not "bounds" in self._p:1482 if not "scrolling:mScrollX" in self._p:1483 self._p["scrolling:mScrollX"] = 01484 self._p["scrolling:mScrollY"] = 01485 self._visible = self._p.get("getVisibility()", "") == "VISIBLE"1486 if "text:mText" in self._p:1487 self._text = self._p["text:mText"]1488 else:1489 self._text = None1490 else:1491 self._visible = True1492 self._text = self._p["text"]1493 fmbtgti.GUIItem.__init__(self, className, self._calculateBbox(displayToScreen), dumpFilename)1494 def addChild(self, child):1495 child._parentsVisible = self.visibleBranch()1496 self._children.append(child)1497 def _calculateBbox(self, displayToScreen):1498 if "bounds" in self._p:1499 try:1500 left, top, right, bottom = [1501 int(v) for v in1502 ViewItem._boundsRegEx.findall(self._p["bounds"])[0]]1503 except IndexError:1504 raise ValueError('invalid bounds "%s"' % (self._p["bounds"],))1505 width = right - left1506 height = bottom - top1507 elif "layout:getLocationOnScreen_x()" in self._p:1508 left = int(self._p["layout:getLocationOnScreen_x()"])1509 top = int(self._p["layout:getLocationOnScreen_y()"])1510 height = int(self._p["layout:getHeight()"])1511 width = int(self._p["layout:getWidth()"])1512 elif "layout:mLeft" in self._p:1513 left = int(self._p["layout:mLeft"])1514 top = int(self._p["layout:mTop"])1515 parent = self._parent1516 while parent:1517 pp = parent._p1518 left += int(pp["layout:mLeft"]) - int(pp["scrolling:mScrollX"])1519 top += int(pp["layout:mTop"]) - int(pp["scrolling:mScrollY"])1520 parent = parent._parent1521 height = int(self._p["layout:getHeight()"])1522 width = int(self._p["layout:getWidth()"])1523 else:1524 raise ValueError("bounding box not found, layout fields missing")1525 screenLeft, screenTop = displayToScreen(left, top)1526 screenRight, screenBottom = displayToScreen(left + width, top + height)1527 return (screenLeft, screenTop, screenRight, screenBottom)1528 def children(self): return self._children1529 def className(self): return self._className1530 def code(self): return self._code1531 def indent(self): return self._indent1532 def id(self): return self._id1533 def parent(self): return self._parent1534 def properties(self): return self._p1535 def property(self, propertyName):1536 return self._p.get(propertyName, None)1537 def visibleBranch(self):1538 """Returns True if this item and all items containing this are visible1539 up to the root node"""1540 return self._parentsVisible and self.visible()1541 def text(self):1542 return self._text1543 def content_desc(self):1544 if "content-desc" in self._p:1545 return self._p["content-desc"]1546 elif "accessibility:getContentDescription()" in self._p:1547 return self._p["accessibility:getContentDescription()"]1548 else:1549 return None1550 def visible(self):1551 return self._visible1552 def dump(self):1553 p = self._p1554 return ("ViewItem(\n\tchildren = %d\n\tclassName = '%s'\n\tcode = '%s'\n\t" +1555 "indent = %d\n\tproperties = {\n\t\t%s\n\t})") % (1556 len(self._children), self._className, self._code, self._indent,1557 '\n\t\t'.join(['"%s": %s' % (key, p[key]) for key in sorted(p.keys())]))1558 def dumpProperties(self):1559 rv = []1560 if self._p:1561 for key in [k for k in sorted(self._p.keys()) if not "layout:" in k and not "padding:" in k and not "drawing:" in k]: # sorted(self._p.keys()): # [k for k in sorted(self._p.keys()) if not ":" in k]:1562 rv.append("%s=%s" % (key, self._p[key]))1563 return "\n".join(rv)1564 def __str__(self):1565 if self.text():1566 text = ", text=%s" % (repr(self.text()),)1567 else:1568 text = ""1569 if "content-desc" in self._p and self._p["content-desc"]:1570 text += ", content_desc=%s" % (repr(self.content_desc(),))1571 return ("ViewItem(className=%s, id=%s, bbox=%s%s)" % (1572 repr(self._className), repr(self.id()), self.bbox(), text))1573class View(object):1574 """1575 View provides interface to screen dumps from Android. It parses1576 the dump to a hierarchy of ViewItems. find* methods enable searching1577 for ViewItems based on their properties.1578 """1579 def __init__(self, screenshotDir, serialNumber, dump, displayToScreen=None,1580 itemOnScreen=None, intCoords=None):1581 self.screenshotDir = screenshotDir1582 self.serialNumber = serialNumber1583 self._viewItems = []1584 self._errors = []1585 self._lineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>[0-9A-Fa-f]{4,8} )(?P<properties>.*)")1586 self._olderAndroidLineRegEx = re.compile("(?P<indent>\s*)(?P<class>[\w.$]+)@(?P<id>\w)(?P<properties>.*)")1587 self._propRegEx = re.compile("(?P<prop>(?P<name>[^=]+)=(?P<len>\d+),)(?P<data>[^\s]* ?)")1588 self._dump = dump1589 self._rawDumpFilename = self.screenshotDir + os.sep + fmbtgti._filenameTimestamp() + "-" + self.serialNumber + ".view"1590 file(self._rawDumpFilename, "w").write(self._dump)1591 if displayToScreen == None:1592 displayToScreen = lambda x, y: (x, y)1593 if itemOnScreen == None:1594 itemOnScreen = lambda item: True1595 self._itemOnScreen = itemOnScreen1596 if intCoords == None:1597 intCoords = lambda x, y: (int(x), int(y))1598 self._intCoords = intCoords1599 try:1600 if dump.startswith("<?xm"):1601 self._parseUIAutomatorDump(dump, self._rawDumpFilename, displayToScreen)1602 else:1603 self._parseDump(dump, self._rawDumpFilename, displayToScreen)1604 except Exception, e:1605 self._errors.append((-1, "", "Parser error"))1606 def viewItems(self): return self._viewItems1607 def errors(self): return self._errors1608 def dumpRaw(self): return self._dump1609 def dumpItems(self, itemList = None):1610 if itemList == None: itemList = self._viewItems1611 l = []1612 for i in itemList:1613 l.append(self._dumpItem(i))1614 return '\n'.join(l)1615 def dumpTree(self, rootItem = None):1616 l = []1617 if rootItem != None:1618 l.extend(self._dumpSubTree(rootItem, 0))1619 else:1620 for i in self._viewItems:1621 if i._indent == 0:1622 l.extend(self._dumpSubTree(i, 0))1623 return '\n'.join(l)1624 def _dumpSubTree(self, viewItem, indent):1625 l = []1626 i = viewItem1627 l.append(" "*indent + self._dumpItem(viewItem))1628 for i in viewItem.children():1629 l.extend(self._dumpSubTree(i, indent + 4))1630 return l1631 def _dumpItem(self, viewItem):1632 i = viewItem1633 if i.text() != None: t = '"%s"' % (i.text(),)1634 else: t = None1635 return "id=%s cls=%s text=%s bbox=%s vis=%s" % (1636 i.id(), i.className(), t, i.bbox(), i.visibleBranch())1637 def filename(self):1638 return self._rawDumpFilename1639 def findItems(self, comparator, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1640 """1641 Returns list of ViewItems to which comparator returns True.1642 Parameters:1643 comparator (function that takes one parameter (ViewItem))1644 returns True for all accepted items.1645 count (integer, optional):1646 maximum number of items to be returned.1647 The default is -1 (unlimited).1648 searchRootItem (ViewItem, optional):1649 search only among items that are children of1650 searchRootItem. The default is None (search from all).1651 searchItems (list of ViewItems, optional):1652 search only among given items. The default is None,1653 (search from all).1654 onScreen (boolean, optional):1655 search only among items that are on screen. The1656 default is False.1657 """1658 foundItems = []1659 if count == 0: return foundItems1660 if searchRootItem != None:1661 # find from searchRootItem and its children1662 if comparator(searchRootItem) and (1663 not onScreen or1664 searchRootItem.visibleBranch() and self._itemOnScreen(searchRootItem)):1665 foundItems.append(searchRootItem)1666 for c in searchRootItem.children():1667 foundItems.extend(self.findItems(comparator, count=count-len(foundItems), searchRootItem=c, onScreen=onScreen))1668 else:1669 if searchItems != None:1670 # find from listed items only1671 searchDomain = searchItems1672 else:1673 # find from all items1674 searchDomain = self._viewItems1675 for i in searchDomain:1676 if comparator(i) and (1677 not onScreen or1678 i.visibleBranch() and self._itemOnScreen(i)):1679 foundItems.append(i)1680 if count > 0 and len(foundItems) >= count:1681 break1682 return foundItems1683 def findItemsByText(self, text, partial=False, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1684 """1685 Returns list of ViewItems with given text.1686 """1687 if partial:1688 c = lambda item: item.text().find(text) != -1 if item.text() != None else False1689 else:1690 c = lambda item: item.text() == text1691 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1692 def findItemsById(self, id, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1693 """1694 Returns list of ViewItems with given id.1695 """1696 c = lambda item: item.id() == id1697 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1698 def findItemsByClass(self, className, partial=True, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1699 """1700 Returns list of ViewItems with given class.1701 """1702 if partial: c = lambda item: item.className().find(className) != -11703 else: c = lambda item: item.className() == className1704 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1705 def findItemsByIdAndClass(self, id, className, partial=True, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1706 """1707 Returns list of ViewItems with given id and class.1708 """1709 idOk = self.findItemsById(id, count=-1, searchRootItem=searchRootItem, onScreen=onScreen)1710 return self.findItemsByClass(className, partial=partial, count=count, searchItems=idOk, onScreen=onScreen)1711 def findItemsByContentDesc(self, content_desc, partial=False, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1712 """1713 Returns list of ViewItems with given content-desc.1714 Works on uiautomatorDumps only.1715 """1716 if partial:1717 c = lambda item: item.content_desc().find(content_desc) != -11718 else:1719 c = lambda item: item.content_desc() == content_desc1720 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1721 def findItemsByRawProps(self, s, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1722 """1723 Returns list of ViewItems with given string in properties.1724 """1725 c = lambda item: item._rawProps.find(s) != -11726 return self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1727 def findItemsByPos(self, pos, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1728 """1729 Returns list of ViewItems whose bounding box contains the position.1730 Parameters:1731 pos (pair of floats (0.0..0.1) or integers (x, y)):1732 coordinates that fall in the bounding box of found items.1733 other parameters: refer to findItems documentation.1734 Items are listed in ascending order based on area. They may1735 or may not be from the same branch in the widget hierarchy.1736 """1737 x, y = self._intCoords(pos)1738 c = lambda item: (item.bbox()[0] <= x <= item.bbox()[2] and item.bbox()[1] <= y <= item.bbox()[3])1739 items = self.findItems(c, count=count, searchRootItem=searchRootItem, searchItems=searchItems, onScreen=onScreen)1740 # sort from smallest to greatest area1741 area_items = [((i.bbox()[2] - i.bbox()[0]) * (i.bbox()[3] - i.bbox()[1]), i) for i in items]1742 return [i for _, i in sorted(area_items)]1743 def findItemsInRegion(self, bbox, count=-1, searchRootItem=None, searchItems=None, onScreen=False):1744 """1745 Returns list of ViewItems whose bounding box is within the region.1746 Parameters:1747 bbox (four-tuple of floats (0.0..1.0) or integers):1748 bounding box that specifies search region1749 (left, top, right, bottom).1750 other parameters: refer to findItems documentation.1751 Returned items are listed in ascending order based on area.1752 """1753 left, top = self._intCoords((bbox[0], bbox[1]))1754 right, bottom = self._intCoords((bbox[2], bbox[3]))1755 c = lambda item: (left <= item.bbox()[0] <= item.bbox()[2] <= right and1756 top <= item.bbox()[1] <= item.bbox()[3] <= bottom)1757 items = self.findItems(c, count=count, searchRootItem=searchRootItem,1758 searchItems=searchItems, onScreen=onScreen)1759 area_items = [((i.bbox()[2] - i.bbox()[0]) * (i.bbox()[3] - i.bbox()[1]), i) for i in items]1760 return [i for _, i in sorted(area_items)]1761 def items(self):1762 """1763 Returns list of all items in the view1764 """1765 return fmbtgti.sortItems(self._viewItems, "topleft")1766 def save(self, fileOrDirName):1767 """1768 Save view dump to a file.1769 """1770 shutil.copy(self._rawDumpFilename, fileOrDirName)1771 def _parseUIAutomatorDump(self, dump, rawDumpFilename, displayToScreen):1772 """1773 Process XML output from "uiautomator dump" and create1774 a tree of ViewItems.1775 """1776 def add_elt(elt, parent, indent, results):1777 if ("resource-id" in elt.attrib and1778 "bounds" in elt.attrib):1779 try:1780 vi = ViewItem(elt.attrib["class"],1781 elt.attrib["resource-id"].split(":", 1)[-1],1782 indent,1783 elt.attrib,1784 parent,1785 "",1786 self._rawDumpFilename,1787 displayToScreen)1788 results.append(vi)1789 if parent:1790 parent.addChild(self._viewItems[-1])1791 except Exception, e:1792 adapterlog("parseUIAutomatorDump error: %s" % (e,))1793 vi = parent1794 else:1795 vi = parent1796 for child in elt.getchildren():1797 add_elt(child, vi, indent + 1, results)1798 self._viewItems = []1799 tree = xml.etree.ElementTree.parse(rawDumpFilename)1800 root = tree.getroot()1801 add_elt(root, None, 0, self._viewItems)1802 return self._viewItems1803 def _parseDump(self, dump, rawDumpFilename, displayToScreen):1804 """1805 Process the raw window service dump data and create a tree of1806 ViewItems.1807 """1808 if not isinstance(dump, unicode):1809 try:1810 dump = unicode(dump, "utf-8")1811 except UnicodeDecodeError, e:1812 self._errors.append((0, 0, "converting to unicode failed: %s" % (e,)))1813 # This code originates from tema-android-adapter-3.2,1814 # AndroidAdapter/guireader.py.1815 self._viewItems = []1816 cellLayout = ""1817 parent = None1818 previousItem = None1819 currentIndent = 01820 visible = True1821 self.TOP_PAGED_VIEW = ""1822 last_line = set(["DONE", "DONE."])1823 for lineIndex, line in enumerate(dump.splitlines()):1824 if line in last_line:1825 break1826 # separate indent, class and properties for each GUI object1827 # TODO: branch here according to self._androidVersion1828 matcher = self._lineRegEx.match(line)1829 if not matcher:1830 # FIXME: this hack falls back to old format,1831 # should branch according to self._androidVersion!1832 matcher = self._olderAndroidLineRegEx.match(line)1833 if not matcher:1834 self._errors.append((lineIndex + 1, line, "illegal line"))1835 continue # skip this line1836 className = matcher.group("class")1837 # Indent specifies the hierarchy level of the object1838 indent = len(matcher.group("indent"))1839 # If the indent is bigger that previous, this object is a1840 # child for the previous object1841 if indent > currentIndent:1842 parent = self._viewItems[-1]1843 elif indent < currentIndent:1844 for tmp in range(0, currentIndent - indent):1845 parent = parent.parent()1846 currentIndent = indent1847 propertiesData = matcher.group("properties")1848 properties = {}1849 index = 01850 x = 01851 y = 01852 # Process the properties of each GUI object1853 while index < len(propertiesData):1854 # Separate name and value for each property [^=]*=1855 propMatch = self._propRegEx.match(propertiesData[index:-1])1856 if not propMatch:1857 self._errors.append((lineIndex, line,1858 "property parse error"))1859 break1860 name = propMatch.group("name")1861 if not name:1862 self._errors.append(1863 (lineIndex, line,1864 'illegal property name "%s"' % (name,)))1865 break1866 try:1867 dataLength = int(propMatch.group("len"))1868 except ValueError:1869 self._errors.append(1870 (lineIndex, line,1871 'illegal length (int) "%s"' % (propMatch.group("len"),)))1872 break1873 data = propMatch.group("data")1874 dataStart = index + propMatch.start("data")1875 if len(data) < dataLength:1876 if not data:1877 self._errors.append(1878 (lineIndex, line,1879 'property "%s": data missing, expected %s' % (name, dataLength, len(data))))1880 break1881 properties[name] = propertiesData[dataStart:dataStart + dataLength]1882 index = dataStart + dataLength + 11883 try:1884 vi = ViewItem(matcher.group("class"), matcher.group("id"), indent, properties, parent, matcher.group("properties"), self._rawDumpFilename, displayToScreen)1885 self._viewItems.append(vi)1886 if parent:1887 parent.addChild(self._viewItems[-1])1888 except Exception, e:1889 self._errors.append(1890 (lineIndex, line,1891 "creating view item failed (%s: %s)" % (type(e), e)))1892 return self._viewItems1893 def __str__(self):1894 return 'View(items=%s, dump="%s")' % (1895 len(self._viewItems), self._rawDumpFilename)1896class _AndroidDeviceConnection(fmbtgti.GUITestConnection):1897 """1898 Connection to the Android Device being tested.1899 """1900 _m_host = os.getenv("FMBTANDROID_ADB_FORWARD_HOST", 'localhost')1901 _m_port = int(os.getenv("FMBTANDROID_ADB_FORWARD_PORT", random.randint(20000, 29999)))1902 _w_host = _m_host1903 def __init__(self, serialNumber, **kwArgs):1904 fmbtgti.GUITestConnection.__init__(self)1905 self._serialNumber = serialNumber1906 self._adbPort = kwArgs.pop("adbPort", None)1907 self._monkeyPortForward = kwArgs.pop(1908 "adbForwardPort", _AndroidDeviceConnection._m_port)1909 self._windowPortForward = kwArgs.pop(1910 "windowPortForward", self._monkeyPortForward + 1)1911 self._stopOnError = kwArgs.pop("stopOnError", True)1912 self._monkeyOptions = kwArgs.pop("monkeyOptions", [])1913 self._screencapArgs = kwArgs.pop("screencapArgs", [])1914 self._screencapFormat = kwArgs.pop("screencapFormat", "raw")1915 self.setScreenToDisplayCoords(1916 kwArgs.pop("screenToDisplay", lambda x, y: (x, y)))1917 self.setDisplayToScreenCoords(1918 kwArgs.pop("displayToScreen", lambda x, y: (x, y)))1919 if kwArgs:1920 raise TypeError('_AndroidDeviceConnection.__init__() got an '1921 'unexpected keyword argument %s=%s' % (1922 kwArgs.keys()[0], repr(kwArgs[kwArgs.keys()[0]])))1923 self._detectFeatures()1924 self._emulatorSocket = None1925 try:1926 self._resetMonkey()1927 self._resetWindow()1928 finally:1929 # Next _AndroidDeviceConnection instance will use different ports1930 _AndroidDeviceConnection._m_port += 1001931 def __del__(self):1932 try: self._monkeySocket.close()1933 except: pass1934 try: self._emulatorSocket.close()1935 except: pass1936 def settings(self):1937 """Returns restorable property values"""1938 rv = {1939 "adbPort": self._adbPort,1940 "adbForwardPort": self._monkeyPortForward,1941 "stopOnError": self._stopOnError,1942 "monkeyOptions": self._monkeyOptions,1943 "screencapArgs": self._screencapArgs,1944 "screencapFormat": self._screencapFormat,1945 "screenToDisplay": self._screenToDisplay,1946 "displayToScreen": self._displayToScreen,1947 }1948 return rv1949 def target(self):1950 return self._serialNumber1951 def _cat(self, remoteFilename):1952 fd, filename = tempfile.mkstemp("fmbtandroid-cat-")1953 os.close(fd)1954 self._runAdb(["pull", remoteFilename, filename], 0, timeout=_LONG_TIMEOUT)1955 contents = file(filename).read()1956 os.remove(filename)1957 return contents1958 def _runAdb(self, adbCommand, expectedExitStatus=0, timeout=None):1959 if not self._stopOnError:1960 expect = None1961 else:1962 expect = expectedExitStatus1963 if self._adbPort:1964 adbPortArgs = ["-P", str(self._adbPort)]1965 else:1966 adbPortArgs = []1967 command = [_g_adbExecutable, "-s", self._serialNumber] + adbPortArgs1968 if type(adbCommand) == list or type(adbCommand) == tuple:1969 command.extend(adbCommand)1970 else:1971 command.append(adbCommand)1972 return _run(command, expectedExitStatus=expect, timeout=timeout)1973 def _emulatorCommand(self, command):1974 if not self._emulatorSocket:1975 try:1976 emulatorPort = int(re.findall("emulator-([0-9]*)", self._serialNumber)[0])1977 except (IndexError, ValueError):1978 raise FMBTAndroidError("emulator port detection failed")1979 try:1980 self._emulatorSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)1981 self._emulatorSocket.connect(("localhost", emulatorPort))1982 except socket.error, e:1983 raise FMBTAndroidError("connecting to the emulator failed: %s" % (e,))1984 self._emulatorSocket.sendall(command + "\n")1985 data = self._emulatorSocket.recv(4096)1986 try:1987 data = data.splitlines()[-1].strip()1988 except IndexError:1989 raise FMBTAndroidError("no response from the emulator")1990 if data.startswith("OK"):1991 return True, data1992 else:1993 return False, data1994 def _runSetupCmd(self, cmd, expectedExitStatus=0):1995 _adapterLog('setting up connections: "%s"' % (cmd,))1996 try:1997 if expectedExitStatus == None: # execute asynchronously1998 self._runAdb(cmd, expectedExitStatus)1999 else: # command is expected to exit2000 self._runAdb(cmd, expectedExitStatus, timeout=_SHORT_TIMEOUT)2001 except (FMBTAndroidRunError, AndroidDeviceNotFound), e:2002 _adapterLog("connection setup problem: %s" % (e,))2003 return False2004 return True2005 def _detectFeatures(self):2006 # check supported features2007 outputLines = self._runAdb(["shell", "getprop", "ro.build.version.release"],2008 timeout=_SHORT_TIMEOUT)[1].splitlines()2009 if len(outputLines) >= 1:2010 self._platformVersion = outputLines[0].strip().split("=")[-1]2011 else:2012 self._platformVersion = "N/A"2013 outputLines = self._runAdb(["shell", "id"],2014 timeout=_SHORT_TIMEOUT)[1].splitlines()2015 if len(outputLines) == 1 and "uid=0" in outputLines[0]:2016 self._shellUid0 = True2017 else:2018 self._shellUid0 = False2019 outputLines = self._runAdb(["shell", "su", "root", "id"],2020 timeout=_SHORT_TIMEOUT)[1].splitlines()2021 if len(outputLines) == 1 and "uid=0" in outputLines[0]:2022 self._shellSupportsSu = True2023 else:2024 self._shellSupportsSu = False2025 outputLines = self._runAdb(["shell", "tar"],2026 expectedExitStatus=EXITSTATUS_ANY,2027 timeout=_SHORT_TIMEOUT)[1].splitlines()2028 if len(outputLines) == 1 and "bin" in outputLines[0]:2029 self._shellSupportsTar = False2030 else:2031 self._shellSupportsTar = True2032 outputLines = self._runAdb(["shell", "echo -n foo | toybox base64"],2033 expectedExitStatus=EXITSTATUS_ANY,2034 timeout=_SHORT_TIMEOUT)[1].splitlines()2035 if len(outputLines) == 1 and "Zm9v" in outputLines[0]:2036 self._shellSupportsToyboxBase64 = True2037 else:2038 self._shellSupportsToyboxBase64 = False2039 outputLines = self._runAdb(["shell", "echo -n foo | uuencode -"],2040 expectedExitStatus=EXITSTATUS_ANY,2041 timeout=_SHORT_TIMEOUT)[1].splitlines()2042 if len(outputLines) > 0 and "begin" in outputLines[0]:2043 self._shellSupportsUuencode = True2044 else:2045 self._shellSupportsUuencode = False2046 def _resetWindow(self):2047 setupCommands = [["shell", "service" , "call", "window", "1", "i32", "4939"],2048 ["forward", "tcp:"+str(self._windowPortForward), "tcp:4939"]]2049 for c in setupCommands:2050 self._runSetupCmd(c)2051 def _resetMonkey(self, timeout=12, pollDelay=.25):2052 tryKillingMonkeyOnFailure = 12053 failureCountSinceKill = 02054 endTime = time.time() + timeout2055 if self._shellUid0:2056 monkeyLaunch = ["monkey"]2057 elif self._shellSupportsSu:2058 monkeyLaunch = ["su", "root", "monkey"]2059 else:2060 monkeyLaunch = ["monkey"]2061 if self._monkeyOptions:2062 monkeyLaunch += self._monkeyOptions2063 while time.time() < endTime:2064 monkeyShellCmd = (" ".join(monkeyLaunch + ["--port", "1080"]) +2065 " >/sdcard/fmbtandroid.monkey.outerr 2>&1")2066 _adapterLog('launching monkey: adb shell "%s"' % (monkeyShellCmd,))2067 self._runAdb(["shell", monkeyShellCmd], expectedExitStatus=None)2068 time.sleep(pollDelay)2069 if not self._runSetupCmd(["forward", "tcp:"+str(self._monkeyPortForward), "tcp:1080"]):2070 time.sleep(pollDelay)2071 failureCountSinceKill += 12072 continue2073 try:2074 self._monkeySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)2075 self._monkeySocket.connect((self._m_host, self._monkeyPortForward))2076 self._monkeySocket.setblocking(0)2077 self._monkeySocket.settimeout(5.0)2078 _ping = self._monkeyCommand("getvar build.version.release", retry=0)[1]2079 if len(_ping) > 0:2080 return True2081 except Exception, e:2082 _, monkeyOutput, _ = self._runAdb(["shell", "cat /sdcard/fmbtandroid.monkey.outerr"],2083 expectedExitStatus=EXITSTATUS_ANY,2084 timeout=_SHORT_TIMEOUT)2085 if "/sdcard/fmbtandroid.monkey.outerr: No such file or directory" in monkeyOutput:2086 msg = 'cannot read/write /sdcard on device %s' % (self._serialNumber,)2087 _adapterLog(msg)2088 raise AndroidConnectionError(msg)2089 elif "Error: Unknown option:" in monkeyOutput:2090 uo = [l for l in monkeyOutput.splitlines() if "Error: Unknown option:" in l][0].split(":")[-1].strip()2091 _adapterLog('detected an unknown option for monkey: "%s". Disabling it.' % (uo,))2092 try:2093 monkeyLaunch.remove(uo)2094 except ValueError:2095 pass2096 continue2097 elif "Error binding to network socket" in monkeyOutput:2098 _adapterLog('monkey network socket binding failed, killing old monkey')2099 self.pkill("monkey")2100 time.sleep(pollDelay)2101 continue2102 _adapterLog("monkey connection failed, output: %s" % (monkeyOutput,))2103 failureCountSinceKill += 12104 time.sleep(pollDelay)2105 if failureCountSinceKill > 2 and tryKillingMonkeyOnFailure > 0:2106 self.pkill("monkey")2107 tryKillingMonkeyOnFailure -= 12108 failureCountSinceKill = 02109 time.sleep(pollDelay)2110 if self._stopOnError:2111 msg = 'Android monkey error: cannot connect to "adb shell monkey --port 1080" to device %s' % (self._serialNumber)2112 _adapterLog(msg)2113 raise AndroidConnectionError(msg)2114 else:2115 return False2116 def _monkeyCommand(self, command, retry=3):2117 try:2118 self._monkeySocket.sendall(command + "\n")2119 data = self._monkeySocket.recv(4096).strip()2120 if len(data) == 0 and retry > 0:2121 return self._monkeyCommand(command, retry-1)2122 if data == "OK":2123 return True, None2124 elif data.startswith("OK:"):2125 return True, data.split("OK:")[1]2126 _adapterLog("monkeyCommand failing... command: '%s' response: '%s'" % (command, data))2127 return False, None2128 except socket.error:2129 try: self._monkeySocket.close()2130 except: pass2131 if retry > 0:2132 self._resetMonkey()2133 return self._monkeyCommand(command, retry=retry-1)2134 else:2135 raise AndroidConnectionError('Android monkey socket connection lost while sending command "%s"' % (command,))2136 def install(self, filename, lock, reinstall, downgrade,2137 sdcard, algo, key, iv):2138 cmd = ["install"]2139 if lock:2140 cmd.append("-l")2141 if reinstall:2142 cmd.append("-r")2143 if downgrade:2144 cmd.append("-d")2145 if sdcard:2146 cmd.append("-s")2147 if algo != None:2148 cmd.extend(["--algo", algo])2149 if key != None:2150 cmd.extend(["--key", key])2151 if iv != None:2152 cmd.extend(["--iv", iv])2153 cmd.append(filename)2154 status, output, error = self._runAdb(cmd, [0, 1], timeout=_LONG_TIMEOUT)2155 if "Success" in output:2156 return True2157 else:2158 return output + "\n" + error2159 def uninstall(self, apkname, keepData):2160 cmd = ["uninstall"]2161 if keepData:2162 cmd.append("-k")2163 cmd.append(apkname)2164 status, output, error = self._runAdb(2165 cmd, expectedExitStatus=EXITSTATUS_ANY, timeout=_LONG_TIMEOUT)2166 if "Success" in output:2167 return True2168 else:2169 return False2170 def pkill(self, pattern, signal=15, exact=False):2171 """send signal to all processes where process name contains pattern"""2172 _, ps, _ = self._runAdb(["shell", "ps"], timeout=_SHORT_TIMEOUT)2173 if self._shellSupportsSu:2174 shell_kill = ["shell", "su", "root", "kill"]2175 else:2176 shell_kill = ["shell", "kill"]2177 pids = []2178 for line in [l.strip() for l in ps.splitlines()]:2179 fields = line.split()2180 if len(fields) > 7:2181 if exact:2182 if pattern == fields[7]:2183 pids.append(fields[1])2184 else:2185 if pattern in " ".join(fields[7:]):2186 pids.append(fields[1])2187 if pids:2188 _adapterLog(str(shell_kill + ["-" + str(signal)] + pids))2189 self._runAdb(shell_kill + ["-" + str(signal)] + pids,2190 expectedExitStatus=EXITSTATUS_ANY,2191 timeout=_SHORT_TIMEOUT)2192 return True2193 else:2194 return False2195 def recvPlatformVersion(self):2196 return self._platformVersion2197 def reboot(self, reconnect, firstBootAfterFlashing, timeout):2198 if firstBootAfterFlashing:2199 self._runAdb("root", expectedExitStatus=EXITSTATUS_ANY,2200 timeout=_SHORT_TIMEOUT)2201 time.sleep(2)2202 self._runAdb(["shell", "rm",2203 "/data/data/com.android.launcher/shared_prefs/com.android.launcher2.prefs.xml"],2204 expectedExitStatus=EXITSTATUS_ANY,2205 timeout=_SHORT_TIMEOUT)2206 self._runAdb("reboot", expectedExitStatus=EXITSTATUS_ANY)2207 _adapterLog("rebooting " + self._serialNumber)2208 if reconnect:2209 time.sleep(2)2210 endTime = time.time() + timeout2211 status, _, _ = self._runAdb("wait-for-device", expectedExitStatus=None, timeout=timeout)2212 if status != 0:2213 raise AndroidDeviceNotFound('"timeout -k 1 %s adb wait-for-device" status %s' % (timeout, status))2214 self._detectFeatures()2215 while time.time() < endTime:2216 try:2217 if self._resetMonkey(timeout=1, pollDelay=1):2218 break2219 except AndroidConnectionError:2220 pass2221 time.sleep(1)2222 else:2223 msg = "reboot: reconnecting to " + self._serialNumber + " failed"2224 _adapterLog(msg)2225 raise AndroidConnectionError(msg)2226 self._resetWindow()2227 return True2228 def recvVariable(self, variableName):2229 ok, value = self._monkeyCommand("getvar " + variableName)2230 if ok: return value2231 else:2232 # LOG: getvar variableName failed2233 return None2234 def recvScreenSize(self):2235 _, output, _ = self._runAdb(["shell", "dumpsys", "display"], 0,2236 timeout=_SHORT_TIMEOUT)2237 try:2238 # parse default display properties2239 ddName, ddWidth, ddHeight, ddWdpi, ddHdpi = re.findall(2240 r'DisplayDeviceInfo\{[^,]*"([^"]*)"[:,] ([0-9]*) x ([0-9]*),.*, ([0-9.]*) x ([0-9.]*) dpi,.*FLAG_DEFAULT_DISPLAY.*\}',2241 output)[0]2242 ddWidth, ddHeight = int(ddWidth), int(ddHeight)2243 except (IndexError, ValueError), e:2244 _adapterLog('recvScreenSize: cannot read size from "%s"' %2245 (output,))2246 raise FMBTAndroidError('cannot read screen size from dumpsys')2247 vpWidth, vpHeight = self.recvDefaultViewportSize()2248 if ((vpWidth > vpHeight) and (ddWidth < ddHeight) or2249 (vpWidth < vpHeight) and (ddWidth > ddHeight)):2250 ddWidth, ddHeight = ddHeight, ddWidth2251 return int(ddWidth), int(ddHeight)2252 def recvDefaultViewportSize(self):2253 _, output, _ = self._runAdb(["shell", "dumpsys", "display"], 0,2254 timeout=_SHORT_TIMEOUT)2255 try:2256 _, w, h = re.findall("mDefaultViewport(\[0\])?=DisplayViewport\{.*deviceWidth=([0-9]*), deviceHeight=([0-9]*)\}", output)[0]2257 width = int(w)2258 height = int(h)2259 except (IndexError, ValueError), e:2260 _adapterLog('recvScreenSize: cannot read size from "%s"' %2261 (output,))2262 raise FMBTAndroidError('cannot read screen size from dumpsys')2263 return width, height2264 def recvCurrentDisplayOrientation(self):2265 _, output, _ = self._runAdb(["shell", "dumpsys", "display"], 0,2266 timeout=_SHORT_TIMEOUT)2267 s = re.findall("mCurrentOrientation=([0-9])", output)2268 if s:2269 return int(s[0])2270 else:2271 return None2272 def recvDisplayPowered(self):2273 _, output, _ = self._runAdb(["shell", "dumpsys", "power"], 0,2274 timeout=_SHORT_TIMEOUT)2275 s = re.findall("Display Power: state=(OFF|ON)", output)2276 if s:2277 return s[0] == "ON"2278 else:2279 return None2280 def recvShowingLockscreen(self):2281 _, output, _ = self._runAdb(["shell", "dumpsys", "window"], 0,2282 timeout=_SHORT_TIMEOUT)2283 s = re.findall("mShowingLockscreen=(true|false)", output)2284 if s:2285 if s[0] == "true":2286 return True2287 else:2288 return False2289 else:2290 return None2291 def recvLastAccelerometer(self):2292 _, output, _ = self._runAdb(["shell", "dumpsys", "sensorservice"], 0,2293 timeout=_SHORT_TIMEOUT)2294 s = re.findall("3-axis Accelerometer.*last=<([- .0-9]*),([- .0-9]*),([- .0-9]*)>", output)2295 try:2296 rv = tuple([float(d) for d in s[0]])2297 except (IndexError, ValueError):2298 rv = (None, None, None)2299 return rv2300 def sendAcceleration(self, abc):2301 """abc is a tuple of 1, 2 or 3 floats, new accelerometer readings"""2302 try:2303 self._emulatorCommand("sensor set acceleration %s" %2304 (":".join([str(value) for value in abc]),))2305 except FMBTAndroidError, e:2306 raise FMBTAndroidError(2307 "accelerometer can be set only on emulator (%s)" % (e,))2308 return True2309 def sendAccelerometerRotation(self, value):2310 if value:2311 sendValue = "i:1"2312 else:2313 sendValue = "i:0"2314 try:2315 self._runAdb(["shell", "content", "insert",2316 "--uri", "content://settings/system",2317 "--bind", "name:s:accelerometer_rotation",2318 "--bind", "value:" + sendValue],2319 expectedExitStatus=0,2320 timeout=_SHORT_TIMEOUT)2321 except Exception:2322 return False2323 return True2324 def recvAccelerometerRotation(self):2325 try:2326 _, output, _ = self._runAdb(2327 ["shell", "content", "query",2328 "--uri", "content://settings/system/accelerometer_rotation"],2329 timeout=_SHORT_TIMEOUT)2330 s = re.findall("value=(.*)", output)[0]2331 return int(s) == 1 # True if accelerometer_rotation is enabled2332 except Exception:2333 return None2334 def sendDeviceLog(self, msg, priority, tag):2335 cmd = ["shell", "log", "-p", priority, "-t", tag, msg]2336 status, out, err = self._runAdb(cmd, [0, 124], timeout=_SHORT_TIMEOUT)2337 if status == 124:2338 errormsg = "log timeout: %s" % (["adb"] + cmd)2339 _adapterLog(errormsg)2340 raise FMBTAndroidError(errormsg)2341 return True2342 def sendUserRotation(self, rotation):2343 allowedRotations = [ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270]2344 if not rotation in allowedRotations:2345 raise ValueError("invalid rotation: %s, use one of %s" %2346 (allowedRotations,))2347 sendValue = "i:%s" % (rotation,)2348 try:2349 self._runAdb(["shell", "content", "insert",2350 "--uri", "content://settings/system",2351 "--bind", "name:s:user_rotation",2352 "--bind", "value:" + sendValue],2353 timeout=_SHORT_TIMEOUT)2354 except Exception:2355 return False2356 return True...

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