Best Python code snippet using fMBT_python
fmbtandroid.py
Source:fmbtandroid.py
...286 self.btAccessory = self._conf.value("environment", "BTAccessory")287 self.serverIP = self._conf.value("environment", "ServerIP")288 self.androidUser = self._conf.value("environment", "AndroidUser")289 self.voiceMailNumber = self._conf.value("environment", "VoiceMailNumber")290 if self._conn: hw = self._conn.recvVariable("build.device")291 else: hw = "nohardware"292 self.hardware = self._conf.value("general", "hardware", hw)293 self.setBitmapPath(self._conf.value("paths", "bitmapPath", ".:" + self._fmbtAndroidHomeDir + os.sep + "bitmaps" + os.sep + self.hardware + "-" + self.platformVersion()), self._fmbtAndroidHomeDir)294 self.setScreenshotDir(self._conf.value("paths", "screenshotDir", self._fmbtAndroidHomeDir + os.sep + "screenshots"))295 def callContact(self, contact):296 """297 Call to given contact.298 Return True if successful, otherwise False.299 """300 callCommand = 'service call phone 1 s16 "%s"' % (contact,)301 status, out, err = self.shellSOE(callCommand)302 if status != 0:303 _logFailedCommand("callContact", callCommand, status, out, err)304 return False305 else:306 return True307 def callNumber(self, number):308 """309 Call to given phone number.310 Return True if successful, otherwise False.311 """312 callCommand = "am start -a android.intent.action.CALL -d 'tel:%s'" % (number,)313 status, out, err = self.shellSOE(callCommand)314 if status != 0:315 _logFailedCommand("callNumber", callCommand, status, out, err)316 return False317 else:318 return True319 def close(self):320 fmbtgti.GUITestInterface.close(self)321 if hasattr(self, "_conn"):322 del self._conn323 if hasattr(self, "_lastView"):324 del self._lastView325 import gc326 gc.collect()327 def dumpIni(self):328 """329 Returns contents of current device configuration as a string (in330 INI format).331 """332 return self._conf.dump()333 def ini(self):334 """335 Returns an Ini object containing effective device336 configuration.337 """338 return self._conf339 def loadConfig(self, filenameOrObj, override=True, level=""):340 try:341 if type(filenameOrObj) == str:342 filename = filenameOrObj343 fileObj = file(filenameOrObj)344 else:345 fileObj = filenameOrObj346 filename = getattr(fileObj, "name", "<string>")347 if hasattr(fileObj, "seek"):348 fileObj.seek(0)349 self._conf.addFile(fileObj, override=override)350 except Exception, e:351 _adapterLog('Loading %s configuration from "%s" failed: %s' % (level, filename, e))352 return353 _adapterLog('Loaded %s configuration from "%s"' % (level, filename))354 def platformVersion(self):355 """356 Returns the platform version of the device.357 """358 if self._platformVersion == None:359 if self._conn:360 self._platformVersion = self._conn.recvVariable("build.version.release")361 else:362 self._platformVersion = "nosoftware"363 return self._platformVersion364 def pressAppSwitch(self, **pressKeyKwArgs):365 """366 Press the app switch button.367 Optional parameters are the same as for pressKey.368 """369 return self.pressKey("KEYCODE_APP_SWITCH", **pressKeyKwArgs)370 def pressBack(self, **pressKeyKwArgs):371 """372 Press the back button.373 Optional parameters are the same as for pressKey.374 """375 return self.pressKey("KEYCODE_BACK", **pressKeyKwArgs)376 def pressHome(self, **pressKeyKwArgs):377 """378 Press the home button.379 Optional parameters are the same as for pressKey.380 """381 return self.pressKey("KEYCODE_HOME", **pressKeyKwArgs)382 def pressKey(self, keyName, long=False, hold=0.0):383 """384 Press a key on the device.385 Parameters:386 keyName (string):387 the name of the key, like KEYCODE_HOME. If KEYCODE_388 prefix is not given, it is added. Refer to Android389 KeyEvent documentation.390 long (boolean, optional):391 if True, press the key for long time.392 hold (float, optional):393 time in seconds to hold the key down.394 """395 if not keyName.upper().startswith("KEYCODE_"):396 keyName = "KEYCODE_" + keyName397 keyName = keyName.upper()398 return fmbtgti.GUITestInterface.pressKey(self, keyName, long, hold)399 def pressMenu(self, **pressKeyKwArgs):400 """401 Press the menu button.402 Optional parameters are the same as for pressKey.403 """404 return self.pressKey("KEYCODE_MENU", **pressKeyKwArgs)405 def pressPower(self, **pressKeyKwArgs):406 """407 Press the power button.408 Optional parameters are the same as for pressKey.409 """410 return self.pressKey("KEYCODE_POWER", **pressKeyKwArgs)411 def pressSearch(self, **pressKeyKwArgs):412 """413 Press the search button.414 Optional parameters are the same as for pressKey.415 """416 return self.pressKey("KEYCODE_SEARCH", **pressKeyKwArgs)417 def pressVolumeUp(self, **pressKeyKwArgs):418 """419 Press the volume up button.420 Optional parameters are the same as for pressKey.421 """422 return self.pressKey("KEYCODE_VOLUME_UP", **pressKeyKwArgs)423 def pressVolumeDown(self, **pressKeyKwArgs):424 """425 Press the volume down button.426 Optional parameters are the same as for pressKey.427 """428 return self.pressKey("KEYCODE_VOLUME_DOWN", **pressKeyKwArgs)429 def reboot(self, reconnect=True, firstBoot=False, timeout=120):430 """431 Reboot the device.432 Parameters433 reconnect (boolean, optional)434 If True, do not return until the device has been435 connected after boot. Otherwise return once reboot436 command has been sent. The default is True.437 firstBoot (boolean, optional)438 If True, the device boots like it would have been439 flashed. Requires that "adb root" works. The default440 is False.441 timeout (integer, optional)442 Timeout in seconds for reconnecting after reboot.443 The default is 120 s.444 Returns True on success, otherwise False.445 """446 return self._conn.reboot(reconnect, firstBoot, timeout)447 def reconnect(self):448 """449 Close connections to the device and reconnect.450 """451 self.setConnection(None)452 import gc453 gc.collect()454 try:455 self.setConnection(_AndroidDeviceConnection(self.serialNumber))456 return True457 except Exception, e:458 _adapterLog("reconnect failed: %s" % (e,))459 return False460 def refreshView(self, forcedView=None):461 """462 (Re)reads view items on display and updates the latest View463 object.464 Parameters:465 forcedView (View or filename, optional):466 use given View object or view file instead of reading467 items from the device.468 Returns created View object.469 """470 def formatErrors(errors):471 return "refreshView parse errors:\n %s" % (472 "\n ".join(["line %s: %s error: %s" % e for e in errors]),)473 if self._conn:474 displayToScreen = self._conn._displayToScreen475 else:476 displayToScreen = None477 if forcedView != None:478 if isinstance(forcedView, View):479 self._lastView = forcedView480 elif type(forcedView) == str:481 self._lastView = View(self.screenshotDir(), self.serialNumber, file(forcedView).read(), displayToScreen)482 _adapterLog(formatErrors(self._lastView.errors()))483 else:484 raise ValueError("forcedView must be a View object or a filename")485 return self._lastView486 retryCount = 0487 while True:488 dump = self._conn.recvViewData()489 if dump != None:490 view = View(self.screenshotDir(), self.serialNumber, dump, displayToScreen)491 else:492 _adapterLog("refreshView window dump reading failed")493 view = None494 # fail quickly if there is no answer495 retryCount += self._PARSE_VIEW_RETRY_LIMIT / 2496 if dump == None or len(view.errors()) > 0:497 if view:498 _adapterLog(formatErrors(view.errors()))499 if retryCount < self._PARSE_VIEW_RETRY_LIMIT:500 retryCount += 1501 time.sleep(0.2) # sleep before retry502 else:503 raise AndroidConnectionError("Cannot read window dump")504 else:505 # successfully parsed or parsed with errors but no more retries506 self._lastView = view507 return view508 def useDisplaySize(self, (width, height) = (None, None)):509 """510 Transform coordinates of synthesized events from screenshot511 resolution to given resolution. By default events are512 synthesized directly to screenshot coordinates.513 Parameters:514 (width, height) (pair of integers, optional):515 width and height of display in pixels. If not516 given, values from Android system properties517 "display.width" and "display.height" will be used.518 Returns None.519 """520 if width == None:521 width = int(self.systemProperty("display.width"))522 if height == None:523 height = int(self.systemProperty("display.height"))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]),))...
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!!