123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- # -*- coding:utf-8 -*-
- import time,sys,os
- from UAT_tree import UATTree
- from UAT_log import error,info,debug
- from UAT_PathManage import UATPathManage
- from UAT_runnerCommand import UATRunnerCommand
- from ssat_sdk.python_uiautomator import PyUIAutomator,DirectionManageAndroid,FocusManageAndroid
- ERROR = True
- INFO = True
- DEBUG = True
- '''
- 采用uiautomator技术,处理界面定位问题,用于移动焦点到目标组件上
- '''
- class FocusCommand():
- cls = "FocusCommand"
- UIObjParam = {
- "text": None, # MASK_TEXT,
- "textContains": None, # MASK_TEXTCONTAINS,
- "textMatches": None, # MASK_TEXTMATCHES,
- "textStartsWith": None, # MASK_TEXTSTARTSWITH,
- "className": None, # MASK_CLASSNAME
- "classNameMatches": None, # MASK_CLASSNAMEMATCHES
- "description": None, # MASK_DESCRIPTION
- "descriptionContains": None, # MASK_DESCRIPTIONCONTAINS
- "descriptionMatches": None, # MASK_DESCRIPTIONMATCHES
- "descriptionStartsWith": None, # MASK_DESCRIPTIONSTARTSWITH
- "checkable": None, # MASK_CHECKABLE
- "checked": None, # MASK_CHECKED
- "clickable": None, # MASK_CLICKABLE
- "longClickable": None, # MASK_LONGCLICKABLE,
- "scrollable": None, # MASK_SCROLLABLE,
- "enabled": None, # MASK_ENABLED,
- "focusable": None, # MASK_FOCUSABLE,
- "focused": None, # MASK_FOCUSED,
- "selected": None, # MASK_SELECTED,
- "packageName": None, # MASK_PACKAGENAME,
- "packageNameMatches": None, # MASK_PACKAGENAMEMATCHES,
- "resourceId": None, # MASK_RESOURCEID,
- "resourceIdMatches": None, # MASK_RESOURCEIDMATCHES,
- "index": None, # MASK_INDEX,
- "instance": None # MASK_INSTANCE,
- }
- UATParamMap = {
- "text":"text", # MASK_TEXT,
- "textContains":"textContains", # MASK_TEXTCONTAINS,
- "textMatch":"textMatches", # MASK_TEXTMATCHES,
- "textSWith":"textStartsWith", # MASK_TEXTSTARTSWITH,
- "class":"className", # MASK_CLASSNAME
- "classMatches":"classNameMatches", # MASK_CLASSNAMEMATCHES
- "desc":"description", # MASK_DESCRIPTION
- "descContain":"descriptionContains", # MASK_DESCRIPTIONCONTAINS
- "descMatch":"descriptionMatches", # MASK_DESCRIPTIONMATCHES
- "descSWith":"descriptionStartsWith", # MASK_DESCRIPTIONSTARTSWITH
- "checkable":"checkable", # MASK_CHECKABLE
- "checked":"checked", # MASK_CHECKED
- "clickable":"clickable", # MASK_CLICKABLE
- "lClickable":"longClickable", # MASK_LONGCLICKABLE,
- "scrollable":"scrollable", # MASK_SCROLLABLE,
- "enable":"enabled", # MASK_ENABLED,
- "focusable":"focusable", # MASK_FOCUSABLE,
- "focused":"focused", # MASK_FOCUSED,
- "selected":"selected", # MASK_SELECTED,
- "pkg":"packageName", # MASK_PACKAGENAME,
- "pkgMatch":"packageNameMatches", # MASK_PACKAGENAMEMATCHES,
- "resid":"resourceId", # MASK_RESOURCEID,
- "residMatch":"resourceIdMatches", # MASK_RESOURCEIDMATCHES,
- "index":"index", # MASK_INDEX,
- "instance":"instance" # MASK_INSTANCE,
- }
- def __init__(self, runnerCommand):
- self.runnerCommand = runnerCommand
- self.pyU = PyUIAutomator()
- self.dm = DirectionManageAndroid()
- self.fm = FocusManageAndroid(self.pyU, self.dm)
- self.inLayout= False
- '''
- 在parent界面,将焦点移动到目标option上。
- 焦点定位:根据layout是不是限制焦点范围,进行焦点组件寻找,焦点组件类型:focus、select、focusView、long-click
- 目标定位:纯粹是根据optionView配置组建坐标定位
- :param parent:当前电视界面的parent字典
- :param option:目标option字典
- :return True/False
- '''
- def focusOptionView(self, parent, option):
- #是否采用layout限制焦点判断范围
- layout = parent[UATTree.TAB_LAYOUT]
- print "focusOptionView,layout:",layout
- self.inLayout = layout[UATTree.Layout_Limit]
- # 找到目标optionView参数
- layoutUIObj = {}
- optionUIObjParam = self.setObjParam(option[UATTree.TAB_OPTION_VIEW])
- if self.inLayout == 1:
- layoutUIObjParam = self.setObjParam(layout)
- else:
- layoutUIObjParam = {}
- # 获取move key按键
- moveKey = parent[UATTree.TAB_MOVE_KEY]
- if moveKey[UATTree.Max_Try] != "":
- Max_Try = int(moveKey[UATTree.Max_Try])
- else:
- Max_Try = parent[UATTree.TAB_OPTION].__len__()
- findDirection = ["down","up"]
- keyType = UATTree.Key_Event
- if moveKey[UATTree.Key_Event].__len__() > 1:
- findDirection = moveKey[UATTree.Key_Event]
- keyType = UATTree.Key_Event
- elif moveKey[UATTree.Key_IR].__len__() > 1:
- findDirection = moveKey[UATTree.Key_IR]
- keyType = UATTree.Key_IR
- elif moveKey[UATTree.Key_Input].__len__() > 1:
- inputCmd = moveKey[UATTree.Key_Input]
- #TODO input情况的处理
- return False
- else:
- error(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " option 读取 move_key失败", ERROR)
- return False
- #获取焦点View和optionview的area参数
- osamBounds = option[UATTree.TAB_OPTION_VIEW][UATTree.View_sambounds]
- fsamBounds = ""
- #获取焦点view参数
- fsParam = option[UATTree.TAB_FOCUS_SELECT]
- fvParam = option[UATTree.TAB_FOCUSE_VIEW]
- fvUIParam = self.setObjParam(fvParam)
- if fsParam[UATTree.FS_Type].__len__() > 1:
- if fsParam[UATTree.FS_Type].lower() == "focus":
- fsParam["focused"] = True
- elif fsParam[UATTree.FS_Type].lower() == "select":
- fsParam["select"] = True
- else:
- error(self.cls,"focusOptionView","Option %s focus-select参数异常。"%option[UATTree.TAB_NAME], ERROR)
- return False
- fsamBounds = fsParam[UATTree.View_sambounds]
- fsUIParam = self.setObjParam(fsParam)
- return self.toDestObj(optionUIObjParam, fsUIParam,Max_Try,findDirection,keyType,layoutUIObjParam,fsamBounds,osamBounds)
- elif fvUIParam.__len__() > 0:
- fsamBounds = fvParam[UATTree.View_sambounds]
- return self.toDestObj(optionUIObjParam, fvUIParam,Max_Try,findDirection,keyType,layoutUIObjParam,fsamBounds,osamBounds)
- else:
- error(self.cls, "focusOptionView", "Option %s focusView参数异常。" % option[UATTree.TAB_NAME], ERROR)
- return False
- def toDestObj(self, destUIParam, focusObjParam, Max_Try=10, findDirections=["down","up"], keyType=UATTree.Key_Event
- ,layoutUIParam={},fsamBounds="",osamBounds=""):
- # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
- print "toDestObj,enter:",Max_Try,findDirections,keyType
- count = 0
- Max_Try = Max_Try
- directIndex = 0
- while (True):
- if count >= Max_Try and directIndex >= findDirections.__len__():
- break
- # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
- time.sleep(0.5)
- print "toDestObj,focusObjParam:",focusObjParam
- focusedUIObject = self.pyU.getUiObject2(focusObjParam)
- focusedBounds = focusedUIObject.info['bounds']
- # print "focusedBounds:",focusedBounds
- if layoutUIParam.__len__() > 0:
- layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
- destUIObject = layoutUIObj.child(**destUIParam)
- else:
- destUIObject = self.pyU.getUiObject2(destUIParam)
- if destUIObject:
- print "focusOptionView,focusedBounds,destUIBounds:",focusedBounds, destUIObject.info['bounds']
- try:
- destBounds = destUIObject.info['bounds']
- # print "destBounds:", destBounds
- if self.hasFocusDest(focusedBounds, destBounds, ):
- print '成功聚焦到目标焦点:',destUIParam
- return True
- else:
- count = count + 1
- direction = self.dm.getTargetDirection(focusedBounds, destBounds)
- self.dm.goOneStep(self.pyU, direction, keyType)
- except Exception,e:
- print "toDestObj,e:",e
- # 出现控件出现一半的时候,获取控件信息会报错
- if count < Max_Try:
- count = count + 1
- else:
- directIndex = directIndex + 1
- self.fm.pressKeyByType(findDirections[directIndex], keyType)
- # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
- else:
- if count < Max_Try:
- count = count + 1
- self.fm.pressKeyByType(findDirections[directIndex], keyType)
- else:
- directIndex = directIndex + 1
- self.fm.pressKeyByType(findDirections[directIndex], keyType)
- print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
- return False
- '''
- 根据配置的样本焦点框和OptionView 区域坐标,计算是否聚焦
- '''
- def hasFocusDest(self,focusedBounds, destBounds, fsamBounds="",osamBounds=""):
- if fsamBounds.__len__() < 1 or osamBounds.__len__()<1:
- return self.dm.isHasAnotherBounds(focusedBounds, destBounds)
- else:#在焦点框bounds特别大时,同时包含多个目标optionView时,用此方法判断是否选中。
- fsamBounds = self.strToBounds(fsamBounds)
- osamBounds = self.strToBounds(osamBounds)
- sdx=fsamBounds[0][0] - osamBounds[0][0]
- sdy=fsamBounds[0][1] - osamBounds[0][1]
- sdrate = self.calPointAngle(fsamBounds)
- focusBounds = self.strToBounds(focusedBounds)
- destBounds = self.strToBounds(destBounds)
- dx = focusBounds[0][0] - destBounds[0][0]
- dy = focusBounds[0][1] - destBounds[0][1]
- drate = dy / dx
- if (drate - sdrate) < 5:
- return True
- else:
- return False
- '''
- 计算点p1相对点p2的角度
- '''
- def calPointAngle(self, p1, p2):
- dx = p1[0]-p2[0]
- dy = p1[1]-p2[1]
- '''
- 将‘[801,116][1280,180]’转成数组[[801,116][1280,180]]
- '''
- def strToBounds(self,bstr):
- char = "[]"
- print "strToBounds,bstr:",bstr
- keyIndex = 1
- # key.__len__()-1 为去掉"["的处理
- i1 = bstr.find(char[0])
- i2 = bstr.find(char[1])
- if i1 == -1 or i2 == -1:
- return []
- str1 = bstr[i1: i2+1]
- str2 = bstr[i2+1 : bstr.__len__()]
- return [eval(str1),eval(str2)]
- '''
- 根据传入的uat界面obj参数,转换成UIObject参数
- 参数均用字典存储。
- '''
- def setObjParam(self, uatObjParam):
- uiObjParam = {}
- for uatKey in uatObjParam:
- uatParam = uatObjParam[uatKey]
- if self.UATParamMap.has_key(uatKey) and uatParam is not None and str(uatParam).__len__() > 0:
- uiObjParam[self.UATParamMap[uatKey]] = uatParam
- return uiObjParam
- '''
- 检测option组件,在电视上是否被选中了
- :param option 数据字典
- :return -1:未进入option的页面,找不到option UIObject;0:进入了option的页面,未选中option;1 已经选中option
- -2:代表未找到焦点
- '''
- def checkOptionChoose(self, option):
- optionUIObj = self.pyU.getUiObject(text=option["optionView"][UATTree.View_Text],
- resourceId=option["optionView"][UATTree.View_ID],
- description=option["optionView"][UATTree.View_Desc])
- if optionUIObj is None or optionUIObj.count == 0:
- return -1
- curUIObj = self.getChooseUIObj(option)
- if curUIObj is None or curUIObj.count == 0:
- return -2
- if self.dm.isHasAnotherBounds(curUIObj.info["bounds"], optionUIObj.info['bounds']):
- return 1
- else:
- return 0
- '''
- 根据option配置的焦点方式,返回当前页面焦点组件
- '''
- def getChooseUIObj(self, option):
- print "getChooseUIObj option:", option["focus-select"]
- if option["focus-select"]["type"].__len__() > 1:
- chooseType = option["focus-select"][UATTree.FS_Type]
- if chooseType.lower() == "focus":
- return self.pyU.getFocusedUIObject()
- elif chooseType.lower() == "select":
- return self.pyU.getSelectedUIObject()
- elif chooseType.lower() == "no":
- resId = option[UATTree.TAB_OPTION_VIEW][UATTree.View_ID]
- text = option[UATTree.TAB_OPTION_VIEW][UATTree.View_Text]
- className = option[UATTree.TAB_OPTION_VIEW][UATTree.View_Class]
- desc = option[UATTree.TAB_OPTION_VIEW][UATTree.View_Desc]
- return self.pyU.getUiObject(resourceId=resId, text=text, className=className, description=desc)
- else:
- error(self.cls, "getChooseUIObj", option["name"] + " option focus-select属性配置异常", ERROR)
- return None
- elif option["focuseView"][UATTree.Focus_Text].__len__() > 0 \
- or option["focuseView"][UATTree.Focus_ID].__len__() > 1 \
- or option["focuseView"][UATTree.Focus_Desc].__len__() > 0:
- return self.pyU.getUiObject(text=option["focuseView"][UATTree.Focus_Text],
- resourceId=option["focuseView"][UATTree.Focus_ID],
- description=option["focuseView"][UATTree.Focus_Desc])
- else:
- error(self.cls, "getChooseUIObj", option["name"] + " option 需要配置 focus-select或者FocusView", ERROR)
- return None
- '''
- 检测parent,在电视上是否被选中了。一个option被选中,表示选中
- :param option 数据字典
- :return
- -3:代表UIView判断未通过;
- -2:代表选中了parent,但未找到焦点;
- -1:未进入parent的页面,找不到parent layout;
- 0:进入了parent的页面,未选中parent;
- 1:已经选中parent
- '''
- def checkParentChoose(self, parent):
- debug(self.cls, "checkParentChoose", "parent:" + parent["name"], DEBUG)
- chooseTypeDict = {}
- layoutResId = parent["layout"][UATTree.Layout_ID]
- uiView = parent[UATTree.TAB_UI_VIEW]
- uiViewResId = uiView[UATTree.View_ID]
- uiViewText = uiView[UATTree.View_Text]
- uiViewDesc = uiView[UATTree.View_Desc]
- if layoutResId == "" and uiViewResId == "" and uiViewText == "" and uiViewDesc == "":
- debug(self.cls, "checkParentChoose",
- "Warning:Parent %s的Layout resId和UIView信息获取失败!!请注意检查UATree文件!!!" % parent['name'], DEBUG)
- return -1
- elif layoutResId != "":
- # 如果存在UIView信息,则先判断UIView
- if uiViewResId != "" or uiViewText != "" or uiViewDesc != "":
- isExist = self.checkUIViewExist(uiView)
- if isExist is False:
- info(self.cls, "checkParentChoose", "当前页面不存在Parent:%s的UIView组件,判断该界面非此parent" % parent['name'],
- INFO)
- return -3
- else:
- info(self.cls, "checkParentChoose", "已识别出Parent:%s的UIView组件" % parent['name'], INFO)
- description = parent["layout"][UATTree.Layout_Desc]
- if description != "":
- layoutUIObj = self.pyU.getUiObject(resourceId=parent["layout"][UATTree.Layout_ID],
- description=parent["layout"][UATTree.Layout_Desc])
- else:
- layoutUIObj = self.pyU.getUiObject(resourceId=parent["layout"][UATTree.Layout_ID])
- if layoutUIObj is None or layoutUIObj.count == 0:
- # debug(self.cls, "checkParentChoose", "parent isn't " + parent["name"], DEBUG)
- return -1
- # print "checkParentChoose, layoutUIObj:",layoutUIObj.info
- debug(self.cls, "checkParentChoose", "layoutUIObj:" + str(layoutUIObj.info), DEBUG)
- for optionName in parent["option"]:
- option = parent["option"][optionName]
- if option["focus-select"]["type"].__len__() > 1:
- chooseTypeDict[option["focus-select"][UATTree.FS_Type]] = option
- elif option["focuseView"][UATTree.Focus_Text].__len__() > 0 \
- or option["focuseView"][UATTree.Focus_ID].__len__() > 1 \
- or option["focuseView"][UATTree.Focus_Desc].__len__() > 0:
- chooseTypeDict[option["focuseView"][UATTree.Focus_ID]
- + option["focuseView"][UATTree.Focus_Text]
- + option["focuseView"][UATTree.Focus_Desc]] = option
- info(self.cls, "checkParentChoose", str(chooseTypeDict), INFO)
- for key in chooseTypeDict.keys():
- option = chooseTypeDict[key]
- chooseUIObj = self.getChooseUIObj(option)
- # TODO 如果选中效果,是没有type[no],例如快捷键,如何处理?
- if chooseUIObj is None or chooseUIObj.count == 0:
- return -2
- debug(self.cls, "checkParentChoose", "chooseUIObj:" + str(chooseUIObj.info), DEBUG)
- # 获取到chooseUIObj后,与layout对比坐标,确认焦点是否存在于layout之中
- layoutBounds = layoutUIObj.info['bounds']
- choosingBounds = chooseUIObj.info['bounds']
- if not self.dm.isHasAnotherBounds(layoutBounds, choosingBounds):
- info(self.cls, "checkParentChoose",
- "识别出parent %s的Layout,但焦点不在该Layout之中,判断界面未处于该parent" % (parent['name']), INFO)
- return -2
- # 如果该页面text属性不为空,则确认该parent下所有option的text,是否存在于当前页面中;如果text属性为空,则判断index属性
- for optionName in parent["option"]:
- option = parent["option"][optionName]
- # 如果有text属性则确认Text,是否能对比成功
- optionText = option[UATTree.TAB_OPTION_VIEW][UATTree.View_Text]
- optionId = option[UATTree.TAB_OPTION_VIEW][UATTree.View_ID]
- optionIndex = option[UATTree.TAB_OPTION_VIEW][UATTree.View_Index]
- if optionText.__len__() > 0:
- info(self.cls, "checkParentChoose",
- "checking parent %s text %s" % (parent['name'], optionText), INFO)
- textObj = self.pyU.getUiObject(text=optionText)
- elif optionId.__len__() > 0:
- info(self.cls, "checkParentChoose",
- "checking parent %s optionId %s" % (parent['name'], optionId),
- INFO)
- textObj = self.pyU.getUiObject(resourceId=optionId)
- elif optionIndex != "":
- # index属性无法用于判断option,如果在以index属性作为判断依据的页面,则直接返回在这个页面
- info(self.cls, "checkParentChoose",
- "已找到目标parent %s,该页面为Index item页面,无法判断具体option" % parent['name'], INFO)
- return 1
- else:
- error(self.cls, "checkParentChoose", "当前参数不足以判断option %s是否存在" % (option['name']), ERROR)
- continue
- if textObj.exists:
- info(self.cls, "checkParentChoose",
- "已找到目标parent %s,并识别出该parent下的option %s" % (parent['name'], option['name']), INFO)
- return 1
- else:
- info(self.cls, "checkParentChoose",
- "return 0", INFO)
- return 0
- else:
- isExist = self.checkUIViewExist(uiView)
- if not isExist:
- return -3
- else:
- info(self.cls, "checkParentChoose",
- "识别出parent %s的UIView参数,判断处于该界面中" % (parent['name']), INFO)
- return 1
- '''
- 检测某个弹窗是否存在。
- 弹窗相关的参数放在UIView中配置。
- 当存在resId参数时,使用resId获取对象并获取文本,再与text做比较;
- 当不存在resId参数时,使用text直接获取对象,判断对象是否存在。
- 与checkParentChoose判断不一致,做特殊处理。
- '''
- def checkDialogExist(self, dialog):
- debug(self.cls, "checkDialogExist", "dialog:" + dialog["name"], DEBUG)
- dialogText = dialog[UATTree.TAB_UI_VIEW][UATTree.UIView_Text]
- dialogResId = dialog[UATTree.TAB_UI_VIEW][UATTree.UIView_ID]
- # print "checkDialogExist.dialogText:", dialogText
- # print "checkDialogExist.dialogResId:", dialogResId
- if dialogResId != "":
- textObj = self.pyU.getUiObject(resourceId=dialogResId)
- if textObj.exists:
- objText = textObj.info['text']
- # print "checkDialogExist.objText:", objText
- if dialogText in objText:
- return 1
- else:
- return 0
- else:
- return 0
- else:
- textObj = self.pyU.getUiObject(text=dialogText)
- if textObj.exists:
- return 1
- else:
- return 0
- def checkUIViewExist(self, uiView):
- resid = uiView[UATTree.View_ID]
- text = uiView[UATTree.View_Text]
- description = uiView[UATTree.View_Desc]
- uiViewObj = self.pyU.getUiObject(resourceId=resid,
- text=text,
- description=description)
- if not uiViewObj.exists:
- return False
- else:
- return True
- if __name__ == "__main__":
- uatPathManage = UATPathManage()
- pyU = PyUIAutomator()
- dm = DirectionManageAndroid()
- fm = FocusManageAndroid(pyU, dm)
- runnerCmd = UATRunnerCommand(uatPathManage, pyU, dm, fm)
- focusCmd = FocusCommand(runnerCmd)
- focusCmd.strToBounds('[801,116][1280,180]')
- # option = focusCmd.runnerCommand.uatPathManage.uatData.getOption("av_devices_settings")
- # parent = focusCmd.runnerCommand.uatPathManage.uatData.getParentByOption(option)
- # focusCmd.focusOptionView(parent, option)
- # print "dump_hierarchy 0:",time.time()
- # print focusCmd.pyU.dump_hierarchy()
- # print "dump_hierarchy 1:",time.time()
- # uiobjg = focusCmd.pyU.getUiObject()
|