python_uiautomator.py 117 KB

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