python_uiautomator.py 114 KB

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