scbc.sat2 5 anos atrás
pai
commit
bbb1e6e28f

+ 9 - 8
ssat_sdk/UATree/UAT_PathManage.py

@@ -124,14 +124,15 @@ class UATPathManage():
 
 if __name__ == '__main__':
     uatPathManage = UATPathManage()
-    parentName = "usb_video_h264-ac3_replay"
+    parentName = "av_devices_settings"
     curParent = uatPathManage.uatData.getParentDict(parentName)
-    print curParent
-    # backPath, forwardPath = uatPathManage.genOptionSmartPath(curParent,option)
-    # print "option:", option
-    # print "backPath:"
-    # uatPathManage.info(backPath)
-    # print "forwardPath:"
-    # uatPathManage.info(forwardPath)
+    print "curParent:", curParent
+    option  = uatPathManage.uatData.getOption("av_vivid")
+    backPath, forwardPath = uatPathManage.genOptionSmartPath(curParent,option)
+    print "option:", option
+    print "backPath:"
+    uatPathManage.info(backPath)
+    print "forwardPath:"
+    uatPathManage.info(forwardPath)
 
 

+ 475 - 0
ssat_sdk/UATree/UAT_focusCommand.py

@@ -0,0 +1,475 @@
+# -*- 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()

+ 11 - 4
ssat_sdk/UATree/UAT_menu.py

@@ -47,9 +47,10 @@ class UATMenu():
     :param optionName 目标option名字
     :param fromFirst 是否固定从firstparent到目标option
     '''
-    def openOption(self, optionName, fromFirst = False):
+    def openOption(self, optionName, fromFirst = False, nextParentName=""):
         option = self.uatRunner.uatPathManage.uatData.getOption(optionName)
-        return self.uatRunner.openOption(option, fromFirst)
+        nextParent = self.uatRunner.uatPathManage.uatData.getParentDict(nextParentName)
+        return self.uatRunner.openOption(option, fromFirst, nextParent)
 
     '''
     进入目标parent,在openOption基础上,增加了后续路过弹窗的无option界面parent。例如:usb的视频播放界面,有弹出提示框,continue或者replay。
@@ -63,7 +64,7 @@ class UATMenu():
     '''
     选中到目标option,如果在option所在页面,直接用moveToOption移动焦点选中,按路径执行选中步骤。
     :param optionName 目标option名字
-    :param value 目标option所设的值
+    :param value 目标option所设的值,若为checkbox,值范围为[True,False],True表示勾选,False表示取消勾选
 	:param exitMenu 执行完以后,是否退出当前菜单
 	:param fromFirst 是否从第一层开始执行(菜单页面是否处于初始状态)
     '''
@@ -119,9 +120,15 @@ class UATMenu():
             vRange = None
         return vRange
 
+
 if __name__ == "__main__":
     uatMenu = UATMenu()
-    print uatMenu.getOptionValueRange("usb_Brightness")
+    # uatMenu.openOption("av_backlight_settings",nextParentName="av_backlight_settings")
+    # uatMenu.openParent("av_backlight_settings")
+
+    uatMenu.setOptionValue("av_backlight",50, fromFirst=True)
+    # uatMenu.setOptionValue("av_picture_mode","av_movie")
+    # print uatMenu.getOptionValueRange("usb_Brightness")
     # obj1 = uatMenu.uatRunner.pyU.getChoosedUIObject("select")
     # print "input:"
     # input()

+ 25 - 9
ssat_sdk/UATree/UAT_runner.py

@@ -44,9 +44,16 @@ class UATRunner():
 
     '''
     根据parent的layout和一个option判断在 UATree中的哪个界面,或者还没有进入UATree界面中
+    :param option:目标option,表示在focusOption的路径上寻找界面定位。则根据excel分表查找
     :return parent数据,或者None。None代表未进入UATree界面中
     '''
-    def locateParentUI(self):
+    def locateParentUI(self, option=None):
+        reg = ""
+        if option is not None:
+            print "locateParentUI,option:",option[UATTree.TAB_NAME]
+            oname = option[UATTree.TAB_NAME]
+            reg = oname.split("_")[0]
+            print "locateParentUI,reg=",reg
         cparent = None
         treeDict = self.uatPathManage.uatData.getTreeDict()
         # print "locateParentUI: treeDict levels:",treeDict.keys()
@@ -58,6 +65,8 @@ class UATRunner():
             # print "locateParentUI,level:", index, level
             levelDict = treeDict[level]
             for parent in levelDict:
+                if reg.__len__() >0 and not parent.startswith(reg):
+                    continue
                 parentDict = levelDict[parent]
                 layout = parentDict["layout"]
                 # print "locateParentUI: layout:", layout
@@ -150,7 +159,7 @@ class UATRunner():
         if flag is False:
             return 0
         info(self.cls, "gotoNextParent", "moveToOption:%s done! executing enter key!"%targetOption[UATTree.TAB_NAME], INFO)
-        ret = self.runnerCmd.executeKey(targetOption[UATTree.TAB_ENTER_KEY])
+        ret = self.runnerCmd.executeEnterKey(targetOption[UATTree.TAB_ENTER_KEY], nextParent=targetParent)
         if ret is False:
             error(self.cls, "gotoNextParent",
                   "Send parent %s enter key fail." % (curParent[UATTree.TAB_NAME]), ERROR)
@@ -200,10 +209,11 @@ class UATRunner():
     count:递归控制变量,执行路径的最大尝试次数
     '''
     def focusOption(self, option, fromFirst, count = 0):
+        info(self.cls, "focusOption", "fromFirst:"+str(fromFirst), INFO)
         if fromFirst is True:
             curParent = None
         else:
-            curParent = self.locateParentUI()
+            curParent = self.locateParentUI(option)
         backPath,forwardPath = self.uatPathManage.genOptionSmartPath(curParent, option)
         info(self.cls,"focusOption", "backPath:", INFO)
         self.uatPathManage.info(backPath)
@@ -253,7 +263,7 @@ class UATRunner():
     '''
     def sendOptionEnterKey(self, option):
         enterKey = option[UATTree.TAB_ENTER_KEY]
-        return self.runnerCmd.executeKey(enterKey)
+        return self.runnerCmd.executeEnterKey(enterKey)
 
     '''
     检查当前页面是否存在目标option
@@ -268,13 +278,13 @@ class UATRunner():
     '''
     在focusOption基础上,执行目标option的enter_key
     '''
-    def openOption(self, option, fromFirst):
+    def openOption(self, option, fromFirst, nextParent = None):
+        info(self.cls, "openOption", "OptionName:"+option[UATTree.TAB_NAME], INFO)
         ret = self.focusOption(option, fromFirst)
         if ret is False:
             return False
-        print "executing enter key"
-        ret = self.runnerCmd.executeKey(option[UATTree.TAB_ENTER_KEY])
-        print "openOption, executeKey:%s"%ret
+        ret = self.runnerCmd.executeEnterKey(option[UATTree.TAB_ENTER_KEY],nextParent)
+        info(self.cls, "openOption", "executeKey,ret:%s"%ret, INFO)
         parent = self.uatPathManage.uatData.getParentDict(option[UATTree.TAB_NAME])
         if parent is None:
             return ret
@@ -286,7 +296,7 @@ class UATRunner():
             return self.openFirstParent(parent, "")
         else:
             prevOption = self.uatPathManage.uatData.getOption(parent[UATTree.TAB_NAME])
-            return self.openOption(prevOption, fromFirst)
+            return self.openOption(prevOption, fromFirst, nextParent=parent)
 
     def setOptionValue(self, option, value, exitMenu=True, fromFirst=True):
         ret = self.openOption(option, fromFirst)
@@ -339,6 +349,12 @@ class UATRunner():
         return infoObj
 
 
+
+
+
+
+
+
 if __name__ == "__main__":
     uatRunner = UATRunner()
     option = uatRunner.uatPathManage.uatData.getOption("usb_video_h264-ac3")

+ 104 - 277
ssat_sdk/UATree/UAT_runnerCommand.py

@@ -10,6 +10,8 @@ from ssat_sdk.sat_environment import getSATTmpDIR
 from ssat_sdk.pic_tool import ImageCMP
 from ssat_sdk.ocr_convert import OCRConvert
 from ssat_sdk.utils.string_util import strcmp, getDigitFromString
+from UAT_valueCommand import ValueCommand
+# from UAT_focusCommand import FocusCommand
 
 import cv2 as cv
 
@@ -32,6 +34,8 @@ class UATRunnerCommand():
         self.CC = CCardManager()
         self.imgCMP = ImageCMP()
         self.ocrConvert = OCRConvert()
+        self.valueCmd = ValueCommand( self)
+        # self.focusCmd = FocusCommand(self)
 
     #检测option组件是不是在电视上显示了
     def checkOptionExist(self, option, parent):
@@ -57,7 +61,7 @@ class UATRunnerCommand():
                                        text=option["optionView"][UATTree.UIView_Text],
                                        description=option["optionView"][UATTree.UIView_Desc]):
                 return True
-            # choosingObj = self.getChooseUIObj(option)
+            # choosingObj = self.focusCmd.getChooseUIObj(option)
             # if lastObj != "":
             #     if choosingObj.info == lastObj.info:
             #         print "choosingObj.info == lastObj.info!!!!"
@@ -78,57 +82,6 @@ class UATRunnerCommand():
 
         return False
 
-    '''
-    检测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 数据字典
@@ -140,146 +93,7 @@ class UATRunnerCommand():
          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
-
-    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
-
-    '''
-    检测某个弹窗是否存在。
-    弹窗相关的参数放在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
-
-
+        return self.focusCmd.checkParentChoose(parent)
 
     def focusTargetOption(self, parent, option):
         if parent[UATTree.TAB_MOVE_KEY][UATTree.Max_Try] != "":
@@ -320,64 +134,8 @@ class UATRunnerCommand():
         print "%s chooseType: %s"%(option["name"], chooseType)
 
         if chooseType.__len__() > 1:
-            if chooseType.lower() == "focus":
-                if viewText != "" and viewId != "":
-                    info(self.cls, "focusTargetOption", "going toDestFocusByText_with_FocuseResourceId, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    info(self.cls, "focusTargetOption", "viewText=%s, focuseResId=%s"%(viewText, focuseViewId), INFO)
-                    return self.fm.toDestFocusByText_with_FocuseResourceId(text=viewText,
-                                                                           focuseResId=viewId,
-                                                                           Max_Try=Max_Try,
-                                                                           keyType=keyType,
-                                                                           hb_keyDict=hb_keyDict)
-
-                elif viewText != "":
-                    info(self.cls, "focusTargetOption", "going toDestFocusByText_for_RecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.toDestFocusByText_for_RecyclerView(text = viewText,
-                                                                   findDirection = findDirection,
-                                                                   Max_Try = Max_Try,
-                                                                   keyType = keyType,
-                                                                   hb_keyDict=hb_keyDict)
-                elif viewId != "":
-                    info(self.cls, "focusTargetOption", "going toDestTargetByResourceId_for_RecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.toDestTargetByResourceId_for_RecyclerView(resourceId = viewId,
-                                                                             chooseType = chooseType.lower(),
-                                                                             Max_Try = Max_Try,
-                                                                             keyType = keyType,
-                                                                             hb_keyDict=hb_keyDict)
-                elif viewDesc != "":
-                    info(self.cls, "focusTargetOption", "going toDestFocusByDescription_for_RecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.toDestFocusByDescription_for_RecyclerView(description=viewDesc,
-                                                                             Max_Try = Max_Try,
-                                                                             keyType = keyType,
-                                                                             hb_keyDict=hb_keyDict)
-                elif viewIndex != "":
-                    info(self.cls, "focusTargetOption", "going focusItemByIndexFromRecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.focusItemByIndexFromRecyclerView(recyclerView_resId = recyclerViewId,
-                                                                    child_class = viewClass,
-                                                                    target_index = viewIndex,
-                                                                    Max_Try = Max_Try,
-                                                                    keyType = keyType,
-                                                                    hb_keyDict=hb_keyDict)
-                else:
-                    error(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " option focus-select属性配置异常", ERROR)
-                    return False
-            elif chooseType.lower() == "select":
-                if viewText != "":
-                    info(self.cls, "focusTargetOption", "going toDestSelectByText_for_RecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.toDestSelectByText_for_RecyclerView(text = viewText,
-                                                                        optionViewResoucreId = viewId,
-                                                                        listViewResourceId = recyclerViewId,
-                                                                        findDirection = findDirection,
-                                                                        Max_Try = Max_Try,
-                                                                        keyType = keyType,
-                                                                        hb_keyDict=hb_keyDict)
-                elif viewId != "":
-                    info(self.cls, "focusTargetOption", "going toDestTargetByResourceId_for_RecyclerView, Option:%s"%option[UATTree.TAB_NAME], INFO)
-                    return self.fm.toDestTargetByResourceId_for_RecyclerView(resourceId = viewId,
-                                                                        chooseType = chooseType.lower(),
-                                                                        Max_Try = Max_Try,
-                                                                        keyType = keyType,
-                                                                        hb_keyDict=hb_keyDict)
+            if chooseType.lower() == "focus" or chooseType.lower() == "select":
+                return self.focusCmd.focusOptionView(parent,option)
             elif chooseType.lower() == "long_click":
                 info(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " going to long click type!!!", info)
                 targetObj = self.pyU.getUiObject(resourceId=viewId)
@@ -390,7 +148,12 @@ class UATRunnerCommand():
                     return False
             elif chooseType.lower() == "no":
                 info(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " 目标Object的chooseType为no,默认为不需要选中。", info)
-                return True
+                retValue = self.checkOptionExist(option,parent)
+                if retValue is True:
+                    return True
+                else:
+                    error(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " option在当前界面不存在", ERROR)
+                    return False
             else:
                 error(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " option focus-select属性配置异常", ERROR)
                 return False
@@ -467,6 +230,32 @@ class UATRunnerCommand():
                     time.sleep(wait)
         return True
 
+    '''
+    用于执行option的EnterKey
+    :param mkeys:option的EnterKey字典
+    :nextParent: option要进入的下一个parent字典,如果parent=None,则进入和option同名的parent。
+    '''
+    def executeEnterKey(self, mkeys, nextParent=None):
+        enterKey = None
+        if nextParent is None:
+            # 不指定nextParent,默认用第一个
+            enterKey = mkeys[0][UATTree.Key_Param]
+        else:
+            # 指定nextParent,根据parentName查找匹配的enterKey
+            enterKey = self.uatPathManage.uatData.UATree.getEKByParent(mkeys, nextParent[UATTree.TAB_NAME])
+            if enterKey is None:
+                error(self.cls,"executeEnterKey","Next parent %s has not enterKey"%nextParent[UATTree.TAB_NAME],ERROR)
+                return True
+        for keyname in enterKey[UATTree.Key_Value]:
+            ret = self.executeKeyByType(keyname,
+                                        enterKey[UATTree.Key_Type],
+                                        times=enterKey[UATTree.Key_Times],
+                                        duration=enterKey[UATTree.Duration_Time])
+            time.sleep(enterKey[UATTree.Wait_Time])
+            if ret is False:
+                return False
+        return True
+
     '''
     执行uatree中的moveKey
     :param mkey move_key的字典
@@ -513,6 +302,7 @@ class UATRunnerCommand():
     根据keyType执行key值
     '''
     def executeKeyByType(self, key, keyType, times = 1, duration = 1.0):
+        info(self.cls, "executeKeyByType", "executeKeyByType key %s, keyType %s, " % (key, keyType), INFO)
         if keyType == UATTree.Key_Event:
             if self.eventKeyCode.has_key(key.upper()):
                 keyCode = self.eventKeyCode[key.upper()]
@@ -571,7 +361,7 @@ class UATRunnerCommand():
             info(self.cls, "executeDialog", "parent %s has %s dialog:%s"%(parent[UATTree.TAB_NAME], type, dialog_A), INFO)
             for dialogName in dialog_A:
                 dialog = dialog_A[dialogName]
-                ret = self.checkDialogExist(dialog)
+                ret = self.focusCmd.checkDialogExist(dialog)
                 if ret < 1:
                     info(self.cls, "executeDialog", "parent %s dialog %s doesnt popup."%(parent[UATTree.TAB_NAME], dialogName), INFO)
                     continue
@@ -580,7 +370,7 @@ class UATRunnerCommand():
                     error(self.cls, "executeDialog", "dialog %s focus choose option %s fail"%(dialogName, tarOption), ERROR)
                     return 0
                 print "executing enter_key"
-                self.executeKey(tarOption[UATTree.TAB_ENTER_KEY])
+                self.executeEnterKey(tarOption[UATTree.TAB_ENTER_KEY])
                 time.sleep(1)
                 # 考虑到弹窗优先级与遍历顺序可能不一致的问题,重新再进行一次弹窗遍历
                 return self.executeDialog(parent, isForward)
@@ -588,20 +378,45 @@ class UATRunnerCommand():
             info(self.cls, "executeDialog", "parent %s has no %s dialog"%(parent[UATTree.TAB_NAME], type), INFO)
         return 1
 
+    '''
+    根据excel表格的enter_key中读取的按键设置checkbox的动作
+    '''
+    def setCheckboxAction(self,option,textValue):
+        info(self.cls, "setCheckboxAction", "textValue:%s" % textValue, INFO)
+        if textValue != "":
+            enterKey = option[UATTree.TAB_ENTER_KEY]
+            return self.executeEnterKey(enterKey)
+        else:
+            error(self.cls, "setCheckboxAction", " Option %s textValue is empty!" % option[UATTree.TAB_NAME], ERROR)
+            return False
+
+    def setCheckbox(self, option, value, currentValue, textValue, resourceId):
+        if currentValue == value:
+            info(self.cls, "setCheckbox", " is %s, no need to change!" % value, INFO)
+        else:
+            self.setCheckboxAction(option,textValue)
+            objInfo = self.pyU.getFocusedUIObject().child(resourceId=resourceId).info  # checkbox的info
+            ifChecked = objInfo['checked']
+            if ifChecked == value:
+                info(self.cls, "setCheckbox", " to %s success!" % value, INFO)
+                return True
+            else:
+                info(self.cls, "setCheckbox", " to %s fail!" % value, INFO)
+                return False
+
     '''
     执行设值动作,区分数字设值以及非数字设值
     '''
     def setValue(self, option, value):
-        textValue = option[UATTree.TAB_TEXT_VALUE]
+        textValue = option[UATTree.TAB_TEXT_VALUE][0]
+        sign = option[UATTree.TAB_TEXT_VALUE][1]
         info(self.cls, "setValue", "textValue:%s"%textValue, INFO)
         if textValue[UATTree.ValueView_Value] != "":
-            enterKey = option[UATTree.TAB_ENTER_KEY]
-            if enterKey[UATTree.Key_Event] != "":
-                keyList = enterKey[UATTree.Key_Event]
-                keyType = UATTree.Key_Event
-            elif enterKey[UATTree.Key_IR] != "":
-                keyList = enterKey[UATTree.Key_IR]
-                keyType = UATTree.Key_IR
+            #EnterKey作为textValue配置中的值设置时的按键,enterKey只能配置一个
+            enterKey = option[UATTree.TAB_ENTER_KEY][0][UATTree.Key_Param]
+            if enterKey[UATTree.Key_Value].__len__() > 0:
+                keyList = enterKey[UATTree.Key_Value]
+                keyType = enterKey[UATTree.Key_Type]
             else:
                 info(self.cls, "setValue", "textValue在有值的情况下,enterKey读取失败,无法进行setValue的动作。", INFO)
                 return False
@@ -620,18 +435,37 @@ class UATRunnerCommand():
                 while(count < 3):
                     # 获取数值时存在两种情况,一种是数值文本在聚焦组件里,一种在聚焦组件之外,分别处理。
                     # 先在聚焦组件内找数值
-                    choosedObj = self.getChooseUIObj(option)
+                    choosedObj = self.focusCmd.getChooseUIObj(option)
                     print "choosedObj.info:", choosedObj.info
                     text = self.getValueInObjectByTextResourceId(choosedObj, valueViewResId)
                     if text is None:
                         # 组件之中找不到时,则直接用resourceId在整个页面找
-                        text = self.getValueByTextResourceId(valueViewResId)
+                        textObj = self.pyU.getUiObject(resourceId=valueViewResId)
+                        text = textObj.info['text']
+                        if text[0] not in sign:
+                            text = self.getValueByTextResourceId(valueViewResId)
+                            text_num = float(text)
+                        else:
+                            if text[0]==sign[0]:
+                                text_num = -float(text.strip(text[0]))
+                            elif text[0]==sign[1]:
+                                text_num = float(text.strip(text[0]))
+                            else:
+                                text_num = float(text)
                         if text is None:
                             error(self.cls, "setValue", "获取数值失败,请检查%s 的textValue resid是否正确"%option[UATTree.TAB_NAME], ERROR)
                             return False
                     info(self.cls, "setValue", "当前设值为%s"%text, INFO)
-                    text_num = float(text)
-                    value_num = float(value)
+                    value = str(value)
+                    if len(sign)!=0:
+                        if value[0]==sign[0]:
+                            value_num = -float(value.strip(value[0]))
+                        elif value[0]==sign[1]:
+                            value_num = float(value.strip(value[0]))
+                        else:
+                            value_num = float(value)
+                    else:
+                        value_num = float(value)
                     if text_num is None:
                         return False
                     if value_num < text_num:
@@ -660,7 +494,7 @@ class UATRunnerCommand():
                     return False
                 else:
                     print "executing enter_key"
-                    return self.executeKey(option[UATTree.TAB_ENTER_KEY])
+                    return self.executeEnterKey(option[UATTree.TAB_ENTER_KEY])
             else:
                 info(self.cls, "setValue", "读取到value参数配置为非数值value,开始进行非数值型value设值。", INFO)
                 try:
@@ -679,7 +513,7 @@ class UATRunnerCommand():
                 while (True):
                     # 获取当前值时存在两种情况,一种是数值文本在聚焦组件里,一种在聚焦组件之外,分别处理。
                     # 先在聚焦组件内找当前值
-                    choosedObj = self.getChooseUIObj(option)
+                    choosedObj = self.focusCmd.getChooseUIObj(option)
                     print "choosedObj.info:", choosedObj.info
                     for i in range(choosedObj.info["childCount"]):
                         childUIObject = choosedObj.child_by_instance(i, resourceId=valueViewResId)
@@ -712,25 +546,18 @@ class UATRunnerCommand():
             optionName = value
             option = self.uatPathManage.uatData.getOption(optionName)
             parent = self.uatPathManage.uatData.getParentByOption(option)
-            ret = self.focusTargetOption(parent, option)
-            if not ret:
-                info(self.cls, "setValue", "未能聚焦至目标value %s,设值失败"%value, INFO)
-                return False
-            info(self.cls, "setValue", "已聚焦至目标value %s"%value, INFO)
-            print "executing enter_key"
-            self.executeKey(option[UATTree.TAB_ENTER_KEY])
-            return True
+            return self.valueCmd.setParentValue(parent, option)
 
     '''
     根据传入路径进行退出菜单的动作。
     顺着传入的parent path,逐个确认当前页面是否为该parent。如果不是该parent,则往path后面继续遍历;如果是该parent,则执行该层parent的toParentKey
     '''
     def exitMenuByPath(self, path):
-        # print "exitMenuByPath path:", path
+        info(self.cls, "exitMenuByPath", "", INFO)
         for i in range(0, path.__len__()):
             parent = path[i]
-            info(self.cls, "exitMenuByPath", "check parent:%s"%parent[UATTree.TAB_NAME], INFO)
             ret = self.checkParentChoose(parent)
+            info(self.cls, "exitMenuByPath", "check parent:%s,ret=%d"%(parent[UATTree.TAB_NAME],ret), INFO)
             if ret < 1:
                 continue
             toParentKey = parent[UATTree.TAB_TOPARENT_KEY]

+ 224 - 24
ssat_sdk/UATree/UAT_tree.py

@@ -1,5 +1,5 @@
 # -*- coding:utf-8 -*-
-import os, sys, time
+import os, sys, time,json
 from collections import OrderedDict
 from ssat_sdk.utils.string_util import strToList
 from UAT_log import error,info,debug
@@ -81,6 +81,7 @@ class UATTree():
     '''
     char为该项参数的括符符号,必须成对带入。默认为中括号[]
     '''
+    #将数据从excel表格里取出来,只返回括号里面的内容
     def parseParam(self, key, params, char = "[]"):
         # 为防止key在其他地方存在相同关键字,添加一个"["做区别
         key = key + char[0]
@@ -96,6 +97,22 @@ class UATTree():
         str2 = str1[i1 + 1: i2]
         return str2.strip()
 
+    def findAllParam(self, key, params,seg="[]"):
+        paramArr = []
+        # for i in range(2):
+        while True:
+            keyIndex = params.find(key)
+            if keyIndex == -1:
+                break
+            endIndex = params.find(seg[1])
+            oneParam = params[keyIndex+key.__len__()+1:endIndex]
+            params = params[endIndex+1:]
+            paramArr.append(oneParam)
+        return paramArr
+
+    '''
+    返回:{key:value,key2:value2,...}
+    '''
     def parseMulParam(self, keyList, params):
         paramDict = {}
         for key in keyList:
@@ -103,6 +120,20 @@ class UATTree():
             paramDict[key] = value
         return paramDict
 
+    '''
+    例如:enter_key,event[]ir[]同时存在多个
+    返回:[[key,value],[key,value],...]
+    '''
+    def parseMulParam_Same(self, keyList, params):
+        mulParam=[]
+        for key in keyList:
+            paramArr = self.findAllParam(key, params)
+            for param in paramArr:
+                keyItem = [key]
+                keyItem.append(param)
+                mulParam.append(keyItem)
+        return mulParam
+
     #KeyDict数据
     Key_AM = "am" #android am命令
     Key_Event = "event" #android KeyEvent
@@ -110,6 +141,9 @@ class UATTree():
     Key_Input = "input" #Android input命令
     Max_Try = "max_try"
     #根据key的字符串,解析出key的字典。格式:am[]event[]ir[]组合
+    '''
+    用于解析move key参数
+    '''
     def parseKey(self, keyStr):
         keyList = [self.Key_AM, self.Key_Event, self.Key_IR, self.Key_Input, self.Max_Try]
         keyDict = self.parseMulParam(keyList, keyStr)
@@ -117,15 +151,93 @@ class UATTree():
         keyDict[self.Key_IR] = strToList(keyDict[self.Key_IR], ",")
         return keyDict
 
+    '''
+    不考虑按键种类,解析按键名、等待时间等参数,enter,wait=1,enterParent=hdmi_settings
+    返回结果:{"keyvalue":[left,right,enter],"wait":'1',"times":"1"}
+    '''
+    def parseKeyParam(self, keyParamStr):
+        paramDict = {self.Key_Value:[],self.Wait_Time:'0', self.Key_Times:'1', self.Duration_Time:'1'}
+        paramArr = strToList(keyParamStr,",")
+        keyValue=[]
+        for param in paramArr:
+            if "=" not in param:
+                keyValue.append(param.strip())
+            else:
+                pArr = strToList(param,"=")
+                paramDict[pArr[0].strip().lower()] = pArr[1].strip()
+        paramDict[self.Key_Value] = keyValue
+        return paramDict
+
+    # enterKeyDict数据
+    Wait_Time = "wait"
+    Duration_Time = "duration"
+    Enter_Parent = "enterparent"
+    Key_Value = "keyvalue"
+    Key_Type = "keytype"
+    Key_Param = "key_param"
+    Key_Times = "times"
+    # 根据key的字符串,解析出key的字典。格式:am[]event[]ir[]组合
+    '''
+    返回值:[{"enterParent":"","key_param":{"keyType","event","keyvalue":[left,right,enter],"wait":1,"enterParent":"hdmi_settings"}}
+    ,...]
+    '''
+    def parseEnterKey(self, keyStr, optionName):
+        keyList = [self.Key_Event, self.Key_IR, self.Key_Input]
+        keyArr = self.parseMulParam_Same(keyList, keyStr)
+        retArr = []
+        for keyItem in keyArr:
+            nextPDict = {} #{"enterParent":"","key_param":{"keyType","event","keyvalue":[left,right,enter],"wait":1,"enterParent":"hdmi_settings"}}
+            keyParamDict = self.parseKeyParam(keyItem[1])
+            keyParamDict[self.Key_Type] = keyItem[0]
+            nextPDict[self.Key_Param] = keyParamDict
+            keyParamDict[self.Wait_Time] = float(keyParamDict[self.Wait_Time])
+            keyParamDict[self.Duration_Time] = float(keyParamDict[self.Duration_Time])
+            keyParamDict[self.Key_Times] = int(keyParamDict[self.Key_Times])
+            if keyParamDict.has_key(self.Enter_Parent) is False:
+                keyParamDict[self.Enter_Parent] = optionName
+            nextPDict[self.Enter_Parent] = keyParamDict[self.Enter_Parent]
+            retArr.append(nextPDict)
+        return retArr
+
     #Android View数据
     View_ID = "resid" #android view resource-id
-    View_Text = "text" #android view 文本内容
+    View_Text = "text" #android view 文本内容。 用于焦点定位,文本组件坐标被焦点组件坐标包含
     View_Desc = "desc" #android view描述
     View_Bounds = "bounds" #android view 坐标
     View_Index = "index"
     View_Class = "class"
+    '''
+    主要用于infoView数据解析
+    '''
     def parseView(self, viewStr):
         keyList = [self.View_ID, self.View_Text, self.View_Desc, self.View_Bounds, self.View_Index, self.View_Class]
+        positionList = [u"left",u"top",u"right",u"bottom"]
+        paramDict = self.parseMulParam(keyList, viewStr)
+        boundsStr = paramDict[self.View_Bounds]
+        if boundsStr != "":
+            i = boundsStr.find(",")
+            if i != -1:
+                boundsList = strToList(boundsStr,",")
+                boundsListToInt = []
+                for bl in boundsList:
+                    bl = int(bl)
+                    boundsListToInt.append(bl)
+        # 将读取出来的列表与positionList合并成为字典,为了与uiautomator viewer相匹配
+            boundsDic = dict(map(lambda x, y: [x, y], positionList, boundsListToInt))
+            paramDict['bounds'] = boundsDic
+
+            ret = paramDict
+            return ret
+        ret = self.parseMulParam(keyList, viewStr)
+        return ret
+		
+    View_sambounds = "sambounds" #采样时的样本坐标,用于和select-focus、focusView的坐标做相对比较,计算相对位置,用于确定是否被选中。
+    '''
+    用于optionView的数据解析
+    '''
+    def parseOptionView(self, viewStr):
+        keyList = [self.View_ID, self.View_Text, self.View_Desc, self.View_Bounds, self.View_Index, self.View_Class
+                   ,self.View_sambounds]
         return self.parseMulParam(keyList, viewStr)
 
     # UI 界面数据
@@ -135,10 +247,8 @@ class UATTree():
     UIView_Text = "text"  # android view 文本内容
     UIView_Desc = "desc"  # android view描述
     UIView_Bounds = "bounds"  # android view 坐标
-
     UIView_Dialog_F = "dialog_forward"  # 进入时可能出现的弹窗
     UIView_Dialog_B = "dialog_back"  # 退出时可能出现的弹窗
-
     def parseUIView(self, viewStr):
         keyList = [self.UIView_Activity, self.UIVIew_Action, self.UIView_ID, self.UIView_Text, self.UIView_Desc,
                    self.UIView_Bounds, self.UIView_Dialog_F, self.UIView_Dialog_B]
@@ -177,40 +287,79 @@ class UATTree():
     Layout_ID = "resid"  # android view resource-id
     Layout_Desc = "desc"  # android view描述
     Layout_Bounds = "bounds"  # android view 坐标
+    Layout_Class = "class" #android view class类型
+    Layout_Limit = "limit" #layout是否限制optionView焦点操作范围。0:不限制,1:限制,默认为0
+    '''
+    layout:各属性值,用于综合确定一个布局组件
+    :return layout 字典:{"resid":"","desc":"","bounds":""}
+    '''
     def parseLayout(self, viewStr):
-        keyList = [self.Layout_ID, self.Layout_Desc, self.Layout_Bounds]
-        return self.parseMulParam(keyList, viewStr)
+        keyList = [self.Layout_ID, self.Layout_Desc, self.Layout_Bounds, self.Layout_Class, self.Layout_Limit]
+        paramDict = self.parseMulParam(keyList, viewStr)
+        if paramDict.has_key(self.Layout_Limit) and paramDict[self.Layout_Limit].__len__()>0:
+            paramDict[self.Layout_Limit] = int(paramDict[self.Layout_Limit]) #字符'0'转数字0
+        return paramDict
 
     #Android FocusView数据
     Focus_ID = "resid" #android view resource-id
     Focus_Text = "text" #android view 文本内容
     Focus_Desc = "desc" #android view描述
+    View_Bounds = "bounds" #android view 坐标
+    View_Class = "class"
     def parseFocus(self, viewStr):
-        keyList = [self.Focus_ID, self.Focus_Text, self.Focus_Desc]
+        keyList = [self.Focus_ID, self.Focus_Text, self.Focus_Desc, self.View_Bounds, self.View_Class,
+                   self.View_sambounds]
         return self.parseMulParam(keyList, viewStr)
 
     #Value数据
     ValueView_ID = "resid" #android view resource-id
     ValueView_Text = "text" #android view 文本内容
     ValueView_Desc = "desc" #android view描述
+    ValueView_Bounds = "bounds"
+    ValueView_Class = "class"
     ValueView_Value = "value"  # 输入的值范围。格式:first, second, ...  或者 0-100
     ValueView_Min = "minvalue" # 如果是数值范围形式的值,返回最小值
     ValueView_Max = "maxvalue" # 如果是数值范围形式的值,返回最小值
     ValueView_StepSize = "stepsize" # 如果是数值范围形式的值,每次调整数值的步长。读不到此参数时,默认为1。
     ValueView_Duration = "duration" # 如果是数值范围形式的值,每次调整数值的间隔时间。读不到此参数时,默认为0.2。
     def parseValueView(self, viewStr):
-        keyList = [self.ValueView_ID, self.ValueView_Text, self.ValueView_Desc, self.ValueView_Value, self.ValueView_StepSize, self.ValueView_Duration]
+        keyList = [self.ValueView_ID, self.ValueView_Text, self.ValueView_Desc, self.ValueView_Value,
+                   self.ValueView_StepSize, self.ValueView_Duration, self.ValueView_Bounds, self.ValueView_Class,
+                   self.View_sambounds]
         paramDict = self.parseMulParam(keyList, viewStr)
         valueStr = paramDict[self.ValueView_Value]
+        sign = []
+        valueListDelStr = []
+        flagList = []
+        flag_v = False # value前缀不为字母
         if valueStr != "":
             i = valueStr.find(",")
             if i != -1:
                 valueList = strToList(valueStr, ",")
                 isRange = False
+
+                # 前缀字母,后缀数字
+                for val in valueList:
+                    if (ord(val[0])>57 or ord(val[0])<48) and (47 < ord(val[1]) < 58):
+                        sign.append(val[0])
+                        valueDelStr = val.strip(val[0])
+                        valueListDelStr.append(valueDelStr)
+                        flagList.append(True)  #value前缀为字母
+                    else:
+                        flagList.append(False)
+                for f in flagList:
+                    flag_v = f
+                    flag_v = flag_v and f
+                if flag_v == False:
+                    sign = []
                 # 处理range类型(数值)
                 try:
                     if valueList.__len__() == 2:
-                        paramDict[self.ValueView_Min] = float(valueList[0])
+                        if flag_v == True: #//
+                            valueList = valueListDelStr
+                            paramDict[self.ValueView_Min] = -float(valueList[0])#//
+                        else:
+                            paramDict[self.ValueView_Min] = float(valueList[0])
                         paramDict[self.ValueView_Max] = float(valueList[1])
                         isRange = True
                 except Exception,ValueError:
@@ -224,15 +373,23 @@ class UATTree():
                         # 读出来的数值未带大括号,需加上大括号,并且json格式化
                         valueView = eval("{%s}" % valueViewStr)
                         paramDict[value] = valueView
-        return paramDict
+        return paramDict,sign
 
-    #focus-select数据
+    #focus-select数据,不仅有select或者focus类型,还有指定组件属性情况,用于处理界面多个聚焦方式出现的场景
     FS_Type = "type"
+    FS_ID = "resid" #android view resource-id
+    FS_Text = "text" #android view 文本内容。
+    FS_Desc = "desc" #android view描述
+    FS_Bounds = "bounds" #android view 坐标
+    FS_Class = "class"
     def parseFocusSelectType(self, fsType):
-        keyList = [self.FS_Type]
+        keyList = [self.FS_Type,self.FS_ID,self.FS_Text,self.FS_Desc,self.FS_Bounds,
+                   self.View_sambounds]
         return self.parseMulParam(keyList, fsType)
 
-
+    '''
+    扫描parent数据行时,要把建立当前parent的prevParent和nextParent关系。
+    '''
     def addParent(self,level, parentName, shortkey, uiview, move_key, toparent_key, layout, others):
         # print "addParent, level,parentName:", level, parentName
         if not self.treeDict.has_key(level):
@@ -250,29 +407,25 @@ class UATTree():
         parentDict[UATTree.TAB_NEXT_PARENT] = {}
         parentDict[UATTree.TAB_OTHERS] = self.parseOthers(others)
         if "first" <> level:
-            prevLevel = self.getPrevLevel(level)
-            prevOption = self.getOpitonInLevel(parentName,prevLevel)
-            if prevOption is None:
-                error(str(self.__class__), "addParent", "Option %s not found in level %s"%(parentName, prevLevel), ERROR)
-            prevParent = self.getParentByOption(prevOption)
+            prevParent = self.getPreParentByParent(parentDict)
             if prevParent is not None:
                 parentDict[UATTree.TAB_PREV_PARENT] = prevParent
                 prevParent[UATTree.TAB_NEXT_PARENT][parentName] = parentDict
-            else:
-                error(str(self.__class__), "addParent", "Option %s's parent not found in level %s"%(parentName, prevLevel), ERROR)
-
         self.treeDict[level][parentName] = parentDict
 
+    '''
+    扫描option行的时候,会把option字典关联到相应的parent字典里
+    '''
     def addOption(self, level, parentName, optionName, optionView, focusSelect, focusView, enterKey, textValue, infoView):
         # print "addOption, level,parentName,optionName:", level, parentName,optionName
         if self.treeDict.has_key(level) and self.treeDict[level].has_key(parentName):
             optionDict = {}
             optionDict[UATTree.TAB_NAME] = optionName
-            optionDict[UATTree.TAB_OPTION_VIEW] = self.parseView(optionView)
+            optionDict[UATTree.TAB_OPTION_VIEW] = self.parseOptionView(optionView)
             optionDict[UATTree.TAB_FOCUS_SELECT] = self.parseFocusSelectType(focusSelect)
             optionDict[UATTree.TAB_FOCUSE_VIEW] = self.parseFocus(focusView)
-            optionDict[UATTree.TAB_ENTER_KEY] = self.parseKey(enterKey)
-            optionDict["textValue"] = self.parseValueView(textValue)
+            optionDict[UATTree.TAB_ENTER_KEY] = self.parseEnterKey(enterKey, optionName)
+            optionDict[UATTree.TAB_TEXT_VALUE] = self.parseValueView(textValue)
             optionDict[UATTree.TAB_INFO_VIEW] = self.parseView(infoView)
             optionDict[UATTree.TAB_PARENT_NAME] = parentName
             optionDict[UATTree.TAB_LEVEL] = level
@@ -344,6 +497,34 @@ class UATTree():
                     return parentDict[UATTree.TAB_OPTION][optionName]
         else:
             return None
+
+    '''
+   检测option的enter_key中是否存在对应parentName
+   '''
+    def checkEnterParentEK(self, enterKey, parentName):
+        # print "checkEnterParentEK,enterKey,parentName:",enterKey, parentName
+        for keyItem in enterKey:
+            if keyItem[self.Enter_Parent] == parentName:
+                return True
+        return False
+    '''
+    检测option字典,是否下一级nextParent包含这一个parentName
+    '''
+    def checkOptionEnterParent(self, option, parentName):
+        enterKey = option[self.TAB_ENTER_KEY]
+        if option[self.TAB_NAME] == parentName:
+            return True
+        return self.checkEnterParentEK(enterKey, parentName)
+
+    '''
+    根据parentName,在EnterKey所有列表中,找到匹配的enterKey字典选项
+    返回值:{"enterParent":"","key_param":{"keyType","event","keyvalue":[left,right,enter],"wait":1,"enterParent":"hdmi_settings"}
+    '''
+    def getEKByParent(self, enterKeys, parentName):
+        for keyItem in enterKeys:
+            if keyItem[self.Enter_Parent] == parentName:
+                return keyItem[self.Key_Param]
+        return None
     '''
     获取option的parent
     '''
@@ -356,6 +537,25 @@ class UATTree():
         else:
             return None
 
+    '''
+    根据Parent数据,查上一级parent。
+    '''
+    def getPreParentByParent(self, parent):
+        prevLevel = self.getPrevLevel(parent[self.TAB_LEVEL])
+        levelDict = self.treeDict[prevLevel]
+        # print "getPreParentByParent,levelDict:",levelDict
+        for parentName in levelDict.keys():
+            parentDict = levelDict[parentName]
+            # print "getPreParentByParent,parentDict:", parentDict
+            for optionName in parentDict[UATTree.TAB_OPTION].keys():
+                option = parentDict[UATTree.TAB_OPTION][optionName]
+                # print "getPreParentByParent,option:", option
+                if self.checkOptionEnterParent(option, parent[self.TAB_NAME]):
+                    return parentDict
+        error(str(self.__class__), "getPreParentByParent",
+              "Parent %s's prevparent not found in level %s"%(parent[self.TAB_NAME], prevLevel), ERROR)
+        return None
+
     '''
     获取当前level的前一个level名
     '''

+ 42 - 0
ssat_sdk/UATree/UAT_valueCommand.py

@@ -0,0 +1,42 @@
+# -*- coding:utf-8 -*-
+from UAT_log import error,info,debug
+from UAT_tree import UATTree
+
+ERROR=True
+INFO = True
+DEBUG = True
+
+'''
+用于处理setOptionValue最后的value值设定。
+有两大类:
+1 利用excel表中的textValue配置,设定界面参数
+2 利用excel表中option的下一级parent,设定选择项
+
+'''
+class ValueCommand():
+    cls = "ValueCommand"
+    def __init__(self, runnerCommand):
+        self.runnerCommand = runnerCommand
+
+    '''
+    在指定的parent页面,选择option。option是参数选项,例如:声音模式设置。
+    av_devices_settings:
+        av_sound_mode:
+            av_sound_Standard
+            av_sound_News
+            av_sound_Movie
+            av_sound_Game
+            av_sound_Custom
+    :param value:parent下的optionName
+    :param executeEnterKey: 传进来执行enterKey的函数
+    :return 返回True/False。True:设置成功,False:设置失败
+    '''
+    def setParentValue(self, parent, option):
+        ret = self.runnerCommand.focusTargetOption(parent, option)
+        if not ret:
+            info(self.cls, "setValue", "未能聚焦至目标value %s,设值失败" % option[UATTree.TAB_NAME], INFO)
+            return False
+        info(self.cls, "setValue", "已聚焦至目标value %s" % option[UATTree.TAB_NAME], INFO)
+        print "executing enter_key"
+        self.runnerCommand.executeEnterKey(option[UATTree.TAB_ENTER_KEY])
+        return True

+ 470 - 91
ssat_sdk/python_uiautomator.py

@@ -41,7 +41,7 @@ self.pyUIAutomator = PyUIAutomator()
 class PyUIAutomator():
     def __init__(self, serial=None):
         try:
-            self.u = u2.connect_usb(serial)
+            self.u = u2.connect_usb(serial) #得到UIAutomatorServer实例对象
             self.serial = serial
         except Exception,e:
             print e
@@ -98,6 +98,18 @@ class PyUIAutomator():
         self.listenAdbConnected()
         self.u.pressKeyTimes(key, times, duration)
 
+    '''
+    用uiautomator view属性键作为paramDIct的键,传入的paramDict里的参数,必须有效。
+    参考session.Selector里的__fields字典
+    '''
+    def getUiObject2(self, paramDict):
+        # print "getUiObject2,paramDict:",paramDict
+        uiObject = None
+        if paramDict.__len__>0:
+            uiObject = self.u(**paramDict)
+            # print uiObject,uiObject.info
+        return uiObject
+
     '''
     作用:获取UiObject对象
     参数:
@@ -120,7 +132,7 @@ class PyUIAutomator():
 
     '''
 
-    def getUiObject(self, className='', resourceId='', text='', description='', instance=-1):
+    def getUiObject(self, className='', resourceId='', text='', description='', bounds='', instance=-1):
         self.listenAdbConnected()
         # print 'className:', className
         # print 'resourceId:', resourceId
@@ -131,117 +143,260 @@ class PyUIAutomator():
         uiObject = None
         try:
 
-            if className == "" and resourceId == "" and text == "" and description == "" and instance == -1:
+            if className == "" and resourceId == "" and text == "" and description == "" and \
+                    bounds == "" and instance == -1:
                 print "没有参数带入,找不到对象"
                 return uiObject
 
-            if className != "" and resourceId != "" and text != "" and description != "" and instance != -1:
+            if className != "" and resourceId != "" and text != "" and description != "" and \
+                    bounds != "" and instance != -1:
                 uiObject = self.u(className=className, resourceId=resourceId, text=text, description=description,
-                                  instance=instance)
+                                  bounds=bounds, instance=instance)
             # 缺少一个元素的
-            if className != "" and resourceId != "" and text != "" and description != "" and instance == -1:
-                uiObject = self.u(className=className, resourceId=resourceId, text=text, description=description)
-
-            if className != "" and resourceId != "" and text != "" and description == "" and instance != -1:
-                uiObject = self.u(className=className, resourceId=resourceId, text=text, instance=instance)
-
-            if className != "" and resourceId != "" and text == "" and description != "" and instance != -1:
+            # 缺instance
+            if className != "" and resourceId != "" and text != "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text, bounds=bounds,
+                                  description=description)
+            # 缺bounds
+            if className != "" and resourceId != "" and text != "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text,
+                                  description=description, instance=instance)
+            # 缺description
+            if className != "" and resourceId != "" and text != "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text,
+                                  bounds=bounds, instance=instance)
+            # 缺text
+            if className != "" and resourceId != "" and text == "" and description != "" and \
+                    bounds != "" and instance != -1:
                 uiObject = self.u(className=className, resourceId=resourceId, description=description,
-                                  instance=instance)
-
-            if className != "" and resourceId == "" and text != "" and description != "" and instance != -1:
+                                  bounds=bounds, instance=instance)
+            # 缺resouceId
+            if className != "" and resourceId == "" and text != "" and description != "" and \
+                    bounds != "" and instance != -1:
                 uiObject = self.u(className=className, text=text, description=description,
-                                  instance=instance)
-
-            if className == "" and resourceId != "" and text != "" and description != "" and instance != -1:
+                                  bounds=bounds, instance=instance)
+            # lack of className
+            if className == "" and resourceId != "" and text != "" and description != "" and \
+                    bounds != "" and instance != -1:
                 uiObject = self.u(resourceId=resourceId, text=text, description=description,
-                                  instance=instance)
+                                  bounds=bounds, instance=instance)
 
             # 缺少两个元素的
-            if className == "" and resourceId == "" and text != "" and description != "" and instance != -1:
-                uiObject = self.u(text=text, description=description,
+            # lack of className and resourceId
+            if className == "" and resourceId == "" and text != "" and description != "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(text=text, description=description, bounds=bounds,
                                   instance=instance)
-
-            if className == "" and resourceId != "" and text == "" and description != "" and instance != -1:
-                uiObject = self.u(resourceId=resourceId, description=description,
+            # lack of className and text
+            if className == "" and resourceId != "" and text == "" and description != "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, description=description, bounds=bounds,
                                   instance=instance)
-
-            if className == "" and resourceId != "" and text != "" and description == "" and instance != -1:
-                uiObject = self.u(resourceId=resourceId, text=text,
+            # lack of className and description
+            if className == "" and resourceId != "" and text != "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, text=text, bounds=bounds,
                                   instance=instance)
-
-            if className == "" and resourceId != "" and text != "" and description != "" and instance == -1:
-                uiObject = self.u(resourceId=resourceId, text=text, description=description)
-
-            if className != "" and resourceId == "" and text == "" and description != "" and instance != -1:
-                uiObject = self.u(className=className, description=description,
+            # lack of className and bounds
+            if className == "" and resourceId != "" and text != "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, text=text, description=description,
                                   instance=instance)
-
-            if className != "" and resourceId == "" and text != "" and description == "" and instance != -1:
-                uiObject = self.u(className=className, text=text,
+            # lack of className and instance
+            if className == "" and resourceId != "" and text != "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(resourceId=resourceId, text=text, description=description,
+                                  bounds=bounds)
+            # lack of resourceId and text
+            if className != "" and resourceId == "" and text == "" and description != "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(className=className, description=description, bounds=bounds,
                                   instance=instance)
-
-            if className != "" and resourceId != "" and text == "" and description != "" and instance == -1:
-                uiObject = self.u(className=className, text=text, description=description)
-            if className != "" and resourceId != "" and text == "" and description == "" and instance != -1:
+            # lack of resourceId and description
+            if className != "" and resourceId == "" and text != "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(className=className, text=text, bounds=bounds,
+                                  instance=instance)
+            # lack of resourceId and bounds
+            if className != "" and resourceId != "" and text == "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, text=text, description=description,
+                                  instance=instance)
+            # lack of resourceId and instance
+            if className != "" and resourceId == "" and text != "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, text=text, description=description,
+                                  bounds=bounds)
+            # lack of text and description
+            if className != "" and resourceId != "" and text == "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(className=className, resourceId=resourceId, bounds=bounds,
+                                  instance=instance)
+            # lack of text and bounds
+            if className != "" and resourceId != "" and text == "" and description != "" and \
+                    bounds == "" and instance != -1:
                 uiObject = self.u(className=className, resourceId=resourceId,
+                                  description=description, instance=instance)
+            # lack of text and instance
+            if className != "" and resourceId != "" and text == "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, resourceId=resourceId,
+                                  description=description, bounds=bounds)
+            # lack of description and bounds
+            if className != "" and resourceId != "" and text != "" and description == "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text,
                                   instance=instance)
+            # lack of description and instance
+            if className != "" and resourceId != "" and text != "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text,
+                                  bounds=bounds)
+            # lack of bounds and instance
+            if className != "" and resourceId != "" and text != "" and description != "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(className=className, resourceId=resourceId, text=text,
+                                  description=description)
 
-            if className != "" and resourceId != "" and text == "" and description == "" and instance != -1:
-                uiObject = self.u(className=className, resourceId=resourceId, description=description)
-
-            if className != "" and resourceId != "" and text != "" and description == "" and instance == -1:
+            # 缺少3个元素
+            # lack of className and resourceId and text
+            if className == "" and resourceId == "" and text == "" and description != "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(description=description, bounds=bounds, instance=instance)
+            # lack of className and resourceId and description
+            if className == "" and resourceId == "" and text != "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(text=text, bounds=bounds, instance=instance)
+            # lack of className and resourceId and bounds
+            if className == "" and resourceId == "" and text != "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(text=text, description=description, instance=instance)
+            # lack of className and resourceId and instance
+            if className == "" and resourceId == "" and text != "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(text=text, description=description, bounds=bounds)
+            # lack of className and text and description
+            if className == "" and resourceId != "" and text == "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, bounds=bounds, instance=instance)
+            # lack of className and text and bounds
+            if className == "" and resourceId != "" and text == "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, description=description, instance=instance)
+            # lack of className and text and instance
+            if className == "" and resourceId != "" and text == "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(resourceId=resourceId, description=description, bounds=bounds)
+            # lack of className and description and bounds
+            if className == "" and resourceId != "" and text != "" and description == "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(resourceId=resourceId, text=text, instance=instance)
+            # lack of className and description and instance
+            if className == "" and resourceId != "" and text != "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(resourceId=resourceId, text=text, bounds=bounds)
+            # lack of resourceId and text and description
+            if className != "" and resourceId == "" and text == "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(className=className, bounds=bounds, instance=instance)
+            # lack of resourceId and text and bounds
+            if className != "" and resourceId == "" and text == "" and description != "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, description=description, instance=instance)
+            # lack of resourceId and text and instance
+            if className != "" and resourceId == "" and text == "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, description=description, bounds=bounds)
+            # lack of resourceId and description and bounds
+            if className != "" and resourceId == "" and text != "" and description == "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, text=text, instance=instance)
+            # lack of resourceId and description and instance
+            if className != "" and resourceId == "" and text != "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, text=text, bounds=bounds)
+            # lack of resourceId and bounds and instance
+            if className != "" and resourceId == "" and text != "" and description != "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(className=className, text=text, description=description)
+            # lack of text and description and bounds
+            if className != "" and resourceId != "" and text == "" and description == "" and \
+                    bounds == "" and instance != -1:
+                uiObject = self.u(className=className, resourceId=resourceId, instance=instance)
+            # lack of text and description and instance
+            if className != "" and resourceId != "" and text == "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, resourceId=resourceId, bounds=bounds)
+            # lack of description and bounds and instance
+            if className != "" and resourceId != "" and text != "" and description == "" and \
+                    bounds == "" and instance == -1:
                 uiObject = self.u(className=className, resourceId=resourceId, text=text)
 
-            # 缺少3个元素
-            if className == "" and resourceId == "" and text == "" and description != "" and instance != -1:
+            # 缺少4个元素
+            # lack of className and resourceId and text and description
+            if className == "" and resourceId == "" and text == "" and description == "" and \
+                    bounds != "" and instance != -1:
+                uiObject = self.u(bounds=bounds, instance=instance)
+            # lack of className and resourceId and text and bounds
+            if className == "" and resourceId == "" and text == "" and description != "" and \
+                    bounds == "" and instance != -1:
                 uiObject = self.u(description=description, instance=instance)
-
-            if className == "" and resourceId == "" and text != "" and description == "" and instance != -1:
+            # lack of className and resourceId and text and instance
+            if className == "" and resourceId == "" and text == "" and description != "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(description=description, bounds=bounds)
+            # lack of className and resourceId and description and bounds
+            if className == "" and resourceId == "" and text != "" and description == "" and \
+                    bounds == "" and instance != -1:
                 uiObject = self.u(text=text, instance=instance)
-
-            if className == "" and resourceId == "" and text != "" and description != "" and instance == -1:
-                uiObject = self.u(text=text, description=description)
-
-            if className == "" and resourceId != "" and text == "" and description == "" and instance != -1:
-                uiObject = self.u(resourceId=resourceId, instance=instance)
-
-            if className == "" and resourceId != "" and text == "" and description != "" and instance == -1:
-                uiObject = self.u(resourceId=resourceId, description=description)
-
-            if className == "" and resourceId != "" and text != "" and description == "" and instance == -1:
-                uiObject = self.u(resourceId=resourceId, text=text)
-
-            if className != "" and resourceId == "" and text == "" and description == "" and instance != -1:
+            # lack of className and resourceId and description and instance
+            if className == "" and resourceId == "" and text != "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(text=text, bounds=bounds)
+            # lack of resourceid and text and description and bounds
+            if className != "" and resourceId == "" and text == "" and description == "" and \
+                    bounds == "" and instance != -1:
                 uiObject = self.u(className=className, instance=instance)
-
-            if className != "" and resourceId == "" and text == "" and description != "" and instance == -1:
-                uiObject = self.u(className=className, description=description)
-
-            if className != "" and resourceId == "" and text != "" and description == "" and instance == -1:
-                uiObject = self.u(className=className, text=text)
-
-            if className != "" and resourceId != "" and text == "" and description == "" and instance == -1:
+            # lack of resourceid and text and description and instance
+            if className != "" and resourceId == "" and text == "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(className=className, bounds=bounds)
+            # lack of text and description and bounds and instance
+            if className != "" and resourceId != "" and text == "" and description == "" and \
+                    bounds == "" and instance == -1:
                 uiObject = self.u(className=className, resourceId=resourceId)
 
-            # 缺少4个元素
-            if className == "" and resourceId == "" and text == "" and description == "" and instance != -1:
-                uiObject = self.u(instance=instance)
-
-            if className == "" and resourceId == "" and text == "" and description != "" and instance == -1:
-                uiObject = self.u(description=description)
-
-            if className == "" and resourceId == "" and text != "" and description == "" and instance == -1:
-                uiObject = self.u(text=text)
-
-            if className == "" and resourceId != "" and text == "" and description == "" and instance == -1:
-                uiObject = self.u(resourceId=resourceId)
-
-            if className != "" and resourceId == "" and text == "" and description == "" and instance == -1:
+            # 缺少5个元素的
+            # only className
+            if className != "" and resourceId == "" and text == "" and description == "" and \
+                    bounds == "" and instance == -1:
                 uiObject = self.u(className=className)
+            # only resourceid
+            if className == "" and resourceId != "" and text == "" and description == "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(resourceId=resourceId)
+            # only text
+            if className == "" and resourceId == "" and text != "" and description == "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(text=text)
+            # only description
+            if className == "" and resourceId == "" and text == "" and description != "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(description=description)
+            # only bounds
+            if className == "" and resourceId == "" and text == "" and description == "" and \
+                    bounds != "" and instance == -1:
+                uiObject = self.u(bounds=bounds)
+            # only instance
+            if className == "" and resourceId == "" and text == "" and description == "" and \
+                    bounds == "" and instance == -1:
+                uiObject = self.u(instance=instance)
             return uiObject
         except Exception, e:
-            print e
+            print "异常:",e
             return uiObject
 
     ''' 
@@ -438,12 +593,11 @@ class PyUIAutomator():
             print e
 
     '''
-          作用:根据传入的chooseType,获取当前界面聚焦的对象
-          参数:
-          注意:
-          例子:self.pyUIAutomator.getChoosedUIObject("focus")
-       '''
-
+      作用:根据传入的chooseType,获取当前界面聚焦的对象
+      参数:
+      注意:
+      例子:self.pyUIAutomator.getChoosedUIObject("focus")
+    '''
     def getChoosedUIObject(self, chooseType, resourceId='', text=''):
         if chooseType.lower() == "focus":
             return self.getFocusedUIObject(resourceId=resourceId, text=text)
@@ -1095,6 +1249,230 @@ class FocusManageAndroid():
         print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
         return False
 
+    # zhouyi
+        # 在RecyclerView 中 focused控件包含bounds控件
+    def toDestFocusByBounds_for_RecyclerView(self, bounds, boundsResourceId="", findDirection="down",
+                                             Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
+        # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
+        count = 0
+        Max_Try = Max_Try
+        Reversecount = 0
+        Reverse_Max_Try = Max_Try * 2
+        while (True):
+            print "count:", count
+            if count >= Max_Try and Reversecount >= Reverse_Max_Try:
+                break
+            # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
+            time.sleep(0.5)
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            focusedUIObject = self.u.getFocusedUIObject()
+            focusedBounds = focusedUIObject.info['bounds']
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            try:
+                destBounds = bounds
+                if self.directionManageAndroid.isHasAnotherBounds(focusedBounds,destBounds):
+                    print "success to focus the target:",bounds
+                    return True
+                else:
+                    count = count + 1
+                    direction = self.directionManageAndroid.getTargetDirection(focusedBounds,destBounds)
+                    self.directionManageAndroid.goOneStep(self.u,direction,keyType)
+            except Exception,e:
+                # 出现控件出现一半的时候,获取控件信息会报错
+                if count < Max_Try:
+                    count = count + 1
+                    self.pressKeyByType(findDirection, keyType)
+                else:
+                    Reversecount = Reversecount + 1
+                    self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+                # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
+            else:
+                if count < Max_Try:
+                    count = count + 1
+                    self.pressKeyByType(findDirection, keyType)
+                else:
+                    Reversecount = Reversecount + 1
+                    self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+
+            print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
+            return False
+
+    # class&Bounds
+    def toDestFocusByClassBounds_for_RecyclerView(self, className, bounds,classResourceId="", findDirection="down",
+                                             Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
+        # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
+        count = 0
+        Max_Try = Max_Try
+        Reversecount = 0
+        Reverse_Max_Try = Max_Try * 2
+        while (True):
+            print "count:", count
+            if count >= Max_Try and Reversecount >= Reverse_Max_Try:
+                break
+            # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
+            time.sleep(0.5)
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            focusedUIObject = self.u.getFocusedUIObject()
+            print "zhouyifocusedUIObject",focusedUIObject
+            print "zhouyifocusedUIObject.info", focusedUIObject.info
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            destUIObject = self.u.getUiObject(className=className, bounds = bounds,resourceId=classResourceId)
+            print "destUIObject",destUIObject
+            try:
+                destUIObjectInfo = destUIObject.info
+                print "destUIObjectInfo",destUIObjectInfo
+            except Exception,e:
+                print "异常:",e
+                # print "destUIObject.info",destUIObjectInfo
+            try:
+                # destBounds = destUIObject.info['bounds']
+                destBounds = bounds
+                print "destBounds:", destBounds
+                if self.directionManageAndroid.isHasAnotherBounds(focusedBounds,destBounds):
+                    print "c&b success to focus the target:",bounds
+                    return True
+                else:
+                    count = count + 1
+                    direction = self.directionManageAndroid.getTargetDirection(focusedBounds,destBounds)
+                    self.directionManageAndroid.goOneStep(self.u,direction,keyType)
+            except Exception,e:
+                # 出现控件出现一半的时候,获取控件信息会报错
+                if count < Max_Try:
+                    count = count + 1
+                    self.pressKeyByType(findDirection, keyType)
+                else:
+                    Reversecount = Reversecount + 1
+                    self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+                # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
+            else:
+                if count < Max_Try:
+                    count = count + 1
+                    self.pressKeyByType(findDirection, keyType)
+                else:
+                    Reversecount = Reversecount + 1
+                    self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+
+            print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
+            return False
+
+        # class
+        def toDestFocusByClass_for_RecyclerView(self, className, classResourceId="", findDirection="down",
+                                                Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
+            # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
+            count = 0
+            Max_Try = Max_Try
+            Reversecount = 0
+            Reverse_Max_Try = Max_Try * 2
+            while (True):
+                print "count:", count
+                if count >= Max_Try and Reversecount >= Reverse_Max_Try:
+                    break
+                # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
+                time.sleep(0.5)
+                if hb_keyDict != {}:
+                    # 执行心跳按键
+                    self.executeHeartBeatKey(hb_keyDict)
+                focusedUIObject = self.u.getFocusedUIObject()
+                print "zhouyifocusedUIObject", focusedUIObject
+                print "zhouyifocusedUIObject.info", focusedUIObject.info
+                if hb_keyDict != {}:
+                    # 执行心跳按键
+                    self.executeHeartBeatKey(hb_keyDict)
+                destUIObject = self.u.getUiObject(className=className, resourceId=classResourceId)
+                print "destUIObject", destUIObject
+                try:
+                    destUIObjectInfo = destUIObject.info
+                    print "destUIObjectInfo", destUIObjectInfo
+                except Exception, e:
+                    print "异常:", e
+                    # print "destUIObject.info",destUIObjectInfo
+                try:
+                    destBounds = destUIObject.info['bounds']
+                    print "destBounds:", destBounds
+                    if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
+                        print '成功聚焦到目标焦点:', bounds
+                        return True
+                    else:
+                        count = count + 1
+                        direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
+                        self.directionManageAndroid.goOneStep(self.u, direction, keyType)
+                except Exception, e:
+                    # 出现控件出现一半的时候,获取控件信息会报错
+                    if count < Max_Try:
+                        count = count + 1
+                        self.pressKeyByType(findDirection, keyType)
+                    else:
+                        Reversecount = Reversecount + 1
+                        self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+                    # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
+                else:
+                    if count < Max_Try:
+                        count = count + 1
+                        self.pressKeyByType(findDirection, keyType)
+                    else:
+                        Reversecount = Reversecount + 1
+                        self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
+
+                print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
+                return False
+
+
+
+    # zhouyi
+    def toDestTargetByBounds_for_RecyclerView(self, bounds, chooseType, Max_Try=20,
+                                              keyType=UATTree.Key_Event, findFocusCount=0, hb_keyDict={}):
+        count = 0
+        while (True):
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            # targetUIObject = self.u.getUiObject(bounds=bounds)
+            # print "targetUIObject",targetUIObject
+            # print "zhouyibounds",bounds
+            # print "targetUIObject.info:", targetUIObject.info
+            # destBounds = targetUIObject.info['bounds']
+            destBounds = bounds
+            print "目标坐标:", destBounds
+            if hb_keyDict != {}:
+                # 执行心跳按键
+                self.executeHeartBeatKey(hb_keyDict)
+            try:
+                if chooseType.lower() == "focus":
+                    choosingUIObject = self.u.getFocusedUIObject()
+                    objBounds = choosingUIObject.info['bounds']
+                elif chooseType.lower() == "select":
+                    choosingUIObject = self.u.getSelectedUIObject()
+                    objBounds = choosingUIObject.info['bounds']
+                print "当前坐标:", objBounds
+            except Exception, e:
+                print "获取焦点失败!Error:", e
+                if findFocusCount < 3:
+                    self.u.pressKeyTimes("down")
+                    return self.toDestTargetByBounds_for_RecyclerView(bounds, chooseType,
+                                                                      findFocusCount=findFocusCount + 1)
+                else:
+                    print "尝试%s次操作!!!仍未能找到聚焦点!!!无法聚焦到目标" % findFocusCount
+                    return False
+            if self.directionManageAndroid.isHasAnotherBounds(objBounds, destBounds):
+                print "已聚焦至目标组件!!!"
+                return True
+            else:
+                if count >= Max_Try:
+                    print "已尝试至最大次数%s次,仍未能聚焦至目标组件!!!" % Max_Try
+                    return False
+                direction = self.directionManageAndroid.getTargetDirection(objBounds, destBounds)
+                print "目标方位:", direction
+                self.directionManageAndroid.goOneStep(self.u, direction, keyType)
+                count += 1
+
     ''' 
                  作用:在界面中 中 focused控件中既没有包含content-des控件属性,也没有text控件属性,
                        采用单张图片模板匹配  用于聚焦目标焦点
@@ -1881,6 +2259,7 @@ class FocusManageAndroid():
 
 
     def pressKeyByType(self, keyName, keyType = UATTree.Key_Event, times = 1, duration = 1.0):
+        print "pressKeyByType:",keyName,keyType
         if keyType == UATTree.Key_Event:
             return self.u.pressKeyTimes(keyName, times, duration)
         elif keyType == UATTree.Key_IR:

+ 12 - 3
ssat_sdk/result_tool.py

@@ -27,6 +27,9 @@ class ResultTool(ProcessSync):
     Key_ItemScreen = "item_screen"
     Key_ItemLog = "item_log"
 
+    File_Name = "unknown"
+
+
     def __init__(self, resultxml = "all-result.xml"):
         print "Init ResultTool"
         ProcessSync.__init__(self)
@@ -45,6 +48,11 @@ class ResultTool(ProcessSync):
         self.detailItemIndex = itemIndex
         runner_sender.sendActionStart(self.tc.name, self.detailItemIndex, itemName, itemDesc)
 
+    # 通过Script_Activity告诉ResultTool,当前脚本名,用于拼接结果文件保存路径
+    @staticmethod
+    def setFileName(fileName):
+        ResultTool.File_Name = fileName
+
     @staticmethod
     def checkResultDIR():
         ResultTool.mkCHdir(ResultTool.Result_DIR)
@@ -82,9 +90,9 @@ class ResultTool(ProcessSync):
         print "updateBaseDir,dir=",dir
         ResultTool.Result_DIR = unicode(dir)
         ResultTool.Result_DIR_DETAIL = ResultTool.Result_DIR + "/" + ResultTool.Result_DETAIL
-        ResultTool.Result_DIR_LOG = ResultTool.Result_DIR + "/log"
-        ResultTool.Result_DIR_SCREEN = ResultTool.Result_DIR + "/screen"
-        ResultTool.Result_DIR_SCRIPTS = ResultTool.Result_DIR + "/scripts"
+        ResultTool.Result_DIR_LOG = ResultTool.Result_DIR + "/adb_log/" + ResultTool.File_Name
+        ResultTool.Result_DIR_SCREEN = ResultTool.Result_DIR + "/screen/" + ResultTool.File_Name
+        ResultTool.Result_DIR_SCRIPTS = ResultTool.Result_DIR + "/scripts/" + ResultTool.File_Name
         ResultTool.checkResultDIR()
         ResultTool.copyInitFile()
 
@@ -92,6 +100,7 @@ class ResultTool(ProcessSync):
     def setBaseDir(dir):
         setResultDir(dir)
 
+
     def getBaseDir(self):
         return ResultTool.Result_DIR
 

+ 46 - 4
ssat_sdk/sat_environment.py

@@ -253,10 +253,17 @@ def getSATHome():
         print e
         return ""
 
+def getScriptExecDIR():
+    satHome = getSATHome()
+    return os.path.join(satHome, "ScriptExec")
 
 def getSATTmpDIR():
-    satHome = getSATHome()
-    return os.path.join(satHome, "tmp")
+    path = g_cfgParser.get_value("COMM", "sat_tmp")
+    if path is None:
+        satHome = getSATHome()
+        return os.path.join(satHome, "tmp")
+    else:
+        return path
 
 
 def getSATTranslationDIR():
@@ -385,6 +392,7 @@ def getAbnormalDir():
 def initDirs():
     print mkCHdir(getSATHome())
     print mkCHdir(getResourceBaseDIR())
+    print mkCHdir(getScriptExecDIR())
     print mkCHdir(getSATTmpDIR())
     print mkCHdir(getSATMenuTreeDIR())
     print mkCHdir(getHDMIResourceDIR())
@@ -423,6 +431,12 @@ def setSATHome(dir):
     except Exception, e:
         print e
 
+def setSATTmpDir(dir):
+    try:
+        g_cfgParser.set_value("COMM", "sat_tmp", dir)
+        # g_cfgParser.write(open(Resource_CFG_Path, "w"))
+    except Exception, e:
+        print e
 
 def setResultDir(dir):
     try:
@@ -432,6 +446,15 @@ def setResultDir(dir):
         print e
 
 
+
+def setScriptResultDIR(dir):
+    try:
+        g_cfgParser.set_value("COMM", "sat_script_dir", dir)
+        # g_cfgParser.write(open(Resource_CFG_Path, "w"))
+    except Exception, e:
+        print e
+
+
 def getUB530_Port():
     return g_cfgParser.get_value("COMM", "ub530_port")
 
@@ -855,19 +878,38 @@ def writeSoundList(sound_list):
 def getOtaParamUrl_dict():
     return eval(g_cfgParser.get_value("URL", "getParam"))
 
+'''
+adb设备可用或不可用状态;
+return ture:可用,false:不可用
+'''
 def getAdbDeviceSatatus():
     Online = "Online"
     options = g_cfgParser.get_options("ADBSTATUS")
-    print "getAdbDeviceSatatus,options:",options
+    # print "getAdbDeviceSatatus,options:",options
     if options is None:
         return False
     for option in options:
         status = g_cfgParser.get_value("ADBSTATUS",option)
-        print "getAdbDeviceSatatus,%s:"%option, status
+        # print "getAdbDeviceSatatus,%s:"%option, status
         if status == Online:
             return True
     return False
 
+'''
+获取adb设备状态描述
+return: none表示没有这个设备,Unauthorized表示设备未授权,offline表示设备离线,online表示在线可用
+'''
+def getAdbDevSTDesc():
+    Online = "Online"
+    options = g_cfgParser.get_options("ADBSTATUS")
+    # print "getAdbDeviceSatatus,options:",options
+    if options is None:
+        return "none"
+    for option in options:
+        status = g_cfgParser.get_value("ADBSTATUS", option)
+        return status
+    return "none"
+
 
 if __name__ == "__main__":
     dict = getOtaParamUrl_dict()

+ 29 - 9
ssat_sdk/sound/audio_recorder.py

@@ -98,17 +98,37 @@ class ARecorder():
             self.CHUNK = int(self.RATE * buf_time)
         self.frameBufMax = timeL * (self.RATE/self.CHUNK)
         self.frameBufDel = 1*(self.RATE/self.CHUNK) #前1秒录取的音频,需要删掉,采集的音频不准。
-        self.pyaudio = pyaudio.PyAudio()
-        LoggingUtil.printLog(TAG,self.pyaudio.get_default_input_device_info())
-        self.pyStream = self.pyaudio.open(rate=self.RATE,
-                              channels=self.CHANNELS,
-                              format=self.FORMAT,
-                              input=True,
-                              frames_per_buffer=self.CHUNK,
-                              stream_callback=self.streamCallBack)
+        tryMax = 6
+        audioEnable = False
+        while tryMax > 0:#在音频设备启动失败时,尝试6次,每次间隔0.5秒
+            tryMax -= 1
+            try:
+                self.pyaudio = pyaudio.PyAudio()
+                LoggingUtil.printLog(TAG,self.pyaudio.get_default_input_device_info())
+                self.pyStream = self.pyaudio.open(rate=self.RATE,
+                                      channels=self.CHANNELS,
+                                      format=self.FORMAT,
+                                      input=True,
+                                      frames_per_buffer=self.CHUNK,
+                                      stream_callback=self.streamCallBack)
+                LoggingUtil.printLog("AudioRecorder monitor, device init success!")
+                audioEnable = True
+                break
+            except Exception,e:
+                audioEnable = False
+                LoggingUtil.printLog("AudioRecorder monitor, Error:"+e.message)
+                if self.pyStream is not None:
+                    self.pyStream.close()
+                    self.pyStream = None
+                if self.pyaudio is not None:
+                    self.pyaudio.terminate()
+                    self.pyaudio = None
+                time.sleep(0.5)
+        if audioEnable is False:
+            return
         self.initRecordStatus(saveWave)
-        self.pyStream.start_stream()
         LoggingUtil.printLog("Record sound....")
+        self.pyStream.start_stream()
         self.recordLock.wait() #等待录音结束
         self.recordLock.release()
         LoggingUtil.printLog("Record sound End")

+ 1 - 0
ssat_sdk/sound_tool.py

@@ -298,6 +298,7 @@ class AudioIdentify():
 if __name__ == "__main__":
     aIden = AudioIdentify()
     aIden.monitorSound(5)
+    time.sleep(1)
     # sound1 = "D:/1.wav"
     # sound2 = "D:/2.wav"
     # list1=[]