UAT_focusCommand.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. # -*- coding:utf-8 -*-
  2. import time,sys,os
  3. from UAT_tree import UATTree
  4. from UAT_log import error,info,debug
  5. from UAT_PathManage import UATPathManage
  6. from UIParamUtil import UIParamUtil
  7. # from UAT_runnerCommand import UATRunnerCommand
  8. from ssat_sdk.python_uiautomator import PyUIAutomator,DirectionManageAndroid,FocusManageAndroid
  9. import math
  10. import traceback
  11. import copy
  12. ERROR = True
  13. INFO = True
  14. DEBUG = True # 上传SVN版本此参数关闭
  15. '''
  16. 采用uiautomator技术,处理界面定位问题,用于移动焦点到目标组件上
  17. '''
  18. class FocusCommand():
  19. cls = "FocusCommand"
  20. UIObjParam = UIParamUtil.UIObjParam
  21. UATParamMap = UIParamUtil.UATParamMap
  22. def __init__(self, runnerCommand):
  23. self.runnerCommand = runnerCommand
  24. self.pyU = PyUIAutomator()
  25. self.dm = DirectionManageAndroid()
  26. self.fm = FocusManageAndroid(self.pyU, self.dm)
  27. self.inLayout= False
  28. '''
  29. 解析option的焦点组件参数,返回focusView或者focus-select组件参数
  30. :param option: option字典
  31. :return 返回 focus焦点参数字典,采用setObjParam可以转换成UIObject识别需要的参数。
  32. 如果为None,则表示不需要焦点选中。
  33. '''
  34. def getFPFromOption(self, option):
  35. focusParam = None
  36. fsParam = option[UATTree.TAB_FOCUS_SELECT]
  37. fvParam = option[UATTree.TAB_FOCUSE_VIEW]
  38. if fsParam[UATTree.FS_Type].__len__() > 1:
  39. if fsParam[UATTree.FS_Type].lower() == "focus":
  40. fsParam["focus"] = True
  41. focusParam = fsParam
  42. elif fsParam[UATTree.FS_Type].lower() == "select":
  43. fsParam["select"] = True
  44. focusParam = fsParam
  45. elif fsParam[UATTree.FS_Type].lower() == "no":
  46. focusParam = None
  47. else:
  48. error(self.cls, "getFPFromOption", "Option %s focus-select参数异常。" % option[UATTree.TAB_NAME], ERROR)
  49. else:
  50. focusParam = fvParam
  51. return focusParam
  52. '''
  53. 解析option的焦点组件参数,返回focusView或者focus-select组件参数.
  54. 在getFPFromOption返回值上,采用setObjParam转换成UIObject识别需要的参数。
  55. :param option: option字典
  56. :return 返回 focus焦点UIObject参数字典.
  57. '''
  58. def getFPObjParam(self, option):
  59. focusParam = self.getFPFromOption(option)
  60. fpObjParam = UIParamUtil.setObjParam(focusParam)
  61. return fpObjParam
  62. '''
  63. 解析存储在UATree里的moveKey字典,得到按键类型、键值数组、最大尝试次数
  64. :param moveKey, parent字典中moveKey字典
  65. :param optionCount: moveKey对应的parent的option个数
  66. :return keyType, keyCodeList, Max_Trye
  67. '''
  68. def parseMoveKey(self,moveKey, optionCount):
  69. if moveKey[UATTree.Max_Try] != "":
  70. Max_Try = int(moveKey[UATTree.Max_Try])
  71. else:
  72. Max_Try = optionCount
  73. findDirection = ["down","up"]
  74. keyType = UATTree.Key_Event
  75. if moveKey[UATTree.Key_Event].__len__() > 1:
  76. findDirection = moveKey[UATTree.Key_Event]
  77. keyType = UATTree.Key_Event
  78. elif moveKey[UATTree.Key_IR].__len__() > 1:
  79. findDirection = moveKey[UATTree.Key_IR]
  80. keyType = UATTree.Key_IR
  81. elif moveKey[UATTree.Key_Input].__len__() > 1:
  82. inputCmd = moveKey[UATTree.Key_Input]
  83. #TODO input情况的处理
  84. return None,None,None
  85. else:
  86. return None,None,None
  87. return keyType, findDirection, Max_Try
  88. '''
  89. 在parent界面,将焦点移动到目标option上。
  90. 焦点定位:根据layout是不是限制焦点范围,进行焦点组件寻找,焦点组件类型:focus、select、focusView、long-click
  91. 目标定位:纯粹是根据optionView配置组建坐标定位
  92. :param parent:当前电视界面的parent字典
  93. :param option:目标option字典
  94. :return True/False
  95. '''
  96. def focusOptionView(self, parent, option,chooseType):
  97. #是否采用layout限制焦点判断范围
  98. layout = parent[UATTree.TAB_LAYOUT]
  99. print "focusOptionView,layout:",layout
  100. self.inLayout = layout[UATTree.Layout_Limit]
  101. # 找到目标optionView参数
  102. layoutUIObj = {}
  103. optionUIObjParam = UIParamUtil.setObjParam(option[UATTree.TAB_OPTION_VIEW])
  104. if self.inLayout == 1:
  105. layoutUIObjParam = UIParamUtil.setObjParam(layout)
  106. else:
  107. layoutUIObjParam = {}
  108. # 获取move key按键
  109. moveKey = parent[UATTree.TAB_MOVE_KEY]
  110. keyType, findDirection,Max_Try = self.parseMoveKey(moveKey, parent[UATTree.TAB_OPTION].__len__())
  111. if keyType is None:
  112. error(self.cls, "focusTargetOption", option[UATTree.TAB_NAME] + " option 读取 move_key失败", ERROR)
  113. return False
  114. #获取optionview的View_sambounds参数
  115. osamBounds = option[UATTree.TAB_OPTION_VIEW][UATTree.View_sambounds]
  116. #获取焦点view参数
  117. focusParam = self.getFPFromOption(option)
  118. focusUIParam = UIParamUtil.setObjParam(focusParam)
  119. if focusParam is None:
  120. fsamBounds = []
  121. else:
  122. fsamBounds = focusParam[UATTree.View_sambounds]
  123. if chooseType.lower()== 'no':
  124. return self.getNoFocusedObj(option, Max_Try, findDirection, keyType, layoutUIObjParam)
  125. else:
  126. return self.toDestObj(parent, option, Max_Try, findDirection, keyType, layoutUIObjParam,fsamBounds,osamBounds)
  127. '''
  128. 传入uiautomator需要的目标组件参数,获取无聚焦属性的option对象
  129. '''
  130. def getNoFocusedObj(self,option, Max_Try, findDirection, keyType, layoutUIObjParam):
  131. count = 0
  132. directIndex = 0
  133. while(True):
  134. if count >= Max_Try and directIndex >= findDirection.__len__()-1:
  135. break
  136. time.sleep(0.1)
  137. destUIObject = self.getOptionUIObj(option, layoutUIObjParam)
  138. if destUIObject and destUIObject.exists():
  139. info(self.cls,"getNoFocusedObj","找到目标option %s"%option[UATTree.TAB_NAME],INFO)
  140. return True
  141. else:
  142. if count < Max_Try:
  143. count = count + 1
  144. elif count >= Max_Try and directIndex<findDirection.__len__() -1:
  145. count=0
  146. Max_Try *= 2
  147. directIndex = directIndex + 1
  148. self.fm.pressKeyByType(findDirection[directIndex], keyType)
  149. error(self.cls, "getNoFocusedObj", "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try)), ERROR)
  150. return False
  151. '''
  152. 传入uiautomator需要的目标组件参数和焦点框参数,用于寻找目标。
  153. '''
  154. def toDestObj(self, parent, option, Max_Try=10, findDirections=["down","up"], keyType=UATTree.Key_Event,
  155. layoutUIParam={}, fsamBounds=[],osamBounds=[]):
  156. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  157. print "toDestObj,enter:",Max_Try,findDirections,keyType,fsamBounds,osamBounds
  158. count = 0
  159. Max_Try = Max_Try
  160. directIndex = 0
  161. focusCount = 0 # 当目标和聚焦点在一个页面同时存在时,从当前聚焦点到目标的移动次数
  162. focusedBoundsPre = {u'top': 0, u'left': 0, u'right': 0, u'bottom': 0} # 上一轮聚焦点的坐标
  163. destBoundsPre = {u'top': 0, u'left': 0, u'right': 0, u'bottom': 0} # 上一轮目标的坐标
  164. hb_keyDict = parent[UATTree.TAB_OTHERS][UATTree.Key_HeartBeat]
  165. # print "##########", hb_keyDict
  166. # print "##########", parent[UATTree.TAB_OTHERS]
  167. if hb_keyDict != {}:
  168. # 执行心跳按键
  169. info(self.cls, "toDestObj", "executeHeartBeatKey:%s"%hb_keyDict, INFO)
  170. self.fm.executeHeartBeatKey(hb_keyDict)
  171. while (True):
  172. if count >= Max_Try and directIndex >= findDirections.__len__()-1:
  173. break
  174. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  175. time.sleep(0.1)
  176. destUIObject = self.getOptionUIObj(option,layoutUIParam)
  177. focusParam = self.getFPFromOption(option)
  178. #option是否需要聚焦
  179. needFocus = True
  180. if focusParam.has_key(UATTree.FS_Type) and \
  181. focusParam[UATTree.FS_Type] == "no":
  182. needFocus = False
  183. if destUIObject and destUIObject.exists(): # 有聚焦属性的option存在不代表已聚焦,无聚焦属性的option存在即当作已聚焦
  184. try:
  185. retCode, focusedUIObject = self.getChooseUIObjP(parent, layoutUIParam,needFocus=needFocus)
  186. debug(self.cls, "toDestObj", "Parent %s 当前聚焦框retCode:%d" % (parent[UATTree.TAB_NAME],retCode), DEBUG)
  187. #如果焦点不存在,只需要判断optionView存在即可算是聚焦成功
  188. if retCode == self.Focus_Need_Not:
  189. return True
  190. #根据已获取到destUIObject和focusedUIObject,进行是否选中目标option判断,
  191. #未选中,则继续利用moveKey查找
  192. focusedBounds = focusedUIObject.info['bounds']
  193. info(self.cls,"toDestObj","当前聚焦框所在坐标:%s"%focusedBounds,INFO)
  194. destBounds = destUIObject.info['bounds']
  195. info(self.cls, "toDestObj", "已寻找%s次" % focusCount, INFO)
  196. info(self.cls,"toDestObj","目标Option %s坐标:%s"%(option[UATTree.TAB_NAME], destBounds),INFO)
  197. if self.hasFocusDest(focusedBounds, destBounds, fsamBounds=fsamBounds, osamBounds=osamBounds):
  198. info(self.cls,"toDestObj","成功聚焦到目标焦点:%s"%option[UATTree.TAB_NAME],INFO)
  199. return True
  200. # 如果往同一个方向跑了5次,聚焦坐标和目标坐标的位置都没变化,则说明目标可能为非聚焦,跑不动了
  201. if focusCount<5:
  202. direction = self.dm.getTargetDirection(focusedBounds, destBounds, findDirections)
  203. self.dm.goOneStep(self.pyU, direction, keyType)
  204. isSameFocused = self.dm.isSameBounds(focusedBoundsPre,focusedBounds) # 前一次聚焦点与当前聚焦点坐标对比
  205. isSameDest = self.dm.isSameBounds(destBoundsPre,destBounds)
  206. info(self.cls,"toDestObj","focusedBoundsPre:%s"%focusedBoundsPre,INFO)
  207. info(self.cls, "toDestObj", "focusedBounds:%s" % focusedBounds, INFO)
  208. if isSameFocused == True and isSameDest == True:
  209. focusCount += 1
  210. focusedBoundsPre = focusedBounds
  211. destBoundsPre = destBounds
  212. info(self.cls,"toDestObj.focusCount","focusCount:%s"%focusCount,INFO)
  213. continue
  214. if focusCount == 0:
  215. focusCount += 1 # 如果focusCount=0,则将当前聚焦点和目标坐标赋值给前一次
  216. focusedBoundsPre = focusedBounds
  217. destBoundsPre = destBounds
  218. info(self.cls,"toDestObj.focusCount.countStart", "focusCount:%s"%focusCount,INFO)
  219. continue
  220. else:
  221. error(self.cls, "toDestObj", "未找到目标焦点!!!", ERROR)
  222. return False
  223. except Exception,e:
  224. info(self.cls,"toDestObj","未获取到目标/焦点对象坐标:count:%d,Max_Try:%d,directIndex:%d"%(count,Max_Try,directIndex),INFO)
  225. traceback.print_exc()
  226. # 出现控件出现一半的时候,获取控件信息会报错
  227. if count < Max_Try:
  228. count = count + 1
  229. elif count >= Max_Try and directIndex < findDirections.__len__() -1:
  230. count=0
  231. Max_Try *= 2
  232. directIndex = directIndex + 1
  233. self.fm.pressKeyByType(findDirections[directIndex], keyType)
  234. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  235. else:
  236. if count < Max_Try:
  237. count = count + 1
  238. elif count >= Max_Try and directIndex<findDirections.__len__() -1:
  239. count=0
  240. Max_Try *= 2
  241. directIndex = directIndex + 1
  242. self.fm.pressKeyByType(findDirections[directIndex], keyType)
  243. error(self.cls, "toDestObj", "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try)), ERROR)
  244. return False
  245. '''
  246. 根据配置的样本焦点框和OptionView 区域坐标,计算是否聚焦
  247. :param focusedBounds 当前电视焦点框坐标
  248. :param destBounds 当前电视目标坐标
  249. :param fsamBounds 取样时的焦点框坐标
  250. :param osamBounds 取样时的目标坐标
  251. :return True/False True:焦点在目标上;False:焦点不在目标上
  252. '''
  253. def hasFocusDest(self,focusedBounds, destBounds, fsamBounds=[],osamBounds=[]):
  254. # print "hasFocusDest,focusedBounds,destBounds,fsamBounds,osamBounds:",focusedBounds, destBounds,fsamBounds,osamBounds
  255. if fsamBounds.__len__() < 1 or osamBounds.__len__()<1:
  256. return self.dm.isHasAnotherBounds(focusedBounds, destBounds)
  257. else:#在焦点框bounds特别大时,同时包含多个目标optionView时,用此方法判断是否选中。
  258. focusBounds = UIParamUtil.atxBounds2UATBounds(focusedBounds)
  259. destBounds = UIParamUtil.atxBounds2UATBounds(destBounds)
  260. print "fsamBounds,osamBounds"
  261. sdrate = self.calPointAngle(fsamBounds[0], osamBounds[0])
  262. sdLine = self.calPointLine(fsamBounds[0], osamBounds[0])
  263. print "focusBounds,destBounds"
  264. drate = self.calPointAngle(focusBounds[0],destBounds[0])
  265. dLine = self.calPointLine(focusBounds[0],destBounds[0])
  266. if abs(drate - sdrate) < 5 and abs(dLine - sdLine) < 30:
  267. return True
  268. else:
  269. return False
  270. '''
  271. 计算点p2相对点p1的角度
  272. '''
  273. def calPointAngle(self, p1, p2):
  274. angle = 0.0
  275. print "calPointAngle,p1,p2:", p1,p2
  276. dx = float(p2[0])-float(p1[0])
  277. dy = float(p2[1])-float(p1[1])
  278. print "calPointAngle,dx,dy:",dx,dy
  279. if dx == 0 and dy >= 0:
  280. return 90
  281. elif dx == 0 and dy < 0:
  282. return 180
  283. radian = math.atan(dy/dx) #计算出弧度值
  284. angle = 180 * radian/math.pi
  285. print "calPointAngle,angle,radian:",angle,radian
  286. return angle
  287. def calPointLine(self, p1,p2):
  288. print "calPointLine,p1,p2:", p1,p2
  289. dx = float(p2[0])-float(p1[0])
  290. dy = float(p2[1])-float(p1[1])
  291. line = round(math.sqrt(dx*dx + dy*dy),1)
  292. print "calPointLine,line:", line
  293. return line
  294. '''
  295. 检测option组件,在电视上是否被选中了
  296. :param option 数据字典
  297. :param layoutUIParam, parent的layout组件定位字典
  298. :param focusUIObj, 焦点组件
  299. :return -1:未进入option的页面,找不到option UIObject;0:进入了option的页面,未选中option;1 已经选中option
  300. -2:代表未找到焦点
  301. '''
  302. def checkOptionChoose(self, option, layoutUIParam, focusUIObj):
  303. optionUIObj = self.getOptionUIObj(option, layoutUIParam)
  304. if optionUIObj is None or optionUIObj.exists() is False:
  305. return -1
  306. if focusUIObj is None or focusUIObj.exists() is False:
  307. return -2
  308. focusParam = self.getFPFromOption(option)
  309. if focusParam is None:
  310. return 1
  311. try:
  312. focusedBounds = focusUIObj.info()["bounds"]
  313. destBounds = optionUIObj.info()['bounds']
  314. except Exception,e:
  315. return 0
  316. fsamBounds = focusParam[UATTree.View_sambounds]
  317. osamBounds = option[UATTree.TAB_OPTION_VIEW][UATTree.View_sambounds]
  318. if self.hasFocusDest(focusedBounds, destBounds,fsamBounds, osamBounds):
  319. return 1
  320. else:
  321. return 0
  322. def checkOptionExist(self, option, parent):
  323. # print "checkOptionExist,option:",option
  324. moveKey = parent[UATTree.TAB_MOVE_KEY]
  325. hb_keyDict = parent[UATTree.TAB_OTHERS][UATTree.Key_HeartBeat]
  326. if hb_keyDict != {}:
  327. # 执行心跳按键
  328. info(self.cls, "checkOptionExist", "executeHeartBeatKey:%s"%hb_keyDict, INFO)
  329. self.fm.executeHeartBeatKey(hb_keyDict)
  330. optionName = option['name']
  331. print "checkOptionExist,moveKey:", moveKey
  332. Max_Try = moveKey[UATTree.Max_Try]
  333. if Max_Try == "":
  334. Max_Try = 1
  335. else:
  336. Max_Try = int(Max_Try)
  337. Reverse_Max_Try = Max_Try * 2
  338. print "Max_Try:", Max_Try
  339. count = 0
  340. Reversecount = 0
  341. lastObj = ""
  342. opUIParam = UIParamUtil.setObjParam(option["optionView"])
  343. # 为了兼容多文本,逐个遍历文本,针对text属性做特殊处理
  344. if "text" in opUIParam and type(opUIParam['text']) == type([]):
  345. for text in opUIParam['text']:
  346. uiParam = copy.deepcopy(opUIParam)
  347. uiParam['text'] = text
  348. while (True):
  349. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  350. break
  351. # 如果找到目标直接返回
  352. debug(self.cls,"checkOptionExist","optionView:%s"%option,DEBUG)
  353. ###
  354. try:
  355. opOBJ = self.pyU.getUiObject2(uiParam)
  356. opOBJInfo = opOBJ.info
  357. debug(self.cls,"checkOptionExist","opOBJInfo: %s"%opOBJInfo,DEBUG)
  358. break
  359. except Exception,e:
  360. opOBJ = None
  361. if count < Max_Try:
  362. flag = 1
  363. count += 1
  364. print "now count:", count
  365. else:
  366. flag = 0
  367. Reversecount += 1
  368. print "now Reversecount:", Reversecount
  369. self.runnerCommand.executeMoveKey(moveKey, flag)
  370. # print "###",type(opOBJ),opOBJ
  371. if opOBJ is not None:
  372. if opOBJ.exists:
  373. info(self.cls, "checkOptionExist", "当前页面已找到option: %s" % optionName, INFO)
  374. return True
  375. else:
  376. while (True):
  377. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  378. break
  379. # 如果找到目标直接返回
  380. debug(self.cls, "checkOptionExist", "optionView:%s" % option, DEBUG)
  381. ###
  382. try:
  383. opOBJ = self.pyU.getUiObject2(opUIParam)
  384. opOBJInfo = opOBJ.info
  385. debug(self.cls, "checkOptionExist", "opOBJInfo: %s" % opOBJInfo, DEBUG)
  386. break
  387. except Exception, e:
  388. opOBJ = None
  389. if count < Max_Try:
  390. flag = 1
  391. count += 1
  392. print "now count:", count
  393. else:
  394. flag = 0
  395. Reversecount += 1
  396. print "now Reversecount:", Reversecount
  397. self.runnerCommand.executeMoveKey(moveKey, flag)
  398. # print "###", type(opOBJ), opOBJ
  399. if opOBJ is not None:
  400. if opOBJ.exists:
  401. info(self.cls, "checkOptionExist", "当前页面已找到option: %s" % optionName, INFO)
  402. return True
  403. info(self.cls, "checkOptionExist", "注意!!!当前页面未找到option: %s" % optionName, INFO)
  404. return False
  405. '''
  406. 根据option配置的焦点方式,返回当前页面焦点组件
  407. :param option: option字典
  408. :param layoutUIObj : option对应组件的根组件
  409. :return retCode,UIObject对象:reCode=0表示默认为不需要选中状态,retCode=1表示option默认为需要选中状态
  410. '''
  411. Focus_Need = 1
  412. Focus_Need_Not = 0
  413. def getChooseUIObj(self, option, layoutUIObj = None):
  414. debug(self.cls, "getChooseUIObj", "option name:"+option[UATTree.TAB_NAME],DEBUG)
  415. focusObjParam = self.getFPObjParam(option)
  416. debug(self.cls, "getChooseUIObj", "focusObjParam:"+str(focusObjParam)+"; layoutUIObj:"+str(layoutUIObj),DEBUG)
  417. if focusObjParam.__len__() <= 0:
  418. return self.Focus_Need_Not,None
  419. if layoutUIObj is None:
  420. return self.Focus_Need,self.pyU.getUiObject2(focusObjParam)
  421. else:
  422. return self.Focus_Need,layoutUIObj.child(**focusObjParam)
  423. '''
  424. 根据parent字典,检索parent是否有一个option被选中,任何一个备选中,返回option的UIObject
  425. :param parent: parent 字典
  426. :param needFocus: 目标option需要聚焦,则优先找焦点,再处理select type为no情况
  427. :return retCode,UIObject对象:reCode=0表示默认为不需要选中状态,retCode=1表示option默认为需要选中状态
  428. '''
  429. def getChooseUIObjP(self, parent, layoutUIParam, needFocus = True):
  430. if layoutUIParam.__len__() > 0:
  431. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  432. else:
  433. layoutUIObj = None
  434. # 筛选焦点定位类型,减少重复判断
  435. focusOptionDict = self.reMuFocusOption(parent[UATTree.TAB_OPTION])
  436. debug(self.cls,"getChooseUIObjP","focusOptionDict:"+str(focusOptionDict.keys()),DEBUG)
  437. for optionName in focusOptionDict:
  438. option = focusOptionDict[optionName]
  439. retCode, uiObj = self.getChooseUIObj(option, layoutUIObj)
  440. if retCode == self.Focus_Need_Not and needFocus is False:
  441. return self.Focus_Need_Not, None
  442. elif retCode == self.Focus_Need and uiObj is not None and uiObj.exists():
  443. return retCode, uiObj
  444. return self.Focus_Need,None
  445. '''
  446. 根据parent字典,检索parent是否有一个option被选中,任何一个备选中,返回option的字典信息
  447. :param parent: parent 字典
  448. :param needFocus: 目标option需要聚焦,则优先找焦点,再处理select type为no情况
  449. :return retCode,UIObject对象:reCode=0表示默认为不需要选中状态,retCode=1表示option默认为需要选中状态
  450. '''
  451. def getChooseOptionP(self, parent, layoutUIParam, needFocus = True):
  452. if layoutUIParam.__len__() > 0:
  453. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  454. else:
  455. layoutUIObj = None
  456. optionDict = parent[UATTree.TAB_OPTION]
  457. # 筛选焦点定位类型,减少重复判断
  458. focusOptionDict = self.reMuFocusOption(parent[UATTree.TAB_OPTION])
  459. debug(self.cls,"getChooseUIObjP","focusOptionDict:"+str(focusOptionDict.keys()),DEBUG)
  460. # 是否确认当前聚焦optionName的标识
  461. # 用任意一option,获取当前聚焦的uiobj
  462. optionName = focusOptionDict.keys()[0]
  463. option = focusOptionDict[optionName]
  464. retCode, choosedObj = self.getChooseUIObj(option, layoutUIObj)
  465. if retCode == self.Focus_Need_Not and needFocus is False:
  466. return self.Focus_Need_Not, None
  467. elif retCode == self.Focus_Need and choosedObj is not None and choosedObj.exists():
  468. for optionName in optionDict:
  469. option = optionDict[optionName]
  470. destUIParam = UIParamUtil.setObjParam(option[UATTree.TAB_OPTION_VIEW])
  471. destObj = self.pyU.getUiObject2(destUIParam)
  472. if destObj.exists():
  473. choosedBound = choosedObj.info['bounds']
  474. destBound = destObj.info['bounds']
  475. if self.dm.isHasAnotherBounds(choosedBound, destBound):
  476. return self.Focus_Need, option
  477. return self.Focus_Need,None
  478. def reMuFocusOption(self, optionDict):
  479. retDict = {}
  480. for optionName in optionDict:
  481. option = optionDict[optionName]
  482. focusObjParam = self.getFPObjParam(option)
  483. if retDict.__len__() == 0:
  484. retDict[optionName] = option
  485. continue
  486. isSame = False
  487. for retName in retDict:
  488. retOption = optionDict[retName]
  489. retFocusObjParam = self.getFPObjParam(retOption)
  490. if UIParamUtil.cmpObjParam(focusObjParam, retFocusObjParam):
  491. isSame = True
  492. break
  493. if isSame is False:
  494. retDict[optionName] = option
  495. return retDict
  496. '''
  497. 根据option和layoutUIParam参数,获取option UIObject对象
  498. layoutUIParam参数有效,则在layout里查找子组件option,否则全界面查找子组件。
  499. '''
  500. def getOptionUIObj(self, option, layoutUIParam):
  501. debug(self.cls, "getOptionUIObj","OptionView:"+str(option[UATTree.TAB_OPTION_VIEW]),DEBUG)
  502. destUIParam = UIParamUtil.setObjParam(option[UATTree.TAB_OPTION_VIEW])
  503. debug(self.cls, "getOptionUIObj", "destUIParam:" + str(destUIParam), DEBUG)
  504. destUITextExist = False
  505. destUIObject = None
  506. try:
  507. destUIText = destUIParam['text']
  508. destUITextExist = True
  509. except Exception, e:
  510. info(self.cls, "getOptionUIObj", "目标对象%s的optionView无text属性"%option[UATTree.TAB_NAME], INFO)
  511. if destUITextExist is True:
  512. #####################
  513. if type(destUIParam['text']) is type([]):
  514. destUIObjectExist = False
  515. tempTextList = destUIParam['text']
  516. txtCount = 0
  517. for txt in tempTextList:
  518. destUIParam['text'] = txt
  519. uix = self.pyU.dump_hierarchy()
  520. if txt not in uix:
  521. continue
  522. if layoutUIParam.__len__() > 0:
  523. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  524. try:
  525. destUIObject = layoutUIObj.child(**destUIParam)
  526. destUIObjectInfo = destUIObject.info
  527. destUIObjectExist = True
  528. info(self.cls, "getOptionUIObj", "文本%s对应的option对象已找到" % txt, INFO)
  529. except Exception, e:
  530. nextText = tempTextList[txtCount + 1]
  531. error(self.cls, "getOptionUIObj", "文本%s对应的option对象未找到,匹配下一个文本%s" % (txt, nextText), ERROR)
  532. if destUIObjectExist is True:
  533. break
  534. else:
  535. try:
  536. destUIObject = self.pyU.getUiObject2(destUIParam)
  537. destUIObjectInfo = destUIObject.info
  538. destUIObjectExist = True
  539. info(self.cls, "getOptionUIObj", "文本%s对应的option对象已找到" % txt, INFO)
  540. except Exception, e:
  541. nextText = tempTextList[txtCount + 1]
  542. error(self.cls, "getOptionUIObj", "文本%s对应的option对象未找到,匹配下一个文本%s" % (txt, nextText), ERROR)
  543. if destUIObjectExist is True:
  544. break
  545. txtCount += 1
  546. else:
  547. if layoutUIParam.__len__() > 0:
  548. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  549. destUIObject = layoutUIObj.child(**destUIParam)
  550. else:
  551. destUIObject = self.pyU.getUiObject2(destUIParam)
  552. #########################
  553. else:
  554. if layoutUIParam.__len__() > 0:
  555. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  556. destUIObject = layoutUIObj.child(**destUIParam)
  557. else:
  558. destUIObject = self.pyU.getUiObject2(destUIParam)
  559. return destUIObject
  560. '''
  561. 检测parent,在电视上是否被选中了。一个option被选中,表示选中
  562. :param option 数据字典
  563. :return
  564. -3:代表UIView判断未通过;
  565. -2:代表选中了parent,但未找到焦点;
  566. -1:未进入parent的页面,找不到parent layout;
  567. 0:进入了parent的页面,未选中parent;
  568. 1:已经选中parent
  569. '''
  570. def checkParentChoose(self, parent):
  571. debug(self.cls, "checkParentChoose", "parent:" + parent[UATTree.TAB_NAME], DEBUG)
  572. chooseTypeDict = {}
  573. layoutParam = parent[UATTree.TAB_LAYOUT]
  574. layoutUIParam = UIParamUtil.setObjParam(layoutParam)
  575. layoutResId = layoutParam[UATTree.View_ID]
  576. uiView = parent[UATTree.TAB_UI_VIEW]
  577. uiViewResId = uiView[UATTree.View_ID]
  578. uiViewText = uiView[UATTree.View_Text]
  579. uiViewDesc = uiView[UATTree.View_Desc]
  580. # print "checkParentChoose,layoutUIParam:",layoutUIParam
  581. if layoutResId == "" and uiViewResId == "" and uiViewText == "" and uiViewDesc == "":
  582. debug(self.cls, "checkParentChoose",
  583. "Warning:Parent %s的Layout resId和UIView信息获取失败!!请注意检查UATree文件!!!" % parent[UATTree.TAB_NAME], DEBUG)
  584. return -1
  585. elif layoutUIParam.__len__() > 0:
  586. # 如果存在UIView信息,则先判断UIView
  587. isExist = self.checkUIViewExist(uiView)
  588. if isExist is False:
  589. info(self.cls, "checkParentChoose", "当前页面不存在Parent:%s的UIView组件,判断该界面非此parent" % parent[UATTree.TAB_NAME],
  590. INFO)
  591. return -3
  592. else:
  593. debug(self.cls, "checkParentChoose", "已识别出Parent:%s的UIView组件" % parent[UATTree.TAB_NAME], DEBUG)
  594. # debug(self.cls, "checkParentChoose", "UIView组件内容:%s" % uiView, DEBUG)
  595. # 判断Layout是否存在
  596. layoutUIObj = self.pyU.getUiObject2(layoutUIParam)
  597. if layoutUIObj is None or layoutUIObj.exists() is False:
  598. info(self.cls, "checkParentChoose", "parent %s layout 不存在 "%parent[UATTree.TAB_NAME], INFO)
  599. return -1
  600. debug(self.cls, "checkParentChoose", "parent %s layout 存在"%parent[UATTree.TAB_NAME], DEBUG)
  601. # 获取焦点组件,判断是否在layout中
  602. retCode, focusObj = self.getChooseUIObjP(parent, layoutUIParam, needFocus=False)
  603. if retCode == self.Focus_Need_Not:
  604. debug(self.cls, "checkParentChoose",
  605. "已找到目标parent %s,不需要选中。" % (parent['name']), DEBUG)
  606. elif focusObj is not None and focusObj.exists():
  607. debug(self.cls, "checkParentChoose",
  608. "已找到目标parent %s,焦点在Layout中。" % (parent['name']), DEBUG)
  609. else:
  610. info(self.cls, "checkParentChoose",
  611. "已找到目标parent %s,但是焦点不在Layout中。" % (parent['name']), INFO)
  612. return -2
  613. # 判断parent中存在一个option,则标识parent被选中。注意:为了快速消失界面相应
  614. if layoutParam[UATTree.Layout_Limit] <> 1:
  615. layoutUIParam = {}
  616. optionUIObj = None
  617. optionExist = False
  618. for optionName in parent["option"]:
  619. option = parent["option"][optionName]
  620. ret = self.checkOptionExist(option,parent)
  621. if ret is True:
  622. info(self.cls, "checkParentChoose",
  623. "已找到目标parent %s,识别出该parent下的option %s。" % (parent['name'], option['name']),
  624. INFO)
  625. return 1
  626. info(self.cls, "checkParentChoose",
  627. "已找到目标parent %s,但是parent下的option未被发现。" % (parent['name']), INFO)
  628. return 0
  629. else:
  630. isExist = self.checkUIViewExist(uiView)
  631. if not isExist:
  632. return -3
  633. else:
  634. info(self.cls, "checkParentChoose",
  635. "识别出parent %s的UIView参数,判断处于该界面中" % (parent['name']), INFO)
  636. return 1
  637. '''
  638. 检测某个弹窗是否存在。
  639. 弹窗相关的参数放在UIView中配置。
  640. 当存在resId参数时,使用resId获取对象并获取文本,再与text做比较;
  641. 当不存在resId参数时,使用text直接获取对象,判断对象是否存在。
  642. 与checkParentChoose判断不一致,做特殊处理。
  643. :return 整型:0代表不存在,1代表存在
  644. '''
  645. def checkDialogExist(self, dialog):
  646. debug(self.cls, "checkDialogExist", "dialog:" + dialog["name"], DEBUG)
  647. dialogText = dialog[UATTree.TAB_UI_VIEW][UATTree.View_Text]
  648. dialogResId = dialog[UATTree.TAB_UI_VIEW][UATTree.View_ID]
  649. # print "checkDialogExist.dialogText:", dialogText
  650. # print "checkDialogExist.dialogResId:", dialogResId
  651. if dialogResId != "":
  652. textObj = self.pyU.getUiObject(resourceId=dialogResId)
  653. if textObj.exists:
  654. objText = textObj.info['text']
  655. # print "checkDialogExist.objText:", objText
  656. if dialogText in objText:
  657. return 1
  658. else:
  659. return 0
  660. else:
  661. return 0
  662. else:
  663. textObj = self.pyU.getUiObject(text=dialogText)
  664. if textObj.exists:
  665. return 1
  666. else:
  667. return 0
  668. def checkUIViewExist(self, uiView):
  669. #uiview未配置默认为检测通过
  670. if uiView.__len__() == 0:
  671. return True
  672. uiviewObjParam = UIParamUtil.setObjParam(uiView)
  673. uiViewObj = self.pyU.getUiObject2(uiviewObjParam)
  674. if uiViewObj is None:
  675. return False
  676. elif uiViewObj.exists:
  677. return True
  678. else:
  679. return False
  680. def moveToCheckedRedioButton(self, fsParam, findDirection="down", keyType=UATTree.Key_Event, maxTry=20):
  681. count = 0
  682. Reversecount = 0
  683. tryCount = 0
  684. while(True):
  685. param={"checked":"true"}
  686. checkedObj = self.pyU.getUiObject2(param)
  687. if not checkedObj.exists():
  688. if count < maxTry:
  689. self.fm.pressKeyByType(findDirection[1], keyType)
  690. count += 1
  691. continue
  692. else:
  693. Reversecount = Reversecount + 1
  694. self.fm.pressKeyByType(self.fm.ReverseDirctionDict[findDirection], keyType)
  695. continue
  696. choosedObj = self.pyU.getUiObject2(fsParam)
  697. if not choosedObj.exists():
  698. count += 1
  699. continue
  700. choosedBounds = choosedObj.info['bounds']
  701. checkedBounds = checkedObj.info['bounds']
  702. if self.dm.isHasAnotherBounds(choosedBounds, checkedBounds):
  703. info(self.cls, "moveToCheckedRedioButton", "已聚焦至目标组件!!!", INFO)
  704. return True, choosedObj
  705. else:
  706. direction = self.dm.getTargetDirection(choosedBounds, checkedBounds)
  707. print "目标方位:",direction
  708. self.dm.goOneStep(self.pyU, direction, keyType)
  709. tryCount += 1
  710. if tryCount >= maxTry:
  711. error(self.cls, "moveToCheckedRedioButton", "已尝试至最大次数%s次,仍未能聚焦至目标组件!!!"%maxTry, error)
  712. return False, choosedObj
  713. if Reversecount >= maxTry:
  714. error(self.cls, "moveToCheckedRedioButton", "已尝试至最大次数%s次,仍未能找到目标组件!!!"%maxTry, error)
  715. return False, choosedObj
  716. if __name__ == "__main__":
  717. uatPathManage = UATPathManage()
  718. pyU = PyUIAutomator()
  719. dm = DirectionManageAndroid()
  720. fm = FocusManageAndroid(pyU, dm)
  721. # runnerCmd = UATRunnerCommand(uatPathManage, pyU, dm, fm)
  722. # focusCmd = FocusCommand(runnerCmd)
  723. # ret = focusCmd.calPointAngle([0,0],[244,151])
  724. # ret = focusCmd.calPointAngle([244,151],[107,641])
  725. # focusCmd.strToBounds('[801,116][1280,180]')
  726. # option = focusCmd.runnerCommand.uatPathManage.uatData.getOption("av_devices_settings")
  727. # parent = focusCmd.runnerCommand.uatPathManage.uatData.getParentByOption(option)
  728. # focusCmd.focusOptionView(parent, option)
  729. # print "dump_hierarchy 0:",time.time()
  730. # print focusCmd.pyU.dump_hierarchy()
  731. # print "dump_hierarchy 1:",time.time()
  732. # uiobjg = focusCmd.pyU.getUiObject()