python_uiautomator.py 119 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395
  1. # -*- coding:utf-8 -*-
  2. import time
  3. from ssat_sdk.ocr_convert import OCRConvert
  4. from ssat_sdk.device_manage.capturecard_manager import CCardManager
  5. from ssat_sdk.uiautomator2.ext import htmlreport
  6. # from uiautomator2.ext import htmlreport
  7. from ssat_sdk import uiautomator2 as u2, LoggingUtil, inspect, FeatureDetect, sat_environment, getSATTmpDIR, ImageCMP
  8. from ssat_sdk.UATree.UAT_tree import UATTree
  9. from ssat_sdk.tv_operator import TvOperator
  10. # import uiautomator2 as u2
  11. import os
  12. import re
  13. from ssat_sdk.utils import LoggingUtil
  14. from ssat_sdk.utils.string_util import getDigitFromString
  15. from ssat_sdk.sat_environment import getAdbDeviceSatatus
  16. pyFileName = os.path.split(__file__)[-1]
  17. def get_current_function_name():
  18. return inspect.stack()[1][3]
  19. '''
  20. 预置条件:保证执行PC和测试电视adb连接
  21. 各个API说明的例子中到达self.pyUIAutomator 是PyUIAutomator类的实例
  22. self.pyUIAutomator = PyUIAutomator()
  23. '''
  24. class PyUIAutomator():
  25. def __init__(self, serial=None):
  26. try:
  27. self.u = u2.connect_usb(serial) #得到UIAutomatorServer实例对象
  28. self.serial = serial
  29. except Exception,e:
  30. print e
  31. # hrp = htmlreport.HTMLReport(self.u, 'report')
  32. # try:
  33. # hrp.patch_click()
  34. # except Exception, e:
  35. # print e
  36. # pass
  37. # self.u.app_stop_all()
  38. def reConnect_usb(self):
  39. self.u = u2.connect_usb(self.serial)
  40. # hrp = htmlreport.HTMLReport(self.u, 'report')
  41. # try:
  42. # hrp.patch_click()
  43. # except Exception, e:
  44. # print e
  45. # pass
  46. # self.u.app_stop_all()
  47. '''
  48. 废弃,改用sat_environment.getAdbDeviceSatatus()
  49. '''
  50. def checkAdbConnected(self):
  51. return u2.check_adb_connect()
  52. def listenAdbConnected(self):
  53. count = 5
  54. while getAdbDeviceSatatus() is False and count >0:
  55. count -= 1
  56. LoggingUtil.printLog("PyUIAutomator","listenAdbConnected,Count %d adb not connected!"%count)
  57. # self.reConnect_usb()
  58. time.sleep(1)
  59. def killAdb(self):
  60. return u2.killAdb()
  61. def getAdbType(self):
  62. return u2.check_adb_connect_type()
  63. '''
  64. 作用:获取UIAutomator 连接对象 后续可以使用该对象使用原生方法
  65. '''
  66. def getPyUIAutomator(self):
  67. self.listenAdbConnected()
  68. return self.u
  69. '''
  70. 作用:Android times次按键 key:常用按键的字符串
  71. 主要的键值字段:home、back、left、right、up、down、center、menu、search、enter、delete ( or del)、
  72. recent (recent apps)、volume_up、volume_down、volume_mute、camera、power
  73. times :按键次数 默认为1次
  74. duration:按键时间间隔 默认为1.0s
  75. '''
  76. def pressKeyTimes(self, key, times=1, duration=1.0):
  77. self.listenAdbConnected()
  78. self.u.pressKeyTimes(key, times, duration)
  79. '''
  80. 用uiautomator view属性键作为paramDIct的键,传入的paramDict里的参数,必须有效。
  81. 参考session.Selector里的__fields字典
  82. '''
  83. def getUiObject2(self, paramDict):
  84. # print "getUiObject2,paramDict:",paramDict
  85. uiObject = None
  86. if paramDict.__len__>0:
  87. try:
  88. uiObject = self.u(**paramDict)
  89. except Exception,e:
  90. print "UIAutomator未启动,请确认是否为开机状态"
  91. uiObject = None
  92. # print uiObject,uiObject.info
  93. return uiObject
  94. '''
  95. 作用:获取UiObject对象
  96. 参数:
  97. className:控件类型(例如:android.widget.TextView)
  98. resourceId:控件的Id(例如:lh.oslauncher:id/tv_title)
  99. text:控件上的文件(例如:'主页')
  100. description:控件描述
  101. instance:实例参数
  102. 注意:className、resourceId、text 、description、instance是利用
  103. UIautomatoview.bat工具查看控件属性看到的
  104. 其中 className对应 UIautomatoview.bat中的 class
  105. resourceId对应 UIautomatoview.bat中的 resource-id
  106. description对应 UIautomatoview.bat中的 content-desc
  107. instance对应 UIautomatoview.bat中的 index
  108. 例子:uiObject =self.pyUIAutomator.getUiObject(resourceId="com.google.android.tvlauncher:id/banner_image", description=u"Play 电影", className = 'android.widget.ImageView')
  109. '''
  110. def getUiObject(self, className='', resourceId='', text='', description='', bounds = '',instance=-1):
  111. if text != "":
  112. if type(text) is not type([]):
  113. obj = self.getUiObjectTest(className,resourceId,text,description,bounds,instance)
  114. return obj
  115. if type(text) is type([]):
  116. count = 0
  117. for t in text:
  118. try:
  119. obj = self.getUiObjectTest(className,resourceId,t,description,bounds,instance)
  120. objInfo = obj.info
  121. print "文本%s对应的option已找到"%t
  122. return obj
  123. except Exception,e:
  124. nextText = text[count+1]
  125. print"文本%s对应的option未找到,匹配下一个文本%s"%(t,nextText)
  126. count += 1
  127. print "所有文本均已匹配完毕,未找到对应option"
  128. class object():
  129. exists = False
  130. obj = object()
  131. return obj
  132. else:
  133. obj = self.getUiObjectTest(className,resourceId,text,description,bounds,instance)
  134. return obj
  135. def getUiObjectTest(self, className='', resourceId='', text='', description='', bounds = '',instance=-1):
  136. self.listenAdbConnected()
  137. # print 'className:', className
  138. # print 'resourceId:', resourceId
  139. # print 'text:', text
  140. # print 'description:', description
  141. # print 'instance:', instance
  142. uiObject = None
  143. try:
  144. if className == "" and resourceId == "" and text == "" and description == "" and\
  145. bounds == "" and instance == -1:
  146. print "没有参数带入,找不到对象"
  147. return uiObject
  148. if className != "" and resourceId != "" and text != "" and description != "" and \
  149. bounds != "" and instance != -1:
  150. uiObject = self.u(className=className, resourceId=resourceId, text=text, description=description,
  151. bounds=bounds,instance=instance)
  152. # 缺少一个元素的
  153. #缺instance
  154. if className != "" and resourceId != "" and text != "" and description != "" and \
  155. bounds != "" and instance == -1:
  156. uiObject = self.u(className=className, resourceId=resourceId, text=text, bounds = bounds,
  157. description=description)
  158. #缺bounds
  159. if className != "" and resourceId != "" and text != "" and description != "" and \
  160. bounds == "" and instance != -1:
  161. uiObject = self.u(className=className, resourceId=resourceId, text=text,
  162. description=description,instance = instance)
  163. #缺description
  164. if className != "" and resourceId != "" and text != "" and description == "" and\
  165. bounds != "" and instance != -1:
  166. uiObject = self.u(className=className, resourceId=resourceId, text=text,
  167. bounds=bounds,instance=instance)
  168. #缺text
  169. if className != "" and resourceId != "" and text == "" and description != "" and\
  170. bounds != "" and instance != -1:
  171. uiObject = self.u(className=className, resourceId=resourceId, description=description,
  172. bounds=bounds,instance=instance)
  173. #缺resouceId
  174. if className != "" and resourceId == "" and text != "" and description != "" and \
  175. bounds!="" and instance != -1:
  176. uiObject = self.u(className=className, text=text, description=description,
  177. bounds=bounds,instance=instance)
  178. # lack of className
  179. if className == "" and resourceId != "" and text != "" and description != "" and \
  180. bounds!="" and instance != -1:
  181. uiObject = self.u(resourceId=resourceId, text=text, description=description,
  182. bounds=bounds,instance=instance)
  183. # 缺少两个元素的
  184. # lack of className and resourceId
  185. if className == "" and resourceId == "" and text != "" and description != "" and \
  186. bounds!="" and instance != -1:
  187. uiObject = self.u(text=text, description=description,bounds=bounds,
  188. instance=instance)
  189. # lack of className and text
  190. if className == "" and resourceId != "" and text == "" and description != "" and \
  191. bounds != "" and instance != -1:
  192. uiObject = self.u(resourceId=resourceId, description=description, bounds=bounds,
  193. instance=instance)
  194. #lack of className and description
  195. if className == "" and resourceId != "" and text != "" and description == "" and \
  196. bounds!="" and instance != -1:
  197. uiObject = self.u(resourceId=resourceId, text=text,bounds=bounds,
  198. instance=instance)
  199. # lack of className and bounds
  200. if className == "" and resourceId != "" and text != "" and description != "" and \
  201. bounds == "" and instance != -1:
  202. uiObject = self.u(resourceId=resourceId, text=text, description=description,
  203. instance=instance)
  204. # lack of className and instance
  205. if className == "" and resourceId != "" and text != "" and description != "" and \
  206. bounds != "" and instance == -1:
  207. uiObject = self.u(resourceId=resourceId, text=text, description=description,
  208. bounds=bounds)
  209. # lack of resourceId and text
  210. if className != "" and resourceId == "" and text == "" and description != "" and \
  211. bounds!="" and instance != -1:
  212. uiObject = self.u(className=className, description=description,bounds=bounds,
  213. instance=instance)
  214. # lack of resourceId and description
  215. if className != "" and resourceId == "" and text != "" and description == "" and \
  216. bounds!="" and instance != -1:
  217. uiObject = self.u(className=className, text=text,bounds = bounds,
  218. instance=instance)
  219. # lack of resourceId and bounds
  220. if className != "" and resourceId != "" and text == "" and description != "" and \
  221. bounds == "" and instance != -1:
  222. uiObject = self.u(className=className, text=text, description=description,
  223. instance=instance)
  224. # lack of resourceId and instance
  225. if className != "" and resourceId == "" and text != "" and description != "" and \
  226. bounds != "" and instance == -1:
  227. uiObject = self.u(className=className, text=text, description=description,
  228. bounds=bounds)
  229. # lack of text and description
  230. if className != "" and resourceId != "" and text == "" and description == "" and \
  231. bounds!="" and instance != -1:
  232. uiObject = self.u(className=className, resourceId=resourceId, bounds=bounds,
  233. instance=instance)
  234. # lack of text and bounds
  235. if className != "" and resourceId != "" and text == "" and description != "" and \
  236. bounds=="" and instance != -1:
  237. uiObject = self.u(className=className, resourceId=resourceId,
  238. description=description,instance=instance)
  239. # lack of text and instance
  240. if className != "" and resourceId != "" and text == "" and description != "" and \
  241. bounds!="" and instance == -1:
  242. uiObject = self.u(className=className, resourceId=resourceId,
  243. description=description,bounds=bounds)
  244. # lack of description and bounds
  245. if className != "" and resourceId != "" and text != "" and description == "" and \
  246. bounds=="" and instance != -1:
  247. uiObject = self.u(className=className, resourceId=resourceId, text = text,
  248. instance=instance)
  249. # lack of description and instance
  250. if className != "" and resourceId != "" and text != "" and description == "" and \
  251. bounds!="" and instance == -1:
  252. uiObject = self.u(className=className, resourceId=resourceId, text = text,
  253. bounds=bounds)
  254. # lack of bounds and instance
  255. if className != "" and resourceId != "" and text != "" and description != "" and \
  256. bounds=="" and instance == -1:
  257. uiObject = self.u(className=className, resourceId=resourceId, text = text,
  258. description=description)
  259. # 缺少3个元素
  260. # lack of className and resourceId and text
  261. if className == "" and resourceId == "" and text == "" and description != "" and \
  262. bounds!="" and instance != -1:
  263. uiObject = self.u(description=description, bounds=bounds,instance=instance)
  264. # lack of className and resourceId and description
  265. if className == "" and resourceId == "" and text != "" and description == "" and \
  266. bounds!="" and instance != -1:
  267. uiObject = self.u(text = text,bounds=bounds,instance=instance)
  268. # lack of className and resourceId and bounds
  269. if className == "" and resourceId == "" and text != "" and description != "" and \
  270. bounds =="" and instance != -1:
  271. uiObject = self.u(text = text,description=description,instance=instance)
  272. # lack of className and resourceId and instance
  273. if className == "" and resourceId == "" and text != "" and description != "" and \
  274. bounds!="" and instance == -1:
  275. uiObject = self.u(text = text,description=description,bounds=bounds)
  276. # lack of className and text and description
  277. if className == "" and resourceId != "" and text == "" and description == "" and \
  278. bounds!="" and instance != -1:
  279. uiObject = self.u(resourceId=resourceId,bounds=bounds,instance=instance)
  280. # lack of className and text and bounds
  281. if className == "" and resourceId != "" and text == "" and description != "" and \
  282. bounds=="" and instance != -1:
  283. uiObject = self.u(resourceId=resourceId,description=description,instance=instance)
  284. # lack of className and text and instance
  285. if className == "" and resourceId != "" and text == "" and description != "" and \
  286. bounds!="" and instance == -1:
  287. uiObject = self.u(resourceId=resourceId,description=description,bounds=bounds)
  288. # lack of className and description and bounds
  289. if className == "" and resourceId != "" and text != "" and description == "" and \
  290. bounds=="" and instance != -1:
  291. uiObject = self.u(resourceId=resourceId, text = text,instance=instance)
  292. # lack of className and description and instance
  293. if className == "" and resourceId != "" and text != "" and description == "" and \
  294. bounds!="" and instance == -1:
  295. uiObject = self.u(resourceId=resourceId, text = text,bounds=bounds)
  296. # lack of resourceId and text and description
  297. if className != "" and resourceId == "" and text == "" and description == "" and \
  298. bounds!="" and instance != -1:
  299. uiObject = self.u(className=className,bounds=bounds,instance=instance)
  300. # lack of resourceId and text and bounds
  301. if className != "" and resourceId == "" and text == "" and description != "" and \
  302. bounds=="" and instance != -1:
  303. uiObject = self.u(className=className,description=description,instance=instance)
  304. # lack of resourceId and text and instance
  305. if className != "" and resourceId == "" and text == "" and description != "" and \
  306. bounds!="" and instance == -1:
  307. uiObject = self.u(className=className,description=description,bounds=bounds)
  308. # lack of resourceId and description and bounds
  309. if className != "" and resourceId == "" and text != "" and description == "" and \
  310. bounds =="" and instance != -1:
  311. uiObject = self.u(className=className,text = text,instance=instance)
  312. # lack of resourceId and description and instance
  313. if className != "" and resourceId == "" and text != "" and description == "" and \
  314. bounds!="" and instance == -1:
  315. uiObject = self.u(className=className, text = text,bounds=bounds)
  316. # lack of resourceId and bounds and instance
  317. if className != "" and resourceId == "" and text != "" and description != "" and \
  318. bounds =="" and instance == -1:
  319. uiObject = self.u(className=className, text = text,description=description)
  320. # lack of text and description and bounds
  321. if className != "" and resourceId != "" and text == "" and description == "" and \
  322. bounds=="" and instance != -1:
  323. uiObject = self.u(className=className, resourceId=resourceId,instance=instance)
  324. # lack of text and description and instance
  325. if className != "" and resourceId != "" and text == "" and description == "" and \
  326. bounds!="" and instance == -1:
  327. uiObject = self.u(className=className, resourceId=resourceId,bounds=bounds)
  328. # lack of description and bounds and instance
  329. if className != "" and resourceId != "" and text != "" and description == "" and \
  330. bounds =="" and instance == -1:
  331. uiObject = self.u(className=className, resourceId=resourceId, text = text)
  332. # 缺少4个元素
  333. # lack of className and resourceId and text and description
  334. if className == "" and resourceId == "" and text == "" and description == "" and \
  335. bounds !="" and instance != -1:
  336. uiObject = self.u(bounds=bounds,instance=instance)
  337. # lack of className and resourceId and text and bounds
  338. if className == "" and resourceId == "" and text == "" and description != "" and \
  339. bounds =="" and instance != -1:
  340. uiObject = self.u(description=description,instance=instance)
  341. # lack of className and resourceId and text and instance
  342. if className == "" and resourceId == "" and text == "" and description != "" and \
  343. bounds !="" and instance == -1:
  344. uiObject = self.u(description=description,bounds=bounds)
  345. # lack of className and resourceId and description and bounds
  346. if className == "" and resourceId == "" and text != "" and description == "" and \
  347. bounds =="" and instance != -1:
  348. uiObject = self.u(text = text,instance=instance)
  349. # lack of className and resourceId and description and instance
  350. if className == "" and resourceId == "" and text != "" and description == "" and \
  351. bounds !="" and instance == -1:
  352. uiObject = self.u(text = text,bounds=bounds)
  353. # lack of resourceid and text and description and bounds
  354. if className != "" and resourceId == "" and text == "" and description == "" and \
  355. bounds =="" and instance != -1:
  356. uiObject = self.u(className=className,instance=instance)
  357. # lack of resourceid and text and description and instance
  358. if className != "" and resourceId == "" and text == "" and description == "" and \
  359. bounds !="" and instance == -1:
  360. uiObject = self.u(className=className,bounds=bounds)
  361. # lack of text and description and bounds and instance
  362. if className != "" and resourceId != "" and text == "" and description == "" and \
  363. bounds =="" and instance == -1:
  364. uiObject = self.u(className=className, resourceId=resourceId)
  365. # 缺少5个元素的
  366. # only className
  367. if className != "" and resourceId == "" and text == "" and description == "" and \
  368. bounds =="" and instance == -1:
  369. uiObject = self.u(className=className)
  370. # only resourceid
  371. if className == "" and resourceId != "" and text == "" and description == "" and \
  372. bounds =="" and instance == -1:
  373. uiObject = self.u(resourceId=resourceId)
  374. # only text
  375. if className == "" and resourceId == "" and text != "" and description == "" and \
  376. bounds =="" and instance == -1:
  377. uiObject = self.u(text = text)
  378. # only description
  379. if className == "" and resourceId == "" and text == "" and description != "" and \
  380. bounds =="" and instance == -1:
  381. uiObject = self.u(description=description)
  382. # only bounds
  383. if className == "" and resourceId == "" and text == "" and description == "" and \
  384. bounds !="" and instance == -1:
  385. uiObject = self.u(bounds=bounds)
  386. # only instance
  387. if className == "" and resourceId == "" and text == "" and description == "" and \
  388. bounds =="" and instance == -1:
  389. uiObject = self.u(instance=instance)
  390. return uiObject
  391. except Exception, e:
  392. print "异常:",e
  393. return uiObject
  394. '''
  395. 作用:判断当前界面中指定控件是否存在
  396. 参数:
  397. className:控件类型(例如:android.widget.TextView)
  398. resourceId:控件的Id(例如:lh.oslauncher:id/tv_title)
  399. text:控件上的文件(例如:'主页')
  400. description:控件描述
  401. instance:实例参数
  402. 注意:className、resourceId、text 是利用WEditor工具查看控件属性看到的
  403. 例子:isExists = self.pyUIAutomator.isElementExist("android.widget.TextView",
  404. resourceId="com.apps.weather:id/today_tv_city",
  405. text='鞍山')
  406. '''
  407. def isElementExist(self, className='', resourceId='', text='', description='', instance=-1):
  408. self.listenAdbConnected()
  409. try:
  410. uiObject = self.getUiObject(className, resourceId, text, description, instance)
  411. print 'uiObject:', uiObject
  412. if uiObject:
  413. isExists = uiObject.exists()
  414. print 'isExists:', isExists
  415. else:
  416. isExists = False
  417. except Exception, e:
  418. print e
  419. isExists = False
  420. return isExists
  421. '''
  422. 作用:获取指定控件的文字属性
  423. 参数:
  424. className:控件类型(例如:android.widget.TextView)
  425. resourceId:控件的Id(例如:lh.oslauncher:id/tv_title)
  426. 注意:className、resourceId 是利用WEditor工具查看控件属性看到的
  427. 例子: str_play_time = self.pyUIAutomator.getTextById("android.widget.TextView",
  428. resourceId="com.apps.usbmediaplayer:id/playingTime")
  429. '''
  430. def getTextById(self, className, resourceId):
  431. self.listenAdbConnected()
  432. try:
  433. text = self.u(className=className, resourceId=resourceId).get_text()
  434. except Exception, e:
  435. print e
  436. text = ''
  437. return text
  438. '''
  439. 作用:执行adb命令
  440. 参数:adbCmd:要被执行的adb命令
  441. 注意:adbCmd不需要输入adb shell
  442. 例子:self.pyUIAutomator.adb_shell('am start -n com.apps.factory.ui/.designmenu.DesignMenuActivity')
  443. '''
  444. def adb_shell(self, adbCmd):
  445. self.listenAdbConnected()
  446. try:
  447. self.u.adb_shell(adbCmd)
  448. except Exception, e:
  449. print e
  450. '''
  451. 作用:设置android.widget.EditText 的文字内容
  452. 参数:text 要输入到EditText的文字内容
  453. 注意:保证焦点在该EditText,处于可以输入的状态
  454. 例子:self.pyUIAutomator.send_text(u'鞍山')
  455. '''
  456. def send_text(self, text):
  457. self.listenAdbConnected()
  458. try:
  459. self.u.set_fastinput_ime(True) # 切换成FastInputIME输入法
  460. self.u.clear_text()
  461. self.u.send_keys(unicode(text)) # adb广播输入
  462. self.u.set_fastinput_ime(False) # 切换成正常的输入法
  463. except Exception, e:
  464. print e
  465. '''
  466. 作用:向电视机发送action动作
  467. 参数:actin 要执行的动作
  468. 注意:焦点在搜索界面输入框中,在搜索界面输入完搜索内容,执行该搜索动作
  469. 例子:小米谷歌商店搜索应用 搜索 keep应用
  470. self.pyUIAutomator.send_text("kee")
  471. self.pyUIAutomator.send_action("search")
  472. '''
  473. def send_action(self, action):
  474. self.listenAdbConnected()
  475. try:
  476. self.u.set_fastinput_ime(True) # 切换成FastInputIME输入法
  477. self.u.send_action(action)
  478. self.u.set_fastinput_ime(False) # 切换成正常的输入法
  479. except Exception, e:
  480. print e
  481. '''
  482. 作用:保存界面截图到指定地址
  483. 参数:pngPath 要保存图片的全路径名称
  484. 注意:保证该图片路径所在文件夹存在
  485. 例子:self.pyUIAutomator.screenshot(
  486. r'E:\svn\SAT\SAT_Runner\btc_runner_se\runner\smoking\report\imgs\testUSB_Desk_Focused.png')
  487. '''
  488. def screenshot(self, pngPath):
  489. self.listenAdbConnected()
  490. try:
  491. self.u.screenshot(pngPath)
  492. except Exception, e:
  493. print e
  494. '''
  495. 作用:在Android 一个土司提示框 方便在电视机中看到跑到哪里
  496. 参数:
  497. toastText:土司的内容
  498. toastTime:土司存留时间
  499. 注意:
  500. 例子:self.pyUIAutomator.makeToast('测试开始', 3)
  501. '''
  502. def makeToast(self, toastText, toastTime=1):
  503. self.listenAdbConnected()
  504. try:
  505. self.u.make_toast(toastText, toastTime)
  506. except Exception, e:
  507. print e
  508. '''
  509. 作用:启动指定包名的应用的指定Activity
  510. 参数:
  511. pkg_name:指定的包名
  512. activity:指定的activity名
  513. 注意:
  514. 例子:self.pyUIAutomator.startApp('com.apps.usbmediaplayer')
  515. self.pyUIAutomator.startApp('com.apps.usbmediaplayer','com.apps.usbmediaplayer.activity.MainActivity')
  516. '''
  517. def startApp(self, pkg_name, activity=None):
  518. self.listenAdbConnected()
  519. try:
  520. if activity:
  521. self.u.app_start(pkg_name, activity=activity)
  522. else:
  523. self.u.app_start(pkg_name)
  524. except Exception, e:
  525. print e
  526. '''
  527. 作用:关闭某一指定包名的APP
  528. 参数:
  529. pkg_name:指定的包名
  530. 注意:
  531. 例子:self.pyUIAutomator.stopApp('com.apps.usbmediaplayer')
  532. '''
  533. def stopApp(self, pkg_name):
  534. self.listenAdbConnected()
  535. try:
  536. self.u.app_stop(pkg_name)
  537. except Exception, e:
  538. print e
  539. '''
  540. 作用:关闭Android系统中所有的运行程序
  541. 参数:
  542. 注意:
  543. 例子:self.pyUIAutomator.stopAllApps()
  544. '''
  545. def stopAllApps(self):
  546. self.listenAdbConnected()
  547. try:
  548. self.u.app_stop_all()
  549. except Exception, e:
  550. print e
  551. '''
  552. 作用:停止uiautomator守护程序,允许其他测试框架如 appium 运行
  553. 参数:
  554. 注意:
  555. 例子:self.pyUIAutomator.stopUIAutomatorService()
  556. '''
  557. def stopUIAutomatorService(self):
  558. self.listenAdbConnected()
  559. try:
  560. self.u.service("uiautomator").stop()
  561. except Exception, e:
  562. print e
  563. '''
  564. 作用:根据传入的chooseType,获取当前界面聚焦的对象
  565. 参数:
  566. 注意:
  567. 例子:self.pyUIAutomator.getChoosedUIObject("focus")
  568. '''
  569. def getChoosedUIObject(self, chooseType, resourceId='', text=''):
  570. if chooseType.lower() == "focus":
  571. return self.getFocusedUIObject(resourceId=resourceId, text=text)
  572. elif chooseType.lower() == "select":
  573. return self.getSelectedUIObject(resourceId=resourceId, text=text)
  574. else:
  575. return None
  576. '''
  577. 作用:获取当前界面的focused的UIObject对象
  578. 参数:
  579. 注意:
  580. 例子:self.pyUIAutomator.getFocusedUIObject()
  581. '''
  582. def getFocusedUIObject(self, resourceId='', text=''):
  583. self.listenAdbConnected()
  584. focusedUIObject = None
  585. try:
  586. if resourceId != "" and text != "":
  587. focusedUIObject = self.u(resourceId=resourceId, text=text, focused=True)
  588. elif resourceId == "" and text != "":
  589. focusedUIObject = self.u(text=text, focused=True)
  590. elif resourceId != "" and text == "":
  591. focusedUIObject = self.u(resourceId=resourceId, focused=True)
  592. else:
  593. focusedUIObject = self.u(focused=True)
  594. except Exception, e:
  595. print "getFocusedUIObject Error:", e
  596. return focusedUIObject
  597. '''
  598. 作用:获取当前界面的selected的UIObject对象
  599. 参数:
  600. 注意:
  601. 例子:self.pyUIAutomator.getFocusedUIObject()
  602. '''
  603. def getSelectedUIObject(self, resourceId='', text=''):
  604. self.listenAdbConnected()
  605. try:
  606. if resourceId != "" and text != "":
  607. selectedUIObject = self.u(resourceId=resourceId, text=text, selected=True)
  608. elif resourceId == "" and text != "":
  609. selectedUIObject = self.u(text=text, selected=True)
  610. elif resourceId != "" and text == "":
  611. selectedUIObject = self.u(resourceId=resourceId, selected=True)
  612. else:
  613. selectedUIObject = self.u(selected=True)
  614. return selectedUIObject
  615. except Exception, e:
  616. print "getSelectedUIObject Error:", e
  617. return None
  618. '''
  619. 作用:在脚本运行过程中,监听弹框的出现,如果出现则按按钮使其消失,使得脚本中获取元素控件时不被遮挡报错
  620. 参数:watcherName 监听器名称
  621. dialogText 弹框的text
  622. buttonText 使弹框消失的按钮text
  623. 注意: 1.这个函数只是创建监听器,这些监听器生效使用u.startWatchers(),监听器失效使用u.stopWatchers();
  624. 2.一般使用在脚本运行实际执行界面前 声明监听器、调用 u.startWatchers(),在脚本 结束时候调用u.stopWatchers()
  625. 例子:self.pyUIAutomator.getFocusedUIObject()
  626. u = PyUIAutomator()
  627. u.createDilogWatcher("Normal Dialog Watcher", "我是一个普通Dialog", "确定")
  628. u.startWatchers()
  629. #这30S延时代表脚本执行
  630. time.sleep(30)
  631. u.stopWatchers()
  632. '''
  633. def createDilogWatcher(self, watcherName, dialogText, buttonText):
  634. self.listenAdbConnected()
  635. self.u.watcher(watcherName).when(text=dialogText).click(text=buttonText)
  636. '''
  637. 作用:使得创建的弹框监听器生效
  638. 参数:
  639. 注意:
  640. '''
  641. def startWatchers(self):
  642. self.listenAdbConnected()
  643. self.u.watchers.watched = True
  644. '''
  645. 作用:使得创建的弹框监听器失效
  646. 参数:
  647. 注意:
  648. '''
  649. def stopWatchers(self):
  650. self.listenAdbConnected()
  651. self.u.watchers.watched = False
  652. def dump_hierarchy(self):
  653. self.listenAdbConnected()
  654. return self.u.dump_hierarchy()
  655. class DirectionManageAndroid():
  656. def __init__(self):
  657. self.className = self.__class__.__name__
  658. self.grid = None
  659. self.remote = TvOperator()
  660. def goOneStep(self, pyUIAutomator, direction, keyType = UATTree.Key_Event):
  661. # keyDict = {'U': "up", "D": "down", "L": "left", "R": "right"}
  662. print "goOneStep,direction:", direction
  663. directionArr = direction.split("-")
  664. for direct in directionArr:
  665. LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(),
  666. u"script:sendKey 执行按键:%s" % (direct))
  667. # self.custSendKey(keyDict[direct])
  668. if keyType == UATTree.Key_Event:
  669. pyUIAutomator.pressKeyTimes(direct)
  670. elif keyType == UATTree.Key_IR:
  671. self.remote.sendKey(direct)
  672. # def custSendKey(self, keyEvent):
  673. # if type(keyEvent) == type('') or type(keyEvent) == type(u""):
  674. # self.operator.sendKey(keyEvent)
  675. # if type(keyEvent) == type([]):
  676. # try:
  677. # self.operator.sendKey(keyEvent[0], keyEvent[1], keyEvent[2])
  678. # except Exception:
  679. # LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(),
  680. # u'script:sendKey ERROR 双击按键数组%s格式出错,请按照格式:[按键字符,按键次数,按键间隔]' % (
  681. # keyEvent))
  682. '''
  683. 计算目标区域在当前焦点区域的方位.
  684. | |
  685. 左上角 | 上 | 右上角
  686. | |
  687. -----------------------------------
  688. | |
  689. | |
  690. 左 | 焦点区域 | 右
  691. | |
  692. -----------------------------------
  693. | |
  694. 左下角 | 下 | 右下角
  695. | |
  696. 区域的方位,按上图,分成4面位方向和4角位方向。
  697. 4面位方向:上、下、左、右。只要目标区域,和4面位方向区域有交集,就属于面位方向。
  698. 4角位方向:左上角、右上角、左下角、右下角。目标区域全部在4角位方向区域,才是角位方向。
  699. 方位定义:up、down、left、right、left-up、left-down、right-up、right-down
  700. :param areaL:当前焦点所在区域
  701. :param areaT:目标区域
  702. :return direction。字符串类型,方位:up、down、left、right、left-up、left-down、right-up、right-down
  703. '''
  704. ImgRectLimit = 10000
  705. def getTargetDirection(self, focusedBounds, destBounds, moveKey=["down","up"]):
  706. areaL = (focusedBounds['left'], focusedBounds['top'], focusedBounds['right'], focusedBounds['bottom'])
  707. areaT = (destBounds['left'], destBounds['top'], destBounds['right'], destBounds['bottom'])
  708. print "getTargetDirection:", areaL, areaT
  709. LoggingUtil.getDebugLogger().info(pyFileName, self.className,
  710. get_current_function_name(),
  711. u'script:focusMatch 当前聚焦区域坐标:%s 目标聚焦区域坐标:%s' % (str(areaL), str(areaT)))
  712. if self.hasSameArea(areaL,areaT):
  713. focusCP = [(areaL[2] + areaL[0])/2,(areaL[3]+areaL[1])/2]
  714. destCP = [(areaT[2] + areaT[0])/2,(areaT[3]+areaT[1])/2]
  715. return self.getPointDirection(focusCP,destCP)
  716. # 确定4个面位方位的区域的x,y轴范围
  717. up = [areaL[0], 0, areaL[2], areaL[1]]
  718. down = [areaL[0], areaL[3], areaL[2], DirectionManageAndroid.ImgRectLimit]
  719. left = [0, areaL[1], areaL[0], areaL[3]]
  720. right = [areaL[2], areaL[1], DirectionManageAndroid.ImgRectLimit, areaL[3]]
  721. # 检测目标区域是否和4个面位方向区域有重叠部分
  722. up_direct = self.hasSameArea(up, areaT)
  723. if up_direct:
  724. return "up"
  725. down_direct = self.hasSameArea(down, areaT)
  726. if down_direct:
  727. return "down"
  728. left_direct = self.hasSameArea(left, areaT)
  729. if left_direct:
  730. return "left"
  731. right_direct = self.hasSameArea(right, areaT)
  732. if right_direct:
  733. return "right"
  734. # 计算目标区域坐上角点的方位,x,y差值确定角位方向
  735. dL_Ux = areaT[0] - areaL[0]
  736. dL_Uy = areaT[1] - areaL[1]
  737. if (dL_Ux > 0) and (dL_Uy > 0):
  738. if "down" in moveKey:
  739. return "down-right"
  740. else:
  741. return "right-down"
  742. if (dL_Ux < 0) and (dL_Uy > 0):
  743. if "down" in moveKey:
  744. return "down-left"
  745. else:
  746. return "left-down"
  747. if (dL_Ux > 0) and (dL_Uy < 0):
  748. if "down" in moveKey:
  749. return "up-right"
  750. else:
  751. return "right-up"
  752. if (dL_Ux < 0) and (dL_Uy < 0):
  753. if "down" in moveKey:
  754. return "up-left"
  755. else:
  756. return "left-up"
  757. '''
  758. 计算点p2相对p1的方位。按p1 45°斜线划分上下左右。
  759. '''
  760. def getPointDirection(self,p1,p2):
  761. print "getPointDirection,p1,p2:",p1,p2
  762. dx = p2[0] - p1[0]
  763. dy = p2[1] - p1[1]
  764. if dx >= 0 and abs(dy) < abs(dx):
  765. return "right"
  766. if dx <= 0 and abs(dy) < abs(dx):
  767. return "left"
  768. if dy >= 0 and abs(dy) >= abs(dx):
  769. return "down"
  770. if dy <= 0 and abs(dy) >= abs(dx):
  771. return "up"
  772. return "center"
  773. '''
  774. 检测两个区域是否有重叠部分
  775. '''
  776. def hasSameArea(self, area1, area2):
  777. # 计算各区域宽、高
  778. area1_W = area1[2] - area1[0]
  779. area1_H = area1[3] - area1[1]
  780. area2_W = area2[2] - area2[0]
  781. area2_H = area2[3] - area2[1]
  782. # 计算目标区域坐上角点的方位
  783. dL_Ux = area1[0] - area2[0]
  784. dL_Uy = area1[1] - area2[1]
  785. # 计算x坐标,判断是否有重叠可能。
  786. x_enable = False
  787. if dL_Ux > 0:
  788. if (abs(dL_Ux) - area2_W) >= 0:
  789. x_enable = False
  790. else:
  791. x_enable = True
  792. else:
  793. if (abs(dL_Ux) - area1_W) >= 0:
  794. x_enable = False
  795. else:
  796. x_enable = True
  797. # 计算y坐标,判断是否有重叠可能。
  798. y_enable = False
  799. if dL_Uy > 0:
  800. if (abs(dL_Uy) - area2_H) >= 0:
  801. y_enable = False
  802. else:
  803. y_enable = True
  804. else:
  805. if (abs(dL_Uy) - area1_H) >= 0:
  806. y_enable = False
  807. else:
  808. y_enable = True
  809. # 如果x坐标、y坐标都有可能重叠,则一定重叠。反之,没有重叠。
  810. return x_enable and y_enable
  811. def isSameBounds(self, BoundA, BoundB):
  812. areaA = (BoundA['left'], BoundA['top'], BoundA['right'], BoundA['bottom'])
  813. areaB = (BoundB['left'], BoundB['top'], BoundB['right'], BoundB['bottom'])
  814. if areaA[0] == areaB[0] \
  815. and areaA[1] == areaB[1] \
  816. and areaA[2] == areaB[2] \
  817. and areaA[3] == areaB[3]:
  818. return True
  819. else:
  820. return False
  821. def isHasAnotherBounds(self, BoundA, BoundB):
  822. areaA = (BoundA['left'], BoundA['top'], BoundA['right'], BoundA['bottom'])
  823. areaB = (BoundB['left'], BoundB['top'], BoundB['right'], BoundB['bottom'])
  824. if areaA[0] <= areaB[0] and areaA[1] <= areaB[1] and areaA[2] >= areaB[2] and areaA[3] >= areaB[3]:
  825. return True
  826. else:
  827. return False
  828. def isRelativePositionBounds(self, initFocusedArea, initDestTextArea, BoundA, BoundB):
  829. # initFocusedArea = (
  830. # initFocusedBound['left'], initFocusedBound['top'], initFocusedBound['right'], initFocusedBound['bottom'])
  831. # initDestTextArea = (
  832. # initFocusedBound['left'], initDestTextBound['top'], initDestTextBound['right'], initDestTextBound['bottom'])
  833. areaA = (BoundA['left'], BoundA['top'], BoundA['right'], BoundA['bottom'])
  834. areaB = (BoundB['left'], BoundB['top'], BoundB['right'], BoundB['bottom'])
  835. # if areaA[0] < areaB[0] and areaA[1] < areaB[1] and areaA[2] > areaB[2] and areaA[3] >areaB[3]:
  836. # return True
  837. # else:
  838. # return False
  839. if initFocusedArea[0] - initDestTextArea[0] == areaA[0] - areaB[0] and initFocusedArea[1] - initDestTextArea[
  840. 1] == areaA[1] - areaB[1] and initFocusedArea[2] - initDestTextArea[2] == areaA[2] - areaB[2] and \
  841. initFocusedArea[3] - initDestTextArea[3] == areaA[3] - areaB[3]:
  842. return True
  843. else:
  844. return False
  845. # 比较两个Bound面积大小
  846. def isBiggerBound(self, boundA, boundB):
  847. # print 'boundA:',boundA
  848. # print 'boundB:',boundB
  849. if ((boundA["bottom"] - boundA["top"]) * (boundA["right"] - boundA["left"])) >= ((
  850. boundB["bottom"] -
  851. boundB["top"]) * (
  852. boundB["right"] -
  853. boundB["left"])):
  854. return True
  855. else:
  856. return False
  857. def getRelativeBounds(self, standBounds_view1, standBounds_view2, currentBound_view1):
  858. currentBound_view2 = {}
  859. currentBound_view2["top"] = standBounds_view2["top"] - standBounds_view1["top"] + currentBound_view1["top"]
  860. currentBound_view2["left"] = standBounds_view2["left"] - standBounds_view1["left"] + currentBound_view1["left"]
  861. currentBound_view2["right"] = standBounds_view2["right"] - standBounds_view1["right"] + currentBound_view1[
  862. "right"]
  863. currentBound_view2["bottom"] = standBounds_view2["bottom"] - standBounds_view1["bottom"] + currentBound_view1[
  864. "bottom"]
  865. return currentBound_view2
  866. class FocusManageAndroid():
  867. # u是PyUIAutomator对象
  868. # focusManage 是DirectionManageAndroid对象
  869. def __init__(self, u, directionManageAndroid):
  870. self.className = self.__class__.__name__
  871. self.u = u
  872. self.directionManageAndroid = directionManageAndroid
  873. self.ReverseDirctionDict = {"up": "down", "down": "up", "left": "right", "right": "left"}
  874. self.featureDetect = FeatureDetect()
  875. self.ccard = CCardManager()
  876. self.imgCMP = ImageCMP()
  877. self.ocr = OCRConvert()
  878. self.remote = TvOperator()
  879. '''
  880. 作用:在RecyclerView 中 focused控件包含文字控件 用于聚焦目标焦点
  881. 参数:
  882. text:目标文字的文字内容
  883. className:目标文字的className
  884. findDirection: 目标文字控件被隐藏时寻找的方向
  885. Max_Try:最多查找次数
  886. 注意:
  887. 例子:
  888. 小米信源设置界面 聚焦到Device Settings/Sound mode
  889. className = "android.widget.TextView"
  890. focusManageAndroid.toDestFocusByText_className_for_RecyclerView("News", className)
  891. '''
  892. # 在RecyclerView 中 focused控件包含文字控件
  893. def toDestFocusByText_className_for_RecyclerView(self, text, className, findDirection="down", Max_Try=10, keyType = UATTree.Key_Event):
  894. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  895. count = 0
  896. Max_Try = Max_Try
  897. Reversecount = 0
  898. Reverse_Max_Try = Max_Try * 2
  899. while (True):
  900. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  901. break
  902. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  903. time.sleep(0.5)
  904. focusedUIObject = self.u.getFocusedUIObject()
  905. focusedBounds = focusedUIObject.info['bounds']
  906. # print "focusedBounds:",focusedBounds
  907. destUIObject = self.u.getUiObject(text=text, className=className)
  908. if destUIObject:
  909. try:
  910. destBounds = destUIObject.info['bounds']
  911. # print "destBounds:", destBounds
  912. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  913. print '成功聚焦到目标焦点:', text
  914. return True
  915. else:
  916. count = count + 1
  917. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  918. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  919. except Exception:
  920. # 出现控件出现一半的时候,获取控件信息会报错
  921. if count < Max_Try:
  922. count = count + 1
  923. self.pressKeyByType(findDirection, keyType)
  924. else:
  925. Reversecount = Reversecount + 1
  926. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  927. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  928. else:
  929. if count < Max_Try:
  930. count = count + 1
  931. self.pressKeyByType(findDirection, keyType)
  932. else:
  933. Reversecount = Reversecount + 1
  934. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  935. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  936. return False
  937. '''
  938. 作用:在RecyclerView 中 focused控件包含文字控件 用于聚焦目标焦点
  939. 参数:
  940. text:目标文字的文字内容
  941. textResourceId:目标文字的resourceId
  942. findDirection: 目标文字控件被隐藏时寻找的方向
  943. Max_Try:最多查找次数
  944. 注意:
  945. 例子:
  946. 小米信源设置界面 聚焦到Device Settings
  947. focusManageAndroid.toDestFocusByText_for_RecyclerView("Device Settings","com.android.tv:id/title")
  948. '''
  949. # 在RecyclerView 中 focused控件包含文字控件
  950. def toDestFocusByText_for_RecyclerView(self, text, textResourceId="", findDirection="down", Max_Try=10, keyType = UATTree.Key_Event, hb_keyDict={}):
  951. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  952. count = 0
  953. Max_Try = Max_Try
  954. Reversecount = 0
  955. Reverse_Max_Try = Max_Try * 2
  956. while (True):
  957. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  958. break
  959. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  960. time.sleep(0.5)
  961. if hb_keyDict != {}:
  962. # 执行心跳按键
  963. self.executeHeartBeatKey(hb_keyDict)
  964. focusedUIObject = self.u.getFocusedUIObject()
  965. try:
  966. focusedBounds = focusedUIObject.info['bounds']
  967. except Exception, e:
  968. print "未能获取到当前聚焦焦点,聚焦框丢失,判断聚焦失败!!"
  969. return False
  970. print "focusedBounds:",focusedBounds
  971. if hb_keyDict != {}:
  972. # 执行心跳按键
  973. self.executeHeartBeatKey(hb_keyDict)
  974. destUIObject = self.u.getUiObject(text=text, resourceId=textResourceId)
  975. if destUIObject:
  976. try:
  977. destBounds = destUIObject.info['bounds']
  978. print "destBounds:", destBounds
  979. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  980. print '成功聚焦到目标焦点:', text
  981. return True
  982. else:
  983. count = count + 1
  984. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  985. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  986. except Exception:
  987. # 出现控件出现一半的时候,获取控件信息会报错
  988. if count < Max_Try:
  989. count = count + 1
  990. self.pressKeyByType(findDirection, keyType)
  991. else:
  992. Reversecount = Reversecount + 1
  993. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  994. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  995. else:
  996. if count < Max_Try:
  997. count = count + 1
  998. self.pressKeyByType(findDirection, keyType)
  999. else:
  1000. Reversecount = Reversecount + 1
  1001. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1002. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1003. return False
  1004. '''
  1005. 作用:在RecyclerView 中 focused控件包含文字控件 用于聚焦目标焦点,传入的resourceId为聚焦焦点的resId时的处理函数
  1006. 参数:
  1007. text:目标文字的文字内容
  1008. focuseResId:整个聚焦焦点的resourceId
  1009. findDirection: 目标文字控件被隐藏时寻找的方向
  1010. Max_Try:最多查找次数
  1011. 注意:
  1012. 例子:
  1013. 小米俄罗斯设置界面 存在复数个聚焦焦点时,使用此函数,可以规避复数焦点的问题
  1014. '''
  1015. def toDestFocusByText_with_FocuseResourceId(self, text, focuseResId, findDirection="down", Max_Try=10, keyType = UATTree.Key_Event, hb_keyDict = {}):
  1016. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1017. count = 0
  1018. Max_Try = Max_Try
  1019. Reversecount = 0
  1020. Reverse_Max_Try = Max_Try * 2
  1021. while (True):
  1022. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1023. break
  1024. if hb_keyDict != {}:
  1025. # 执行心跳按键
  1026. self.executeHeartBeatKey(hb_keyDict)
  1027. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1028. time.sleep(0.5)
  1029. focusedUIObject = self.u.getFocusedUIObject(resourceId=focuseResId)
  1030. try:
  1031. focusedBounds = focusedUIObject.info['bounds']
  1032. except Exception, e:
  1033. print "未能获取到当前聚焦焦点,聚焦框丢失,判断聚焦失败!!"
  1034. return False
  1035. print "focusedBounds:",focusedBounds
  1036. if hb_keyDict != {}:
  1037. # 执行心跳按键
  1038. self.executeHeartBeatKey(hb_keyDict)
  1039. destUIObject = self.u.getUiObject(text=text)
  1040. if destUIObject:
  1041. try:
  1042. destBounds = destUIObject.info['bounds']
  1043. print "destBounds:", destBounds
  1044. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1045. print '成功聚焦到目标焦点:', text
  1046. return True
  1047. else:
  1048. count = count + 1
  1049. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1050. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1051. except Exception:
  1052. # 出现控件出现一半的时候,获取控件信息会报错
  1053. if count < Max_Try:
  1054. count = count + 1
  1055. self.pressKeyByType(findDirection, keyType)
  1056. else:
  1057. Reversecount = Reversecount + 1
  1058. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1059. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1060. else:
  1061. if count < Max_Try:
  1062. count = count + 1
  1063. self.pressKeyByType(findDirection, keyType)
  1064. else:
  1065. Reversecount = Reversecount + 1
  1066. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1067. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1068. return False
  1069. '''
  1070. 作用:在RecyclerVi或listView 中 selected控件包含文字控件 用于聚焦目标焦点
  1071. 参数:
  1072. text:目标文字的文字内容
  1073. textResourceId:目标文字的resourceId
  1074. listViewResourceId:RecyclerVi或listView的resourceId
  1075. findDirection: 目标文字控件被隐藏时寻找的方向
  1076. Max_Try:最多查找次数
  1077. 注意:
  1078. 例子:
  1079. 2841项目信源列表聚焦 聚焦到HDMI1
  1080. focusManageAndroid.toDestSelectByText_for_RecyclerView("HDMI1","com.android.tv:id/title","com.android.tv:id/scene_transition_common")
  1081. '''
  1082. def toDestSelectByText_for_RecyclerView(self, text, textResourceId='', optionViewResoucreId='', listViewResourceId='', findDirection="down",
  1083. Max_Try=10, keyType = UATTree.Key_Event, hb_keyDict={}):
  1084. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1085. count = 0
  1086. Max_Try = Max_Try
  1087. Reversecount = 0
  1088. Reverse_Max_Try = Max_Try * 2
  1089. while (True):
  1090. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1091. break
  1092. if hb_keyDict != {}:
  1093. # 执行心跳按键
  1094. self.executeHeartBeatKey(hb_keyDict)
  1095. listViewUIObject = self.u.getUiObject(resourceId=listViewResourceId)
  1096. print "listViewUIObject.info:", listViewUIObject.info
  1097. if optionViewResoucreId != '':
  1098. selectedUIObject = listViewUIObject.child(selected=True, resourceId=optionViewResoucreId)
  1099. else:
  1100. selectedUIObject = listViewUIObject.child(selected=True)
  1101. print "selectedUIObject.info:", selectedUIObject.info
  1102. selectedBounds = selectedUIObject.info['bounds']
  1103. # print "focusedBounds:",focusedBounds
  1104. if hb_keyDict != {}:
  1105. # 执行心跳按键
  1106. self.executeHeartBeatKey(hb_keyDict)
  1107. destUIObject = self.u.getUiObject(text=text, resourceId=textResourceId)
  1108. if destUIObject:
  1109. destBounds = destUIObject.info['bounds']
  1110. # print "destBounds:", destBounds
  1111. if self.directionManageAndroid.isHasAnotherBounds(selectedBounds, destBounds):
  1112. print '成功聚焦到目标焦点:', text
  1113. return True
  1114. else:
  1115. count = count + 1
  1116. direction = self.directionManageAndroid.getTargetDirection(selectedBounds, destBounds)
  1117. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1118. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1119. else:
  1120. if count < Max_Try:
  1121. count = count + 1
  1122. self.pressKeyByType(findDirection, keyType)
  1123. else:
  1124. Reversecount = Reversecount + 1
  1125. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1126. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1127. return False
  1128. '''
  1129. 作用:在界面中 中 focused控件包含content-des控件 用于聚焦目标焦点
  1130. 参数:
  1131. description:目标描述的文字内容
  1132. descriptionResourceId:目标描述的resourceId
  1133. findDirection: 目标文字控件被隐藏时寻找的方向
  1134. Max_Try:最多查找次数
  1135. 注意:
  1136. 例子:
  1137. 小米APP 聚焦到YouTube
  1138. descriptionResourceId = "com.google.android.tvlauncher:id/banner_image"
  1139. focusManageAndroid.toDestFocusByDescription_for_RecyclerView("YouTube",descriptionResourceId=descriptionResourceId)
  1140. '''
  1141. # 在RecyclerView 中 focused控件包含文字控件
  1142. def toDestFocusByDescription_for_RecyclerView(self, description, descriptionResourceId="", findDirection="down",
  1143. Max_Try=10 ,keyType = UATTree.Key_Event, hb_keyDict = {}):
  1144. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1145. count = 0
  1146. Max_Try = Max_Try
  1147. Reversecount = 0
  1148. Reverse_Max_Try = Max_Try * 2
  1149. while (True):
  1150. print "count:", count
  1151. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1152. break
  1153. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1154. time.sleep(0.5)
  1155. if hb_keyDict != {}:
  1156. # 执行心跳按键
  1157. self.executeHeartBeatKey(hb_keyDict)
  1158. focusedUIObject = self.u.getFocusedUIObject()
  1159. focusedBounds = focusedUIObject.info['bounds']
  1160. # print "focusedBounds:",focusedBounds
  1161. if hb_keyDict != {}:
  1162. # 执行心跳按键
  1163. self.executeHeartBeatKey(hb_keyDict)
  1164. destUIObject = self.u.getUiObject(description=description, resourceId=descriptionResourceId)
  1165. if destUIObject:
  1166. try:
  1167. destBounds = destUIObject.info['bounds']
  1168. # print "destBounds:", destBounds
  1169. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1170. print '成功聚焦到目标焦点:', description
  1171. return True
  1172. else:
  1173. count = count + 1
  1174. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1175. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1176. except Exception, e:
  1177. # 出现控件出现一半的时候,获取控件信息会报错
  1178. if count < Max_Try:
  1179. count = count + 1
  1180. self.pressKeyByType(findDirection, keyType)
  1181. else:
  1182. Reversecount = Reversecount + 1
  1183. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1184. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1185. else:
  1186. if count < Max_Try:
  1187. count = count + 1
  1188. self.pressKeyByType(findDirection, keyType)
  1189. else:
  1190. Reversecount = Reversecount + 1
  1191. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1192. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1193. return False
  1194. # 在RecyclerView 中 focused控件包含bounds控件
  1195. def toDestFocusByBounds_for_RecyclerView(self, bounds, boundsResourceId="", findDirection="down",
  1196. Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
  1197. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1198. count = 0
  1199. Max_Try = Max_Try
  1200. Reversecount = 0
  1201. Reverse_Max_Try = Max_Try * 2
  1202. while (True):
  1203. print "count:", count
  1204. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1205. break
  1206. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1207. time.sleep(0.5)
  1208. if hb_keyDict != {}:
  1209. # 执行心跳按键
  1210. self.executeHeartBeatKey(hb_keyDict)
  1211. focusedUIObject = self.u.getFocusedUIObject()
  1212. focusedBounds = focusedUIObject.info['bounds']
  1213. if hb_keyDict != {}:
  1214. # 执行心跳按键
  1215. self.executeHeartBeatKey(hb_keyDict)
  1216. try:
  1217. destBounds = bounds
  1218. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds,destBounds):
  1219. print "success to focus the target:",bounds
  1220. return True
  1221. else:
  1222. count = count + 1
  1223. direction = self.directionManageAndroid.getTargetDirection(focusedBounds,destBounds)
  1224. self.directionManageAndroid.goOneStep(self.u,direction,keyType)
  1225. except Exception,e:
  1226. # 出现控件出现一半的时候,获取控件信息会报错
  1227. if count < Max_Try:
  1228. count = count + 1
  1229. self.pressKeyByType(findDirection, keyType)
  1230. else:
  1231. Reversecount = Reversecount + 1
  1232. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1233. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1234. else:
  1235. if count < Max_Try:
  1236. count = count + 1
  1237. self.pressKeyByType(findDirection, keyType)
  1238. else:
  1239. Reversecount = Reversecount + 1
  1240. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1241. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1242. return False
  1243. # class&Bounds
  1244. def toDestFocusByClassBounds_for_RecyclerView(self, className, bounds,classResourceId="", findDirection="down",
  1245. Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
  1246. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1247. count = 0
  1248. Max_Try = Max_Try
  1249. Reversecount = 0
  1250. Reverse_Max_Try = Max_Try * 2
  1251. while (True):
  1252. print "count:", count
  1253. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1254. break
  1255. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1256. time.sleep(0.5)
  1257. if hb_keyDict != {}:
  1258. # 执行心跳按键
  1259. self.executeHeartBeatKey(hb_keyDict)
  1260. focusedUIObject = self.u.getFocusedUIObject()
  1261. print "zhouyifocusedUIObject",focusedUIObject
  1262. print "zhouyifocusedUIObject.info", focusedUIObject.info
  1263. if hb_keyDict != {}:
  1264. # 执行心跳按键
  1265. self.executeHeartBeatKey(hb_keyDict)
  1266. destUIObject = self.u.getUiObject(className=className, bounds = bounds,resourceId=classResourceId)
  1267. print "destUIObject",destUIObject
  1268. try:
  1269. destUIObjectInfo = destUIObject.info
  1270. print "destUIObjectInfo",destUIObjectInfo
  1271. except Exception,e:
  1272. print "异常:",e
  1273. # print "destUIObject.info",destUIObjectInfo
  1274. try:
  1275. # destBounds = destUIObject.info['bounds']
  1276. destBounds = bounds
  1277. print "destBounds:", destBounds
  1278. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds,destBounds):
  1279. print "c&b success to focus the target:",bounds
  1280. return True
  1281. else:
  1282. count = count + 1
  1283. direction = self.directionManageAndroid.getTargetDirection(focusedBounds,destBounds)
  1284. self.directionManageAndroid.goOneStep(self.u,direction,keyType)
  1285. except Exception,e:
  1286. # 出现控件出现一半的时候,获取控件信息会报错
  1287. if count < Max_Try:
  1288. count = count + 1
  1289. self.pressKeyByType(findDirection, keyType)
  1290. else:
  1291. Reversecount = Reversecount + 1
  1292. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1293. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1294. else:
  1295. if count < Max_Try:
  1296. count = count + 1
  1297. self.pressKeyByType(findDirection, keyType)
  1298. else:
  1299. Reversecount = Reversecount + 1
  1300. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1301. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1302. return False
  1303. # class
  1304. def toDestFocusByClass_for_RecyclerView(self, className, classResourceId="", findDirection="down",
  1305. Max_Try=10, keyType=UATTree.Key_Event, hb_keyDict={}):
  1306. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1307. count = 0
  1308. Max_Try = Max_Try
  1309. Reversecount = 0
  1310. Reverse_Max_Try = Max_Try * 2
  1311. while (True):
  1312. print "count:", count
  1313. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1314. break
  1315. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1316. time.sleep(0.5)
  1317. if hb_keyDict != {}:
  1318. # 执行心跳按键
  1319. self.executeHeartBeatKey(hb_keyDict)
  1320. focusedUIObject = self.u.getFocusedUIObject()
  1321. print "zhouyifocusedUIObject", focusedUIObject
  1322. print "zhouyifocusedUIObject.info", focusedUIObject.info
  1323. if hb_keyDict != {}:
  1324. # 执行心跳按键
  1325. self.executeHeartBeatKey(hb_keyDict)
  1326. destUIObject = self.u.getUiObject(className=className, resourceId=classResourceId)
  1327. print "destUIObject", destUIObject
  1328. try:
  1329. destUIObjectInfo = destUIObject.info
  1330. print "destUIObjectInfo", destUIObjectInfo
  1331. except Exception, e:
  1332. print "异常:", e
  1333. # print "destUIObject.info",destUIObjectInfo
  1334. try:
  1335. destBounds = destUIObject.info['bounds']
  1336. print "destBounds:", destBounds
  1337. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1338. print '成功聚焦到目标焦点:', bounds
  1339. return True
  1340. else:
  1341. count = count + 1
  1342. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1343. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1344. except Exception, e:
  1345. # 出现控件出现一半的时候,获取控件信息会报错
  1346. if count < Max_Try:
  1347. count = count + 1
  1348. self.pressKeyByType(findDirection, keyType)
  1349. else:
  1350. Reversecount = Reversecount + 1
  1351. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1352. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1353. else:
  1354. if count < Max_Try:
  1355. count = count + 1
  1356. self.pressKeyByType(findDirection, keyType)
  1357. else:
  1358. Reversecount = Reversecount + 1
  1359. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1360. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1361. return False
  1362. # zhouyi
  1363. def toDestTargetByBounds_for_RecyclerView(self, bounds, chooseType, Max_Try=20,
  1364. keyType=UATTree.Key_Event, findFocusCount=0, hb_keyDict={}):
  1365. count = 0
  1366. while (True):
  1367. if hb_keyDict != {}:
  1368. # 执行心跳按键
  1369. self.executeHeartBeatKey(hb_keyDict)
  1370. # targetUIObject = self.u.getUiObject(bounds=bounds)
  1371. # print "targetUIObject",targetUIObject
  1372. # print "zhouyibounds",bounds
  1373. # print "targetUIObject.info:", targetUIObject.info
  1374. # destBounds = targetUIObject.info['bounds']
  1375. destBounds = bounds
  1376. print "目标坐标:", destBounds
  1377. if hb_keyDict != {}:
  1378. # 执行心跳按键
  1379. self.executeHeartBeatKey(hb_keyDict)
  1380. try:
  1381. if chooseType.lower() == "focus":
  1382. choosingUIObject = self.u.getFocusedUIObject()
  1383. objBounds = choosingUIObject.info['bounds']
  1384. elif chooseType.lower() == "select":
  1385. choosingUIObject = self.u.getSelectedUIObject()
  1386. objBounds = choosingUIObject.info['bounds']
  1387. print "当前坐标:", objBounds
  1388. except Exception, e:
  1389. print "获取焦点失败!Error:", e
  1390. if findFocusCount < 3:
  1391. self.u.pressKeyTimes("down")
  1392. return self.toDestTargetByBounds_for_RecyclerView(bounds, chooseType,
  1393. findFocusCount=findFocusCount + 1)
  1394. else:
  1395. print "尝试%s次操作!!!仍未能找到聚焦点!!!无法聚焦到目标" % findFocusCount
  1396. return False
  1397. if self.directionManageAndroid.isHasAnotherBounds(objBounds, destBounds):
  1398. print "已聚焦至目标组件!!!"
  1399. return True
  1400. else:
  1401. if count >= Max_Try:
  1402. print "已尝试至最大次数%s次,仍未能聚焦至目标组件!!!" % Max_Try
  1403. return False
  1404. direction = self.directionManageAndroid.getTargetDirection(objBounds, destBounds)
  1405. print "目标方位:", direction
  1406. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1407. count += 1
  1408. '''
  1409. 作用:在界面中 中 focused控件中既没有包含content-des控件属性,也没有text控件属性,
  1410. 采用单张图片模板匹配 用于聚焦目标焦点
  1411. 参数:
  1412. singleImagePath:目标聚焦的单张小图片的地址
  1413. findDirection: 目标文字控件被隐藏时寻找的方向
  1414. Max_Try:最多查找次数
  1415. 注意:
  1416. 例子:
  1417. 小米内销APP(既没有文字text属性也没有描述属性content-des) 聚焦到ATX APP
  1418. singleImagePath = "D:\\ATX_APP.jpg"
  1419. focusManageAndroid.toDestFocusBySingleImage_for_RecyclerView(singleImagePath)
  1420. '''
  1421. # 在RecyclerView 中 focused控件包含文字控件
  1422. def toDestFocusBySingleImage_for_RecyclerView(self, singleImagePath, findDirection="down",
  1423. Max_Try=10 ,keyType = UATTree.Key_Event):
  1424. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1425. count = 0
  1426. Max_Try = Max_Try
  1427. Reversecount = 0
  1428. Reverse_Max_Try = Max_Try * 2
  1429. while (True):
  1430. print "count:", count
  1431. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1432. break
  1433. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1434. time.sleep(0.5)
  1435. focusedUIObject = self.u.getFocusedUIObject()
  1436. focusedBounds = focusedUIObject.info['bounds']
  1437. srceenImgPath = os.path.join(sat_environment.getSATTmpDIR(), "SingleImage_runpath.png")
  1438. self.ccard.takePicture(srceenImgPath)
  1439. resultDict = self.featureDetect.matchSingleImage(srceenImgPath, [0, 0, 1920, 1080], singleImagePath)
  1440. # destUIObject = self.u.getUiObject(description=description, resourceId=descriptionResourceId)
  1441. if resultDict:
  1442. try:
  1443. destBounds_coordinate = resultDict['coordinate']
  1444. # areaA = (BoundA['left'], BoundA['top'], BoundA['right'], BoundA['bottom'])
  1445. destBounds = {"left": destBounds_coordinate[0], "top": destBounds_coordinate[1],
  1446. "right": destBounds_coordinate[2], "bottom": destBounds_coordinate[3]}
  1447. # print "destBounds:", destBounds
  1448. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1449. print '成功聚焦到目标焦点:', singleImagePath
  1450. return True
  1451. else:
  1452. count = count + 1
  1453. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1454. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1455. except Exception, e:
  1456. # 出现控件出现一半的时候,获取控件信息会报错
  1457. if count < Max_Try:
  1458. count = count + 1
  1459. self.pressKeyByType(findDirection, keyType)
  1460. else:
  1461. Reversecount = Reversecount + 1
  1462. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1463. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1464. else:
  1465. if count < Max_Try:
  1466. count = count + 1
  1467. self.pressKeyByType(findDirection, keyType)
  1468. else:
  1469. Reversecount = Reversecount + 1
  1470. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1471. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1472. return False
  1473. '''
  1474. 作用:在界面中 中 focused控件中既没有包含content-des控件属性,也没有text控件属性,
  1475. 采用OCR识别文字 用于聚焦目标焦点
  1476. 参数:
  1477. text:需要OCR识别的文字
  1478. textResourceId:文字区域的resourceId
  1479. recyclerViewResourceId:列表recyclerView的resourceId
  1480. ocrTextBorder:为OCR识别更准确,文字识别坐标需要扩充的边界的值(默认为10)
  1481. OCRDict:OCR识别文字的属性 默认为百度中英文识别
  1482. findDirection: 目标文字控件被隐藏时寻找的方向
  1483. Max_Try:最多查找次数
  1484. 注意:
  1485. 例子:
  1486. '''
  1487. # 在RecyclerView 中 focused控件包含文字控件
  1488. def toDestFocusByOCRText_for_RecyclerView(self, text, textResourceId, recyclerViewResourceId, ocrTextBorder=10,
  1489. OCRDict={"OCR_lan": "CHN_ENG", "OCR_type": 10000},
  1490. findDirection="down",
  1491. Max_Try=10,
  1492. keyType = UATTree.Key_Event):
  1493. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1494. count = 0
  1495. Max_Try = Max_Try
  1496. Reversecount = 0
  1497. Reverse_Max_Try = Max_Try * 2
  1498. while (True):
  1499. print "count:", count
  1500. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1501. break
  1502. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1503. time.sleep(0.5)
  1504. focusedUIObject = self.u.getFocusedUIObject()
  1505. focusedBounds = focusedUIObject.info['bounds']
  1506. # 寻找目标焦点坐标
  1507. childbound = None
  1508. recyclerViewUIObject = self.u.getUiObject(resourceId=recyclerViewResourceId)
  1509. for i in range(recyclerViewUIObject.info["childCount"]):
  1510. childUIObject = recyclerViewUIObject.child_by_instance(i, resourceId=textResourceId)
  1511. try:
  1512. childbound = childUIObject.info["bounds"]
  1513. # 对扩大后的图片坐标进行边界判断
  1514. childbound_Area_left = childbound["left"] - 10
  1515. if childbound_Area_left < 0: childbound_Area_left = 0
  1516. childbound_Area_top = childbound["top"] - 10
  1517. if childbound_Area_top < 0: childbound_Area_top = 0
  1518. childbound_Area_right = childbound["right"] + 10
  1519. if childbound_Area_right > 1920: childbound_Area_right = 1920
  1520. childbound_Area_bottom = childbound["bottom"] - 10
  1521. if childbound_Area_bottom > 1080: childbound_Area_bottom = 1080
  1522. childbound_Area = (childbound_Area_left, childbound_Area_top,
  1523. childbound_Area_right, childbound_Area_bottom)
  1524. # 小图保存地址
  1525. tmpPic = os.path.join(getSATTmpDIR(), "uiautomator_text_ocr.png")
  1526. # 整个界面图片保存地址
  1527. srceenImgPath = os.path.join(sat_environment.getSATTmpDIR(), "uiautomator_OCR_runpath.png")
  1528. self.u.screenshot(srceenImgPath)
  1529. # self.ccard.takePicture(srceenImgPath)
  1530. # 切割小图片
  1531. self.imgCMP.saveCropPic(srceenImgPath, tmpPic, (
  1532. childbound_Area[0], childbound_Area[1], childbound_Area[2], childbound_Area[3]))
  1533. # ocr 识别
  1534. textValueCUR = self.ocr.getStr(tmpPic, OCRDict["OCR_lan"], OCRDict["OCR_type"])
  1535. print "textValueCUR:", textValueCUR
  1536. print "destText:", text
  1537. if self.ocr.cmpOcrStr(textValueCUR, text):
  1538. break
  1539. else:
  1540. childbound = None
  1541. except Exception:
  1542. childbound = None
  1543. pass
  1544. if childbound:
  1545. try:
  1546. destBounds = childbound
  1547. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1548. print '成功聚焦到目标焦点:', text
  1549. return True
  1550. else:
  1551. count = count + 1
  1552. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1553. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1554. except Exception, e:
  1555. # 出现控件出现一半的时候,获取控件信息会报错
  1556. if count < Max_Try:
  1557. count = count + 1
  1558. self.pressKeyByType(findDirection, keyType)
  1559. else:
  1560. Reversecount = Reversecount + 1
  1561. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1562. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1563. else:
  1564. if count < Max_Try:
  1565. count = count + 1
  1566. self.pressKeyByType(findDirection, keyType)
  1567. else:
  1568. Reversecount = Reversecount + 1
  1569. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1570. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1571. return False
  1572. '''
  1573. 作用:在界面中 中 focused控件中既没有包含content-des控件属性,也没有text控件属性,
  1574. 一般这种控件是自定义控件 class类型是android.view.View
  1575. 采用OCR识别文字 用于聚焦目标焦点
  1576. 参数:
  1577. text:需要OCR识别的文字
  1578. visableViewResourceId:可以通过UIAutomator框架获取到的控件的id
  1579. initTextArea: 确定的一个区域下的文字坐标
  1580. initVisableViewArea:确定的一个区域下的可获取控件的坐标
  1581. ocrTextBorder:为OCR识别更准确,文字识别坐标需要扩充的边界的值(默认为10)
  1582. OCRDict:OCR识别文字的属性 默认为百度中英文识别
  1583. findDirection: 目标文字控件被隐藏时寻找的方向
  1584. Max_Try:最多查找次数
  1585. 注意:
  1586. 例子:小米内销APP测试
  1587. #文字内容
  1588. text = "应用商店"
  1589. #图标的resourceId
  1590. visableViewResourceId = "com.mitv.tvhome:id/di_img"
  1591. #非聚焦的app文字坐标
  1592. initTextArea = [90, 392, 229, 424]
  1593. #非聚焦的app图片坐标
  1594. initVisableViewArea = [90, 257, 227, 382]
  1595. focusManageAndroid.toDestFocusRelativeOCRText__for_RecyclerView(text=text,
  1596. visableViewResourceId=visableViewResourceId,
  1597. initTextArea=initTextArea,
  1598. initVisableViewArea=initVisableViewArea)
  1599. '''
  1600. # 在RecyclerView 中 focused控件包含文字控件
  1601. def toDestFocusRelativeOCRText__for_RecyclerView(self, text, visableViewResourceId, initTextArea,
  1602. initVisableViewArea, ocrTextBorder=5,
  1603. OCRDict={"OCR_lan": "CHN_ENG", "OCR_type": 10000},
  1604. findDirection="down",
  1605. Max_Try=10,
  1606. keyType = UATTree.Key_Event):
  1607. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1608. count = 0
  1609. Max_Try = Max_Try
  1610. Reversecount = 0
  1611. Reverse_Max_Try = Max_Try * 2
  1612. initTextBounds = {"left": initTextArea[0], "top": initTextArea[1], "right": initTextArea[2],
  1613. "bottom": initTextArea[3]}
  1614. initvisableViewBounds = {"left": initVisableViewArea[0], "top": initVisableViewArea[1],
  1615. "right": initVisableViewArea[2], "bottom": initVisableViewArea[3]}
  1616. while (True):
  1617. print "count:", count
  1618. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1619. break
  1620. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1621. time.sleep(0.5)
  1622. focusedUIObject = self.u.getFocusedUIObject()
  1623. focusedBounds = focusedUIObject.info['bounds']
  1624. # 寻找目标焦点坐标
  1625. childbound = None
  1626. childCountUIObject = self.u.getUiObject(resourceId=visableViewResourceId)
  1627. print "childCountUIObject.info", childCountUIObject.info
  1628. childCount = childCountUIObject.count
  1629. print "列表包含的子控件数量:", childCount
  1630. for i in range(childCount):
  1631. print "第%s次查找目标bounds" % (str(i))
  1632. visableViewObject = self.u.getUiObject(instance=i, resourceId=visableViewResourceId)
  1633. try:
  1634. visableViewBound = visableViewObject.info["bounds"]
  1635. print "initvisableViewBounds:", initvisableViewBounds
  1636. print "initTextBounds:", initTextBounds
  1637. print "visableViewBound:", visableViewBound
  1638. childbound = self.directionManageAndroid.getRelativeBounds(initvisableViewBounds, initTextBounds,
  1639. visableViewBound)
  1640. print "childbound:", childbound
  1641. # return False
  1642. # childbound = childUIObject.info["bounds"]
  1643. # 对扩大后的图片坐标进行边界判断
  1644. childbound_Area_left = childbound["left"] - 10
  1645. if childbound_Area_left < 0: childbound_Area_left = 0
  1646. childbound_Area_top = childbound["top"] - 10
  1647. if childbound_Area_top < 0: childbound_Area_top = 0
  1648. childbound_Area_right = childbound["right"] + 10
  1649. if childbound_Area_right > 1920: childbound_Area_right = 1920
  1650. childbound_Area_bottom = childbound["bottom"] + 10
  1651. if childbound_Area_bottom > 1080: childbound_Area_bottom = 1080
  1652. childbound_Area = [childbound_Area_left, childbound_Area_top,
  1653. childbound_Area_right, childbound_Area_bottom]
  1654. print "childbound_Area:", childbound_Area
  1655. # 小图保存地址
  1656. tmpPic = os.path.join(getSATTmpDIR(), "uiautomator_text_ocr.png")
  1657. # 整个界面图片保存地址
  1658. srceenImgPath = os.path.join(sat_environment.getSATTmpDIR(), "uiautomator_OCR_runpath.png")
  1659. self.u.screenshot(srceenImgPath)
  1660. # self.ccard.takePicture(srceenImgPath)
  1661. # 切割小图片
  1662. self.imgCMP.saveCropPic(srceenImgPath, tmpPic, (
  1663. childbound_Area[0], childbound_Area[1], childbound_Area[2], childbound_Area[3]))
  1664. # ocr 识别
  1665. textValueCUR = self.ocr.getStr(tmpPic, OCRDict["OCR_lan"], OCRDict["OCR_type"])
  1666. print "textValueCUR:", textValueCUR
  1667. print "destText:", text
  1668. if self.ocr.cmpOcrStr(textValueCUR, text):
  1669. break
  1670. else:
  1671. childbound = None
  1672. except Exception, e:
  1673. print e
  1674. childbound = None
  1675. pass
  1676. print "childbound:", childbound
  1677. # return False
  1678. if childbound:
  1679. try:
  1680. destBounds = childbound
  1681. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1682. print '成功聚焦到目标焦点:', text
  1683. return True
  1684. else:
  1685. count = count + 1
  1686. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1687. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1688. except Exception, e:
  1689. # 出现控件出现一半的时候,获取控件信息会报错
  1690. if count < Max_Try:
  1691. count = count + 1
  1692. self.pressKeyByType(findDirection, keyType)
  1693. else:
  1694. Reversecount = Reversecount + 1
  1695. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1696. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1697. else:
  1698. if count < Max_Try:
  1699. count = count + 1
  1700. self.pressKeyByType(findDirection, keyType)
  1701. else:
  1702. Reversecount = Reversecount + 1
  1703. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1704. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1705. return False
  1706. '''
  1707. 作用:在RecyclerView 中 focused控件和文字控件同级 相对位置固定 用于聚焦目标焦点
  1708. 参数:
  1709. text:目标文字的文字内容
  1710. textResourceId:目标文字的resourceId
  1711. initFocusedArea:聚焦情况下的focused控件的坐标区域(x1,y1,x2,y2)
  1712. initDestTextArea:聚焦情况下的text控件的坐标区域(x1,y1,x2,y2)
  1713. findDirection: 目标文字控件被隐藏时寻找的方向
  1714. Max_Try:最多查找次数
  1715. 注意:
  1716. 例子:
  1717. 小米信源设置 的声音自定义界面 Device /Settings Sound mode /Custom/
  1718. initFocusedArea = (822, 180, 1259, 221)
  1719. initDestTextArea = (822, 116, 1259, 180)
  1720. focusManageAndroid.toDestFocusRelativeText_for_RecyclerView("3500Hz: 0dB", "com.android.tv:id/title",
  1721. initFocusedArea, initDestTextArea)
  1722. '''
  1723. # 在RecyclerView 中 focused控件和文字控件同级
  1724. def toDestFocusRelativeText_for_RecyclerView(self, text, textResourceId, initFocusedArea, initDestTextArea,
  1725. findDirection="down", Max_Try=10, keyType = UATTree.Key_Event):
  1726. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1727. count = 0
  1728. Max_Try = Max_Try
  1729. Reversecount = 0
  1730. Reverse_Max_Try = Max_Try * 2
  1731. while (True):
  1732. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1733. break
  1734. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1735. time.sleep(0.5)
  1736. focusedUIObject = self.u.getFocusedUIObject()
  1737. focusedBounds = focusedUIObject.info['bounds']
  1738. # print "focusedBounds:",focusedBounds
  1739. destUIObject = self.u.getUiObject(text=text, resourceId=textResourceId)
  1740. if destUIObject:
  1741. try:
  1742. destBounds = destUIObject.info['bounds']
  1743. # print "destBounds:", destBounds
  1744. if self.directionManageAndroid.isRelativePositionBounds(initFocusedArea, initDestTextArea,
  1745. focusedBounds,
  1746. destBounds):
  1747. print '成功聚焦到目标焦点:', text
  1748. return True
  1749. else:
  1750. count = count + 1
  1751. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1752. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1753. except Exception:
  1754. # 出现控件出现一半的时候,获取控件信息会报错
  1755. if count < Max_Try:
  1756. count = count + 1
  1757. self.pressKeyByType(findDirection, keyType)
  1758. else:
  1759. Reversecount = Reversecount + 1
  1760. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1761. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1762. else:
  1763. if count < Max_Try:
  1764. count = count + 1
  1765. self.pressKeyByType(findDirection, keyType)
  1766. else:
  1767. Reversecount = Reversecount + 1
  1768. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1769. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1770. return False
  1771. '''
  1772. 作用:聚焦效果View控件 包含 目标文本控件 用于聚焦目标焦点
  1773. 参数:
  1774. text:目标文字的文字内容
  1775. textResourceId:目标文字的resourceId
  1776. FocusViewResourceId:聚焦效果View的resourceId
  1777. findDirection: 目标文字控件被隐藏时寻找的方向
  1778. Max_Try:最多查找次数
  1779. 注意:
  1780. 例子:
  1781. 小米USB界面上方Tab聚焦方法
  1782. focusManageAndroid.toDestFocusByText_for_FocusView("Devices", "com.xiaomi.mitv.mediaexplorer:id/dev",
  1783. "com.xiaomi.mitv.mediaexplorer:id/tab_cursor",
  1784. findDirection="right",
  1785. Max_Try=5)
  1786. '''
  1787. # 聚焦效果View控件 包含 目标文本控件
  1788. def toDestFocusByText_for_FocusView(self, text, FocusViewResourceId='', FocusViewClass='',FocusViewDesc='',findDirection="down",
  1789. Max_Try=10, keyType = UATTree.Key_Event, hb_keyDict={}):
  1790. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1791. count = 0
  1792. Max_Try = Max_Try
  1793. Reversecount = 0
  1794. Reverse_Max_Try = Max_Try * 2
  1795. while (True):
  1796. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1797. break
  1798. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1799. time.sleep(0.5)
  1800. if hb_keyDict != {}:
  1801. # 执行心跳按键
  1802. self.executeHeartBeatKey(hb_keyDict)
  1803. if FocusViewResourceId is not '':
  1804. focusedUIObject = self.u.getUiObject(resourceId=FocusViewResourceId)
  1805. else:
  1806. focusedUIObject = self.u.getUiObject(description=FocusViewDesc,className=FocusViewClass)
  1807. focusedBounds = focusedUIObject.info['bounds']
  1808. print "focusedBounds:", focusedBounds
  1809. if hb_keyDict != {}:
  1810. # 执行心跳按键
  1811. self.executeHeartBeatKey(hb_keyDict)
  1812. destUIObject = self.u.getUiObject(text=text)
  1813. if destUIObject:
  1814. try:
  1815. destBounds = destUIObject.info['bounds']
  1816. print "destBounds:", destBounds
  1817. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1818. print '成功聚焦到目标焦点:', text
  1819. return True
  1820. else:
  1821. count = count + 1
  1822. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  1823. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1824. except Exception:
  1825. # 出现控件出现一半的时候,获取控件信息会报错
  1826. if count < Max_Try:
  1827. count = count + 1
  1828. self.pressKeyByType(findDirection, keyType)
  1829. else:
  1830. Reversecount = Reversecount + 1
  1831. self.pressKeyByType(self.ReverseDirctionDict[findDirection] ,keyType)
  1832. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1833. else:
  1834. if count < Max_Try:
  1835. count = count + 1
  1836. self.pressKeyByType(findDirection, keyType)
  1837. else:
  1838. Reversecount = Reversecount + 1
  1839. self.pressKeyByType(self.ReverseDirctionDict[findDirection] ,keyType)
  1840. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1841. return False
  1842. '''
  1843. 作用:RecyclerView 中焦点没有focused属性 只是子项中的View有放大效果
  1844. 参数:
  1845. text:目标文字的文字内容
  1846. textResourceId:目标文字的resourceId
  1847. zoomViewResourceId:f放大效果View的resourceId
  1848. recyclerViewResourceId:列表recyclerView 的resourceId
  1849. findDirection: 目标文字控件被隐藏时寻找的方向
  1850. Max_Try:最多查找次数
  1851. 注意:
  1852. 例子:
  1853. 小米USB Images 浏览界面
  1854. focusManageAndroid.toDestZoomByText_for_RecyclerView("Pattern", "com.xiaomi.mitv.mediaexplorer:id/album_item_name",
  1855. "com.xiaomi.mitv.mediaexplorer:id/album_item_bg",
  1856. "com.xiaomi.mitv.mediaexplorer:id/all_albums_view")
  1857. '''
  1858. # RecyclerView 中焦点没有focused属性 只是子项中的View有放大效果
  1859. def toDestZoomByText_for_RecyclerView(self, text, textResourceId, zoomViewResourceId, recyclerViewResourceId,
  1860. findDirection="down",
  1861. Max_Try=20,
  1862. keyType=UATTree.Key_Event):
  1863. # 按照传入的方向寻找Max_Try次,如果仍未聚焦到选中area,则按照传入方向的反方向 反向寻找 2*Max_Try 次
  1864. count = 0
  1865. Max_Try = Max_Try
  1866. Reversecount = 0
  1867. Reverse_Max_Try = Max_Try * 2
  1868. while (True):
  1869. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  1870. break
  1871. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1872. time.sleep(0.5)
  1873. # focusedUIObject = self.u.getUiObject(resourceId=FocusViewResourceId)
  1874. # focusedBounds = focusedUIObject.info['bounds']
  1875. # print "focusedBounds:", focusedBounds
  1876. destUIObject = self.u.getUiObject(text=text, resourceId=textResourceId)
  1877. if destUIObject:
  1878. try:
  1879. # 获取目标文本的bounds
  1880. destBounds = destUIObject.info['bounds']
  1881. # print "destBounds:", destBounds
  1882. zoomUiObject = self.u.getUiObject(resourceId=recyclerViewResourceId)
  1883. # print "uiObject.info: ", uiObject.info
  1884. childCount = zoomUiObject.info['childCount']
  1885. zoomBound = {u'top': 0, u'left': 0, u'right': 0, u'bottom': 0}
  1886. zoomIndex = -1
  1887. for i in range(childCount):
  1888. childObject = zoomUiObject.child_by_instance(i, resourceId=zoomViewResourceId)
  1889. # print "childObject.info:", childObject.info
  1890. childounds = childObject.info['bounds']
  1891. # print "child:", str(i), "bounds:", childounds
  1892. if self.directionManageAndroid.isBiggerBound(childounds, zoomBound):
  1893. zoomBound = childounds
  1894. zoomIndex = i
  1895. zoomTextBound = zoomUiObject.child_by_instance(i, resourceId=textResourceId).info[
  1896. "bounds"]
  1897. zoomText = zoomUiObject.child_by_instance(i, resourceId=textResourceId).info["text"]
  1898. # print zoomBound, zoomIndex, zoomTextBound, zoomText
  1899. print "toDestZoomByText_for_RecyclerView 当前聚焦文字:", zoomText
  1900. if str(zoomText) == str(text):
  1901. print '成功聚焦到目标焦点:', text
  1902. return True
  1903. # if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  1904. # print '成功聚焦到目标焦点:', text
  1905. # return True
  1906. else:
  1907. count = count + 1
  1908. direction = self.directionManageAndroid.getTargetDirection(zoomTextBound, destBounds)
  1909. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  1910. except Exception:
  1911. # 出现控件出现一半的时候,获取控件信息会报错
  1912. if count < Max_Try:
  1913. count = count + 1
  1914. self.pressKeyByType(findDirection, keyType)
  1915. else:
  1916. Reversecount = Reversecount + 1
  1917. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1918. # 如果界面中没有目标文字的控件出现,则按照传入的方向寻找Max_Try次;仍然未找到 则反方向寻找2*Max_Try次
  1919. else:
  1920. if count < Max_Try:
  1921. count = count + 1
  1922. self.pressKeyByType(findDirection, keyType)
  1923. else:
  1924. Reversecount = Reversecount + 1
  1925. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  1926. print "执行%s 次查找,仍未找到目标焦点!!" % (str(Max_Try))
  1927. return False
  1928. '''
  1929. 作用:获取RecyclerView 中所有文字名称的列表
  1930. 参数:
  1931. recyclerViewResourceId:列表recyclerView 的resourceId
  1932. textResourceId:item中文本区域的的resourceId
  1933. findDirection: 目标文字控件被隐藏时寻找的方向
  1934. Max_Try:最多查看次数,执行Max_Try 次findDirection 后 仍无新控件被刷出 则返回所有文件的列表
  1935. name_list:最终返回的列表
  1936. 注意:
  1937. 例子:
  1938. 小米USB Music 浏览界面 获取所有的音乐文件
  1939. recyclerViewResourceId = "com.xiaomi.mitv.mediaexplorer:id/all_music_view"
  1940. textResourceId = "com.xiaomi.mitv.mediaexplorer:id/item_title"
  1941. recyclerViewItemNameList = focusManageAndroid.getRecyclerViewItemNameList(recyclerViewResourceId,textResourceId)
  1942. print "recyclerViewItemNameList:", recyclerViewItemNameList
  1943. '''
  1944. def getRecyclerViewItemNameList(self, recyclerViewResourceId, textResourceId, findDirection="down",
  1945. Max_Try=10, name_list=[], keyType = UATTree.Key_Event):
  1946. count = 0
  1947. isNOTChange = False
  1948. old_name_list = name_list
  1949. while (True):
  1950. if count > Max_Try and isNOTChange:
  1951. return name_list
  1952. break
  1953. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  1954. time.sleep(0.5)
  1955. recyclerViewUIObject = self.u.getUiObject(resourceId=recyclerViewResourceId)
  1956. for i in range(recyclerViewUIObject.info["childCount"]):
  1957. childUIObject = recyclerViewUIObject.child_by_instance(i, resourceId=textResourceId)
  1958. try:
  1959. childText = childUIObject.info["text"]
  1960. if childText not in name_list:
  1961. name_list.append(childUIObject.info["text"])
  1962. except Exception:
  1963. pass
  1964. if old_name_list == name_list:
  1965. isNOTChange = True
  1966. count = count + 1
  1967. self.pressKeyByType(findDirection, keyType)
  1968. else:
  1969. isNOTChange = False
  1970. self.pressKeyByType(findDirection, keyType)
  1971. self.getRecyclerViewItemNameList(recyclerViewResourceId, textResourceId, findDirection,
  1972. Max_Try, name_list)
  1973. '''
  1974. 作用:获取RecyclerView 中所有文字名称的列表
  1975. 参数:
  1976. keyText:寻找目标Text的key的Text
  1977. keyResourceId:寻找目标Text的key的resourceId
  1978. recyclerViewResourceId:列表recyclerView 的resourceId
  1979. textResourceId:目标text的中文本区域的的resourceId
  1980. findDirection: 目标文字控件被隐藏时寻找的方向
  1981. Max_Try:最多查看次数,执行Max_Try 次findDirection 后 仍无新控件被刷出 则返回""
  1982. 注意:
  1983. 例子:
  1984. 小米USB Music 音乐播放界面 通过音乐名称获取音乐时长
  1985. keyResourceId = "com.xiaomi.mimusic2:id/item_textview"
  1986. recyclerViewResourceId = "com.xiaomi.mimusic2:id/music_list_view"
  1987. textResourceId = "com.xiaomi.mimusic2:id/music_list_item_duration"
  1988. findText = focusManageAndroid.getRecyclerViewItemTextByKeyText("鸭子", keyResourceId,
  1989. recyclerViewResourceId,
  1990. textResourceId)
  1991. print "findText:", findText
  1992. '''
  1993. def getRecyclerViewItemTextByKeyText(self, keyText, keyResourceId, recyclerViewResourceId, textResourceId,
  1994. findDirection="down",
  1995. Max_Try=20,
  1996. keyType = UATTree.Key_Event):
  1997. count = 0
  1998. Reversecount = 0
  1999. Reverse_Max_Try = Max_Try * 2
  2000. while (True):
  2001. if count >= Max_Try and Reversecount >= Reverse_Max_Try:
  2002. break
  2003. # 等待聚焦效果刷新完成,稳定之后再获取相关的属性
  2004. time.sleep(0.5)
  2005. recyclerViewUIObject = self.u.getUiObject(resourceId=recyclerViewResourceId)
  2006. iCounnt = -1
  2007. findText = ""
  2008. print "recyclerViewUIObject.info:", recyclerViewUIObject.info
  2009. for i in range(recyclerViewUIObject.info["childCount"]):
  2010. print "i:", i
  2011. try:
  2012. childUIObject = recyclerViewUIObject.child_by_instance(i, resourceId=keyResourceId)
  2013. if str(childUIObject.info["text"]) == str(keyText):
  2014. iCounnt = i
  2015. findUIObject = recyclerViewUIObject.child_by_instance(i, resourceId=textResourceId)
  2016. findText = findUIObject.info["text"]
  2017. return str(findText)
  2018. except Exception:
  2019. iCounnt = -1
  2020. pass
  2021. if iCounnt == -1:
  2022. if count < Max_Try:
  2023. count = count + 1
  2024. self.pressKeyByType(findDirection, keyType)
  2025. else:
  2026. Reversecount = Reversecount + 1
  2027. self.pressKeyByType(self.ReverseDirctionDict[findDirection], keyType)
  2028. print "执行%s 次查找,仍未找到keyText:%s!!" % (str(Max_Try), str(keyText))
  2029. return ""
  2030. def focusFirstItemFromRecyclerView(self, recyclerView_resId, child_class, Max_Try=20, keyType = UATTree.Key_Event):
  2031. return self.focusItemByIndexFromRecyclerView(recyclerView_resId, child_class, 0, Max_Try, keyType)
  2032. def focusItemByIndexFromRecyclerView(self, recyclerView_resId, child_class, target_index, Max_Try=20,
  2033. keyType = UATTree.Key_Event, hb_keyDict={}):
  2034. count = 0
  2035. recyclerView = self.u.getUiObject(resourceId=recyclerView_resId)
  2036. while(True):
  2037. if hb_keyDict != {}:
  2038. # 执行心跳按键
  2039. self.executeHeartBeatKey(hb_keyDict)
  2040. firstItemUIObject = recyclerView.child_by_instance(target_index, className = child_class)
  2041. print "firstItemUIObject.info:", firstItemUIObject.info
  2042. if hb_keyDict != {}:
  2043. # 执行心跳按键
  2044. self.executeHeartBeatKey(hb_keyDict)
  2045. destBounds = firstItemUIObject.info['bounds']
  2046. print "目标坐标:", destBounds
  2047. focusedUIObject = self.u.getFocusedUIObject()
  2048. focusedBounds = focusedUIObject.info['bounds']
  2049. print "当前坐标:",focusedBounds
  2050. if self.directionManageAndroid.isHasAnotherBounds(focusedBounds, destBounds):
  2051. print "已将焦点归位至第一位!!!"
  2052. return True
  2053. else:
  2054. if count >= Max_Try:
  2055. print "已尝试至最大次数%s次,仍未能使焦点归位至第一位!!!"%Max_Try
  2056. return False
  2057. direction = self.directionManageAndroid.getTargetDirection(focusedBounds, destBounds)
  2058. print "目标方位:",direction
  2059. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  2060. count += 1
  2061. def focusTargetSeekBar(self, target_resId, chooseType, Max_Try=20, keyType = UATTree.Key_Event, findFocusCount = 0):
  2062. count = 0
  2063. while(True):
  2064. targetUIObject = self.u.getUiObject(resourceId=target_resId)
  2065. print "targetUIObject.info:", targetUIObject.info
  2066. destBounds = targetUIObject.info['bounds']
  2067. print "目标坐标:", destBounds
  2068. try:
  2069. if chooseType.lower() == "focus":
  2070. choosingUIObject = self.u.getFocusedUIObject()
  2071. objBounds = choosingUIObject.info['bounds']
  2072. elif chooseType.lower() == "select":
  2073. choosingUIObject = self.u.getSelectedUIObject()
  2074. objBounds = choosingUIObject.info['bounds']
  2075. print "当前坐标:",objBounds
  2076. except Exception,e:
  2077. print "获取焦点失败!Error:",e
  2078. if findFocusCount < 3:
  2079. self.u.pressKeyTimes("down")
  2080. return self.focusTargetSeekBar(target_resId, chooseType, findFocusCount = findFocusCount + 1)
  2081. else:
  2082. print "尝试%s次操作!!!仍未能找到聚焦点!!!无法聚焦到目标"%findFocusCount
  2083. return False
  2084. if self.directionManageAndroid.isHasAnotherBounds(objBounds, destBounds):
  2085. print "已聚焦至目标seekbar!!!"
  2086. return True
  2087. else:
  2088. if count >= Max_Try:
  2089. print "已尝试至最大次数%s次,仍未能聚焦至目标seekbar!!!"%Max_Try
  2090. return False
  2091. direction = self.directionManageAndroid.getTargetDirection(objBounds, destBounds)
  2092. print "目标方位:",direction
  2093. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  2094. count += 1
  2095. def toDestTargetByResourceId_for_RecyclerView(self, resourceId, chooseType, Max_Try=20,
  2096. keyType = UATTree.Key_Event, findFocusCount = 0, hb_keyDict={}):
  2097. count = 0
  2098. while(True):
  2099. if hb_keyDict != {}:
  2100. # 执行心跳按键
  2101. self.executeHeartBeatKey(hb_keyDict)
  2102. targetUIObject = self.u.getUiObject(resourceId=resourceId)
  2103. print "targetUIObject.info:", targetUIObject.info
  2104. destBounds = targetUIObject.info['bounds']
  2105. print "目标坐标:", destBounds
  2106. if hb_keyDict != {}:
  2107. # 执行心跳按键
  2108. self.executeHeartBeatKey(hb_keyDict)
  2109. try:
  2110. if chooseType.lower() == "focus":
  2111. choosingUIObject = self.u.getFocusedUIObject()
  2112. objBounds = choosingUIObject.info['bounds']
  2113. elif chooseType.lower() == "select":
  2114. choosingUIObject = self.u.getSelectedUIObject()
  2115. objBounds = choosingUIObject.info['bounds']
  2116. print "当前坐标:",objBounds
  2117. except Exception,e:
  2118. print "获取焦点失败!Error:",e
  2119. if findFocusCount < 3:
  2120. self.u.pressKeyTimes("down")
  2121. return self.toDestTargetByResourceId_for_RecyclerView(resourceId, chooseType, findFocusCount = findFocusCount + 1)
  2122. else:
  2123. print "尝试%s次操作!!!仍未能找到聚焦点!!!无法聚焦到目标"%findFocusCount
  2124. return False
  2125. if self.directionManageAndroid.isHasAnotherBounds(objBounds, destBounds):
  2126. print "已聚焦至目标组件!!!"
  2127. return True
  2128. else:
  2129. if count >= Max_Try:
  2130. print "已尝试至最大次数%s次,仍未能聚焦至目标组件!!!"%Max_Try
  2131. return False
  2132. direction = self.directionManageAndroid.getTargetDirection(objBounds, destBounds)
  2133. print "目标方位:",direction
  2134. self.directionManageAndroid.goOneStep(self.u, direction, keyType)
  2135. count += 1
  2136. def pressKeyByType(self, keyName, keyType = UATTree.Key_Event, times = 1, duration = 1.0):
  2137. print "pressKeyByType:",keyName,keyType
  2138. if keyType == UATTree.Key_Event:
  2139. return self.u.pressKeyTimes(keyName, times, duration)
  2140. elif keyType == UATTree.Key_IR:
  2141. return self.remote.sendKey(keyName, times, duration)
  2142. else:
  2143. return False
  2144. '''
  2145. 执行心跳按键的函数。传入UATree里parent['others']['heartbeat_key']中的参数,会根据参数的配置执行心跳按键
  2146. '''
  2147. def executeHeartBeatKey(self, hb_keyDict):
  2148. try:
  2149. eventList = hb_keyDict["event"]
  2150. irList = hb_keyDict["ir"]
  2151. if eventList != "":
  2152. LoggingUtil.printLog("Executing heartbeat_key by EventKey!!!KeyList:%s" % eventList)
  2153. for key in eventList:
  2154. self.u.pressKeyTimes(key)
  2155. elif irList != "":
  2156. LoggingUtil.printLog("Executing heartbeat_key by irKey!!!KeyList:%s" % irList)
  2157. for key in irList:
  2158. self.remote.sendKey(key)
  2159. except Exception,e:
  2160. LoggingUtil.printLog(u"[executeHeartBeatKey]: 心跳按键配置异常,无法正常执行心跳按键。\n %s"%e)
  2161. if __name__ == "__main__":
  2162. u = PyUIAutomator()
  2163. dm = DirectionManageAndroid()
  2164. fm = FocusManageAndroid(u, dm)
  2165. fm.toDestFocusByText_with_FocuseResourceId(text="Picture", focuseResId="com.mediatek.wwtv.tvcenter:id/menu_item_frame")
  2166. # directionMange = DirectionManageAndroid()
  2167. # focusManage = FocusManageAndroid(u, directionMange)
  2168. # focusObj = focusManage.u.getFocusedUIObject()
  2169. # print "focusObj.info:",focusObj.info
  2170. # childCount = focusObj.info["childCount"]
  2171. # for i in range(childCount):
  2172. # childUI = focusObj.child_by_instance(i, className = "android.widget.TextView")
  2173. # print childUI.info["text"]
  2174. # focusManage.toDestFocusByText_for_RecyclerView(text="Picture mode",textResourceId="",
  2175. # findDirection="down")
  2176. # focusManage.focusTargetSeekBar("com.android.tv.settings:id/seekbar_freq_300")
  2177. # recyclerViewUIObject = u.getUiObject(resourceId="com.xiaomi.mitv.mediaexplorer:id/photo_list")
  2178. # print "recyclerViewUIObject.info", recyclerViewUIObject.info
  2179. # for i in range(recyclerViewUIObject.info["childCount"]):
  2180. # childUI = recyclerViewUIObject.child_by_instance(i)
  2181. # print "cound %s child.info:"%i, childUI.info
  2182. # focusManage.focusFirstItemFromRecyclerView(recyclerViewUIObject, child_class="android.widget.LinearLayout")
  2183. # focusedUIObject = pyui.getFocusedUIObject()
  2184. # print 'focusedUIObject:', focusedUIObject
  2185. # if focusedUIObject:
  2186. # print focusedUIObject.info