python_uiautomator.py 92 KB

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