PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/AndroidAdapter/ui_keywords.py

https://github.com/jaaskel9/tema-android-adapter
Python | 1250 lines | 1213 code | 8 blank | 29 comment | 2 complexity | a7c7774ee28131b70baac09b3a392edb MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2006-2010 Tampere University of Technology
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining
  5. # a copy of this software and associated documentation files (the
  6. # "Software"), to deal in the Software without restriction, including
  7. # without limitation the rights to use, copy, modify, merge, publish,
  8. # distribute, sublicense, and/or sell copies of the Software, and to
  9. # permit persons to whom the Software is furnished to do so, subject to
  10. # the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be
  13. # included in all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. import re
  23. import time
  24. import subprocess
  25. import socket
  26. import ConfigParser
  27. from adapterlib.keyword import Keyword
  28. import AndroidAdapter.guireader as guireader
  29. from AndroidAdapter.object_keyword import ObjectKeyword
  30. TAP_INTERVAL = 0.2 #s
  31. NAV_DELAY = 0.5 #s
  32. #-----------------------------------------------------------------------------#
  33. class VerifyText(ObjectKeyword):
  34. """
  35. Verifies if the given text is found from the screen from some GUI object.
  36. If <NoUpdate> -parameter is given, the keyword will not update the GUI
  37. hierarchy, but uses the previous update. This can be used to make execution
  38. faster
  39. If "partial:" parameter is given, the search accepts components where the
  40. text is found somewhere inside its text content.
  41. Usage::
  42. VerifyText [<NoUpdate>][partial:]'text',[object]
  43. """
  44. def __init__(self):
  45. super(VerifyText,self).__init__()
  46. #TODO: Not completed pattern!
  47. pattern = re.compile("(<(?P<style>[^>]+)>\s+)?(?P<partial>partial:)?\'(?P<text>.*)\'(\s*,\s*(?P<component>" + self.componentPattern + "))?")
  48. self.attributePattern = pattern
  49. self.delay = -1
  50. def execute(self):
  51. matcher = self.attributePattern.match(self.attributes)
  52. self.log('text: ' + matcher.group("text"))
  53. #No component specified
  54. if(matcher.group("component") == None):
  55. self.log("Searching from first component showing")
  56. return self.verifyText(matcher.group("text"),partial = (matcher.group("partial") != None), style = matcher.group("style"))
  57. #Component and rolename specified
  58. componentName, rolename = self.matchComponent(matcher.group("component"))
  59. if(componentName == None):
  60. return False
  61. self.log("component: " + componentName)
  62. if(rolename != None):
  63. self.log("rolename: " + rolename)
  64. result = self.verifyText(matcher.group("text"), componentName, rolename, partial = (matcher.group("partial") != None),style = matcher.group("style") )
  65. return result
  66. def verifyText(self, text, rootName="", rolename="", searchNodes = None, partial = False, style = None):
  67. """
  68. Searches the given string under the given node(s).
  69. @type text: string
  70. @param text: Text that is searched.
  71. @type rootName: string
  72. @param rootName: Reference to the component that is used as a root for the search
  73. @type rolename: string
  74. @param rolename: rolename of the search root component (to identify better)
  75. @type searchNodes: list
  76. @param searchNodes: List of ViewItems. If given, this list is used as search roots for
  77. the search, and the rootName and rolename parameters are omitted. Giving the nodes
  78. this way enhanches the performance greatly if multiple verifys are done in a row.
  79. (i.e. waitText)
  80. @rtype: boolean or "ERROR"
  81. @return: True if text was found, false if text was not found and "ERROR" if fatal
  82. errors occured in the search.
  83. """
  84. if style != "NoUpdate":
  85. self._target.getGUIReader().readGUI()
  86. rootNodes = searchNodes
  87. if searchNodes == None:
  88. rootNodes = []
  89. if rootName == 'root' or rootName == '':
  90. rootNodes.append(self.searchroot)
  91. else:
  92. rootNodes = self.findComponent(rootName, rolename, True)
  93. if(rootNodes == None or len(rootNodes) == 0):
  94. self.log("Root node for verification not found")
  95. return False
  96. else:
  97. for node in rootNodes:
  98. #self.log("Searching text: \"" + text + "\" below the node: " + node.name)
  99. #Check children
  100. #if self.findText(text, node,regex):
  101. # return True
  102. if self._target.getGUIReader().findComponentWithText(text, rolename, node, partial = partial) != None:
  103. return True
  104. return False
  105. #-----------------------------------------------------------------------------#
  106. class WaitText(VerifyText):
  107. """
  108. WaitText waits that a desired text appears on screen. Uses Verify text
  109. methods to find the text.
  110. If "regex:" parameter is given, the text parameter is treated as a regular
  111. expression. If any text found mathes with the expression, the keyword
  112. returns true
  113. Usage:
  114. kw_WaitText [regex:]'text',[timeout],[componentReference]
  115. """
  116. def __init__(self):
  117. super(WaitText,self).__init__()
  118. #TODO: Not completed pattern!
  119. #kw_WaitText 'text',[waittime],component[;rolename]
  120. pattern = re.compile('(?P<partial>partial:)?\'(?P<text>.+)\'(\s*,\s*(?P<time>\d+))?(\s*,\s*(?P<component>' + self.componentPattern + '))?')
  121. self.attributePattern = pattern
  122. self.__time = 10 #Default time
  123. def execute(self):
  124. matcher = self.attributePattern.match(self.attributes)
  125. self.log('text: ' + matcher.group("text"))
  126. if matcher.group("component"):
  127. componentName, rolename = self.matchComponent(matcher.group("component"))
  128. if(componentName == None):
  129. return False
  130. else:
  131. componentName = "root"
  132. rolename = ""
  133. self.log("component: " + componentName)
  134. if(rolename != None):
  135. self.log("rolename: " + rolename)
  136. self.__time = matcher.group("time")
  137. if(self.__time == None):
  138. self.__time = 10
  139. else:
  140. self.__time = int(self.__time)
  141. self.log("wait-time: " + str(self.__time))
  142. #Search node is searched here to optimate the verification
  143. #TODO: Create a function for this in Keyword-class
  144. """
  145. searchNodes = []
  146. if componentName == 'root':
  147. searchNodes.append(self.searchroot)
  148. elif componentName.strip() == "":
  149. searchNodes.append(self.findFirstNodeShowing());
  150. else:
  151. searchNodes = self.findComponent(componentName, rolename, True)
  152. if searchNodes == None:
  153. self.log("Root node for verification not found")
  154. return False
  155. """
  156. counter = 1
  157. result = False
  158. searchTime = int(time.time()) + self.__time
  159. while int(time.time()) <= searchTime:
  160. try:
  161. result = self.verifyText(matcher.group("text"), componentName, rolename, searchNodes = None, partial = matcher.group("partial") != None )
  162. #result = self.verifyText(matcher.group(1), searchNodes = searchNodes)
  163. print "search nro:" + str(counter)
  164. counter = counter + 1
  165. except Exception:
  166. pass
  167. if result:
  168. break
  169. time.sleep(0.2)
  170. return result
  171. #-----------------------------------------------------------------------------#
  172. class WaitObject(VerifyText):
  173. """
  174. Kw_WaitText waits that a desired object appears on screen.
  175. Usage:
  176. kw_WaitObject [timeout,]componentReference
  177. """
  178. def __init__(self):
  179. super(WaitObject,self).__init__()
  180. #TODO: Not completed pattern!
  181. #kw_WaitText 'text',[waittime],component[;rolename]
  182. pattern = re.compile('((?P<time>\d+)\s*,\s*)?(?P<component>' + self.componentPattern + ')')
  183. self.attributePattern = pattern
  184. self.__time = 10 #Default time
  185. def execute(self):
  186. matcher = self.attributePattern.match(self.attributes)
  187. self.__time = matcher.group("time")
  188. if(self.__time == None):
  189. self.__time = 10
  190. else:
  191. self.__time = int(self.__time)
  192. self.log("wait-time: " + str(self.__time))
  193. counter = 1
  194. result = False
  195. searchTime = int(time.time()) + self.__time
  196. while int(time.time()) <= searchTime:
  197. try:
  198. result = self.findComponentReference(matcher.group("component")) != None
  199. print "search nro:" + str(counter)
  200. counter = counter + 1
  201. except Exception:
  202. pass
  203. if result:
  204. break
  205. time.sleep(0.2)
  206. return result
  207. #-----------------------------------------------------------------------------#
  208. class SelectFromList(ObjectKeyword):
  209. """
  210. Selects an item from a vertical list of items.
  211. Usage:
  212. kw_SelectFromList 'list_item'
  213. """
  214. def __init__(self):
  215. super(SelectFromList,self).__init__()
  216. pattern = re.compile('\'(?P<item>.*)\'(\s*,\s*(?P<execute>(true|false)))?')
  217. self.attributePattern = pattern
  218. def __getSelectedIndex__(self):
  219. list = None
  220. selectedIndex = None
  221. try:
  222. self._target.getGUIReader().readGUI()
  223. list = self._target.getGUIReader().getListView()
  224. if not list:
  225. print "No ListView found from the screen"
  226. return None, None
  227. selectedIndex = int(list.getProperties()["mSelectedPosition"])
  228. except ValueError:
  229. return None, None
  230. return list, selectedIndex
  231. def execute(self):
  232. matcher = self.attributePattern.match(self.attributes)
  233. self.log('item: ' + matcher.group("item"))
  234. executeItem = matcher.group("execute") == None or matcher.group("execute") == "true"
  235. list, selectedIndex = self.__getSelectedIndex__()
  236. if list == None:
  237. return False
  238. #gui not found
  239. #Give focus to an item in the list
  240. while selectedIndex == -1:
  241. if not self._target.getMonkeyDriver().sendPress("DPAD_DOWN"):
  242. return False
  243. list, selectedIndex = self.__getSelectedIndex__()
  244. if list == None:
  245. return False
  246. item = self._target.getGUIReader().findComponentWithText(matcher.group("item"), rootItem = list, searchAll = False)
  247. #Selected item's index relative to currently shown list part
  248. RelIndex = 0
  249. for c in list.getChildren():
  250. if self._target.getGUIReader().findComponent(lambda x: x.getProperties().has_key("isSelected()") and x.getProperties()["isSelected()"].lower() == "true", c, False):
  251. break
  252. RelIndex +=1
  253. #Scroll list to the top if not already and if the item was not found from the current list part
  254. if selectedIndex > 0 and item == None and RelIndex != selectedIndex:
  255. for i in range(0,selectedIndex):
  256. if not self._target.getMonkeyDriver().sendPress("DPAD_UP"):
  257. return False
  258. time.sleep(NAV_DELAY)
  259. self._target.getGUIReader().readGUI()
  260. #Scroll the list down until the item is seen, or the bottom of the list is reached
  261. while item == None:
  262. list = self._target.getGUIReader().getListView()
  263. item = self._target.getGUIReader().findComponentWithText(matcher.group("item"), rootItem = list, searchAll = False)
  264. selectedIndex = int(list.getProperties()["mSelectedPosition"])
  265. if item:
  266. break
  267. RelCurrentIndex = 0
  268. for c in list.getChildren():
  269. if self._target.getGUIReader().findComponent(lambda x: x.getProperties().has_key("isSelected()") and x.getProperties()["isSelected()"].lower() == "true", c, False):
  270. break
  271. RelCurrentIndex += 1
  272. #If last item of the list is listed, item can't be found
  273. if selectedIndex + (len(list.getChildren()) - RelCurrentIndex) >= int(list.getProperties()["mItemCount"]):
  274. return False
  275. #TODO: Too much scrolling in some situations.
  276. for i in range(0,len(list.getChildren())):
  277. if not self._target.getMonkeyDriver().sendPress("DPAD_DOWN"):
  278. return False
  279. time.sleep(NAV_DELAY)
  280. self._target.getGUIReader().readGUI()
  281. #If item was found, tap it...
  282. if item:
  283. #...only if execute parameter allows
  284. if executeItem:
  285. try:
  286. x,y = self._target.getGUIReader().getViewCoordinates(item)
  287. except guireader.GuiReaderError,e:
  288. print e
  289. return False
  290. return self._target.getMonkeyDriver().sendTap(x,y)
  291. #else make sure the item is in the selected state
  292. else:
  293. currentRelIndex = 0
  294. currentFound = False
  295. itemRelIndex = 0
  296. itemFound = False
  297. for c in list.getChildren():
  298. if self._target.getGUIReader().findComponentWithText(matcher.group("item"), rootItem = c) != None:
  299. itemFound = True
  300. elif not itemFound:
  301. itemRelIndex += 1
  302. if c.getProperties()["isSelected()"] == "true":
  303. currentFound = True
  304. elif not currentFound:
  305. currentRelIndex += 1
  306. press = "DPAD_DOWN"
  307. if itemRelIndex < currentRelIndex:
  308. press = "DPAD_UP"
  309. while item.getProperties()["isSelected()"] == "false":
  310. if not self._target.getMonkeyDriver().sendPress(press):
  311. return False
  312. time.sleep(NAV_DELAY)
  313. self._target.getGUIReader().readGUI()
  314. list = self._target.getGUIReader().getListView()
  315. item = self._target.getGUIReader().findComponentWithText(matcher.group("item"), rootItem = list, searchAll = False)
  316. if not item:
  317. return False
  318. return True
  319. """
  320. #This implementation navigates to the desired item with dpad. It does not work if the list contains items that are not focusable.
  321. RelItemIndex = 0
  322. for c in list.getChildren():
  323. if self._target.getGUIReader().findComponentWithText(matcher.group("item"), rootItem = c, searchAll = False):
  324. break
  325. RelItemIndex +=1
  326. RelCurrentIndex = 0
  327. for c in list.getChildren():
  328. if self._target.getGUIReader().findComponent(lambda x: x.getProperties().has_key("isSelected()") and x.getProperties()["isSelected()"].lower() == "true", c, False):
  329. break
  330. RelCurrentIndex +=1
  331. steps = RelItemIndex - RelCurrentIndex
  332. if steps > 0:
  333. key = "DPAD_DOWN"
  334. else:
  335. key = "DPAD_UP"
  336. for i in range(0,abs(steps)):
  337. if not self._target.getMonkeyDriver().sendPress(key):
  338. return False
  339. if not self._target.getMonkeyDriver().sendPress("DPAD_CENTER"):
  340. return False
  341. return True
  342. """
  343. return False
  344. #-----------------------------------------------------------------------------#
  345. class TapCoordinate(Keyword):
  346. def __init__(self):
  347. super(TapCoordinate,self).__init__()
  348. pattern = re.compile("(?P<x>\d+)\s*,\s*(?P<y>\d+)(\s*,\s*(?P<times>\d+))?")
  349. self.attributePattern = pattern
  350. def doTap(self,x,y):
  351. w, h = self._target.getMonkeyDriver().getScreenSize()
  352. if (int(x) > w or int(y) > h):
  353. print "Invalid coordinates"
  354. return False
  355. return self._target.getMonkeyDriver().sendTap(x,y)
  356. def execute(self):
  357. matcher = self.attributePattern.match(self.attributes)
  358. times = 1
  359. if matcher.group("times"):
  360. times = int(matcher.group("times"))
  361. for i in range(0,times):
  362. if not self.doTap(matcher.group(1),matcher.group(2)):
  363. return False
  364. return True
  365. #-----------------------------------------------------------------------------#
  366. class TapDownCoordinate(TapCoordinate):
  367. def doTap(self,x,y):
  368. return self._target.getMonkeyDriver().sendTouchDown(x,y)
  369. #-----------------------------------------------------------------------------#
  370. class TapUpCoordinate(TapCoordinate):
  371. def doTap(self,x,y):
  372. return self._target.getMonkeyDriver().sendTouchUp(x,y)
  373. #-----------------------------------------------------------------------------#
  374. class LongTapCoordinate(TapCoordinate):
  375. def doTap(self,x,y):
  376. if self._target.getMonkeyDriver().sendTouchDown(x,y):
  377. time.sleep(self.__hold_time)
  378. return self._target.getMonkeyDriver().sendTouchUp(x,y)
  379. return False
  380. def execute(self):
  381. matcher = self.attributePattern.match(self.attributes)
  382. self.__hold_time = 2
  383. if matcher.group("times"):
  384. self.__hold_time = int(matcher.group("times"))
  385. if not self.doTap(matcher.group(1),matcher.group(2)):
  386. return False
  387. return True
  388. #-----------------------------------------------------------------------------#
  389. class MoveToCoordinate(TapCoordinate):
  390. def doTap(self,x,y):
  391. return self._target.getMonkeyDriver().sendTouchMove(x,y)
  392. #-----------------------------------------------------------------------------#
  393. class TapObject(ObjectKeyword):
  394. """
  395. Taps the given component.
  396. Usage:
  397. kw_TapObject componentReferece
  398. """
  399. def __init__(self):
  400. super(TapObject,self).__init__()
  401. pattern = re.compile("((?P<times>\d+)\s*,\s*)?(?P<component>" + self.componentPattern + ")")
  402. self.attributePattern = pattern
  403. def doTapAction(self,x,y):
  404. return self._target.getMonkeyDriver().sendTap(x,y)
  405. def doTap(self,reference, times = 1):
  406. item = self.findComponentReference(reference)
  407. if not item:
  408. return False
  409. try:
  410. x,y = self._target.getGUIReader().getViewCoordinates(item)
  411. except guireader.GuiReaderError,e:
  412. print e
  413. return False
  414. for i in range(0,times):
  415. if not self.doTapAction(x,y):
  416. return False
  417. if times > 1:
  418. time.sleep(TAP_INTERVAL)
  419. return True
  420. def execute(self):
  421. matcher = self.attributePattern.match(self.attributes)
  422. times = 1
  423. if matcher.group("times"):
  424. times = int(matcher.group("times"))
  425. return self.doTap(matcher.group("component"),times)
  426. #-----------------------------------------------------------------------------#
  427. class TapDownObject(TapObject):
  428. def doTapAction(self,x,y):
  429. return self._target.getMonkeyDriver().sendTouchDown(x,y)
  430. #-----------------------------------------------------------------------------#
  431. class TapUpObject(TapObject):
  432. def doTapAction(self,x,y):
  433. return self._target.getMonkeyDriver().sendTouchUp(x,y)
  434. #-----------------------------------------------------------------------------#
  435. class LongTapObject(TapObject):
  436. def doTapAction(self,x,y):
  437. if self._target.getMonkeyDriver().sendTouchDown(x,y):
  438. time.sleep(self.__hold_time)
  439. return self._target.getMonkeyDriver().sendTouchUp(x,y)
  440. return False
  441. def execute(self):
  442. matcher = self.attributePattern.match(self.attributes)
  443. times = 1
  444. self.__hold_time = 2
  445. if matcher.group("times"):
  446. self.__hold_time = int(matcher.group("times"))
  447. return self.doTap(matcher.group("component"),times)
  448. #-----------------------------------------------------------------------------#
  449. class MoveToObject(TapObject):
  450. def doTapAction(self,x,y):
  451. return self._target.getMonkeyDriver().sendTouchMove(x,y)
  452. #-----------------------------------------------------------------------------#
  453. class Drag(ObjectKeyword):
  454. def __init__(self):
  455. super(Drag,self).__init__()
  456. pattern = re.compile("((?P<coord1>(?P<x1>\d+)\s*,\s*(?P<y1>\d+))|(?P<component1>.+))\s*-->\s*((?P<coord2>(?P<x2>\d+)\s*,\s*(?P<y2>\d+))|(?P<component2>.*))")
  457. self.attributePattern = pattern
  458. self._holdtime = 2
  459. self._dragtime = 0.001
  460. self._movepoints = 20
  461. def execute(self):
  462. matcher = self.attributePattern.match(self.attributes)
  463. if matcher.group("coord1"):
  464. x1 = int(matcher.group("x1"))
  465. y1 = int(matcher.group("y1"))
  466. else:
  467. item = self.findComponentReference(matcher.group("component1").strip())
  468. if not item:
  469. return False
  470. try:
  471. x1,y1 = self._target.getGUIReader().getViewCoordinates(item)
  472. except guireader.GuiReaderError,e:
  473. print e
  474. return False
  475. #Tap down the first coordinate
  476. if not self._target.getMonkeyDriver().sendTouchDown(x1,y1):
  477. return False
  478. if matcher.group("coord2"):
  479. x2 = int(matcher.group("x2"))
  480. y2 = int(matcher.group("y2"))
  481. time.sleep(self._holdtime)
  482. else:
  483. item = self.findComponentReference(matcher.group("component2").strip())
  484. if not item:
  485. return False
  486. try:
  487. x2,y2 = self._target.getGUIReader().getViewCoordinates(item)
  488. except guireader.GuiReaderError,e:
  489. print e
  490. return False
  491. #Move to the second coordinate and tap up
  492. for i in range(0,self._movepoints):
  493. if x2 > x1:
  494. nx = x1 + ((x2-x1)/self._movepoints)*i
  495. else:
  496. nx = x1 - ((x1 -x2)/self._movepoints)*i
  497. if x2 > x1:
  498. ny = y1 + ((y2-y1)/self._movepoints)*i
  499. else:
  500. ny = y1 - ((y1 -y2)/self._movepoints)*i
  501. #print nx,ny
  502. if not self._target.getMonkeyDriver().sendTouchMove(nx,ny):
  503. return False
  504. #time.sleep(self._dragtime)
  505. if self._target.getMonkeyDriver().sendTouchUp(x2,y2):
  506. return True
  507. return False
  508. #-----------------------------------------------------------------------------#
  509. class TouchScroll(Drag):
  510. def __init__(self):
  511. super(TouchScroll,self).__init__()
  512. self._holdtime = 0
  513. #-----------------------------------------------------------------------------#
  514. class MoveTrackBall(Keyword):
  515. """
  516. Taps the given component.
  517. Usage:
  518. kw_TapObject componentReferece
  519. """
  520. def __init__(self):
  521. super(MoveTrackBall,self).__init__()
  522. pattern = re.compile("(?P<dx>(-)?\d+)\s*,\s*(?P<dy>(-)?\d+)")
  523. self.attributePattern = pattern
  524. def execute(self):
  525. matcher = self.attributePattern.match(self.attributes)
  526. return self._target.getMonkeyDriver().sendTrackBallMove(matcher.group("dx"),matcher.group("dy"))
  527. #-----------------------------------------------------------------------------#
  528. class SelectFromMenu(TapObject):
  529. """
  530. Selects an item from the menu.
  531. Presses the menu button, and finds the desired item. If the menu does not fit entirely to the screen and contains a "more" option, the item is searched under that menu. If the item is not found, menu will be closed in the end.
  532. Usage:
  533. """
  534. def __init__(self):
  535. super(SelectFromMenu,self).__init__()
  536. pattern = re.compile("(?P<menu>'.*')")
  537. self.attributePattern = pattern
  538. def execute(self):
  539. matcher = self.attributePattern.match(self.attributes)
  540. item = matcher.group("menu")
  541. if not self._target.getMonkeyDriver().sendPress("menu"):
  542. return False
  543. time.sleep(2)
  544. self._target.getGUIReader().readGUI()
  545. if self.doTap(item):
  546. result = True
  547. elif self.doTap("'More'"):
  548. self._target.getGUIReader().readGUI()
  549. result = self.doTap(item)
  550. else:
  551. result = False
  552. if not result:
  553. self._target.getMonkeyDriver().sendPress("menu")
  554. return result
  555. #-----------------------------------------------------------------------------#
  556. class IsTrue(Keyword):
  557. """
  558. Kw_IsTrue returns True or False depending on the parameter
  559. Usage::
  560. kw_IsTrue True
  561. kw_IsTrue False
  562. """
  563. def __init__(self):
  564. super(IsTrue,self).__init__()
  565. pattern = re.compile("((True)|(False))?")
  566. self.attributePattern = pattern
  567. self.delay = -1
  568. self.shouldLog = False
  569. def execute(self):
  570. matcher = self.attributePattern.match(self.attributes)
  571. if(matcher.group(2) != None):
  572. return True
  573. return False
  574. #-----------------------------------------------------------------------------#
  575. class SetTarget(Keyword):
  576. def __init__(self):
  577. super(SetTarget,self).__init__()
  578. pattern = re.compile(".*")
  579. self.attributePattern = pattern
  580. self.delay = -1
  581. def execute(self):
  582. return True
  583. #-----------------------------------------------------------------------------#
  584. class UpdateScreen(Keyword):
  585. def __init__(self):
  586. super(UpdateScreen,self).__init__()
  587. pattern = re.compile("\s*")
  588. self.attributePattern = pattern
  589. self.delay = -1
  590. self.shouldLog = False
  591. def execute(self):
  592. self._target.getGUIReader().readGUI()
  593. return True
  594. #-----------------------------------------------------------------------------#
  595. class Delay(Keyword):
  596. def __init__(self):
  597. super(Delay,self).__init__()
  598. pattern = re.compile("(\\d.)?\\d+")
  599. self.attributePattern = pattern
  600. self.delay = -1
  601. self.shouldLog = False
  602. def execute(self):
  603. matcher = self.attributePattern.match(self.attributes)
  604. if(matcher.group(0) != None):
  605. time.sleep(eval(matcher.group(0)))
  606. return True
  607. return False
  608. #-----------------------------------------------------------------------------#
  609. class Type(Keyword):
  610. """
  611. Inserts text into a component.
  612. Returns false if the component does not support text editation.
  613. Usage:
  614. kw_Type 'text', componentReference
  615. """
  616. def __init__(self):
  617. super(Type,self).__init__()
  618. pattern = re.compile("'(.*)\'")#(\s*,\s*(" + self.componentPattern + "))")
  619. self.attributePattern = pattern
  620. def execute(self):
  621. matcher = self.attributePattern.match(self.attributes)
  622. text = matcher.group(1)
  623. words = text.split(' ')
  624. first = True
  625. for word in words:
  626. if not first:
  627. if not self._target.getMonkeyDriver().sendPress("space"):
  628. return False
  629. if word != '':
  630. if not self._target.getMonkeyDriver().sendType(word):
  631. return False
  632. first = False
  633. return True
  634. #-----------------------------------------------------------------------------#
  635. class PressKey(Keyword):
  636. """
  637. Presses and releases a key
  638. Usage:
  639. Kw_PressKey keyname
  640. """
  641. def __init__(self):
  642. super(PressKey,self).__init__()
  643. pattern = re.compile("(?P<button>\w+)(\s*,\s*(?P<times>\d+))?")
  644. self.attributePattern = pattern
  645. def execute(self):
  646. matcher = self.attributePattern.match(self.attributes)
  647. times = 1
  648. if matcher.group("times"):
  649. times = int(matcher.group("times"))
  650. for i in range(0,times):
  651. if not self._target.getMonkeyDriver().sendPress(matcher.group(1)):
  652. return False
  653. return True
  654. #-----------------------------------------------------------------------------#
  655. #Alias
  656. class PressHardKey(PressKey):
  657. pass
  658. #-----------------------------------------------------------------------------#
  659. class PressKeyUp(PressKey):
  660. """
  661. releases a key
  662. Usage:
  663. Kw_PressKeyUp keyname
  664. """
  665. def __init__(self):
  666. super(PressKeyUp,self).__init__()
  667. pattern = re.compile("(?P<button>\w+)")
  668. self.attributePattern = pattern
  669. def execute(self):
  670. matcher = self.attributePattern.match(self.attributes)
  671. return self._target.getMonkeyDriver().sendKeyUp(matcher.group(1))
  672. #-----------------------------------------------------------------------------#
  673. class PressKeyDown(PressKey):
  674. """
  675. presses and holds a key
  676. Usage:
  677. Kw_PressKeyDown keyname
  678. """
  679. def __init__(self):
  680. super(PressKeyDown,self).__init__()
  681. pattern = re.compile("(?P<button>\w+)")
  682. self.attributePattern = pattern
  683. def execute(self):
  684. matcher = self.attributePattern.match(self.attributes)
  685. return self._target.getMonkeyDriver().sendKeyDown(matcher.group(1))
  686. #-----------------------------------------------------------------------------#
  687. class LongPressKey(PressKey):
  688. """
  689. """
  690. def __init__(self):
  691. super(LongPressKey,self).__init__()
  692. pattern = re.compile("(?P<button>\w+)(\s*,\s*(?P<time>\d+))?")
  693. self.attributePattern = pattern
  694. def execute(self):
  695. matcher = self.attributePattern.match(self.attributes)
  696. hold_time = 2
  697. if matcher.group("time"):
  698. hold_time = int(matcher.group("time"))
  699. if not self._target.getMonkeyDriver().sendKeyDown(matcher.group(1)):
  700. return False
  701. time.sleep(hold_time)
  702. return self._target.getMonkeyDriver().sendKeyUp(matcher.group(1))
  703. #-----------------------------------------------------------------------------#
  704. class CheckProperty(ObjectKeyword):
  705. """
  706. """
  707. def __init__(self):
  708. super(CheckProperty,self).__init__()
  709. pattern = re.compile('(?P<property>[^,]*)\s*,\s*\'(?P<value>.*)\'\s*,\s*(?P<component>' + self.componentPattern+ ')')
  710. self.attributePattern = pattern
  711. def execute(self):
  712. matcher = self.attributePattern.match(self.attributes)
  713. property = matcher.group("property")
  714. value = matcher.group("value")
  715. component = self.findComponentReference(matcher.group("component"))
  716. if component == None:
  717. return False
  718. if component.getProperties().has_key(property) and component.getProperties()[property] == value:
  719. return True
  720. return False
  721. #-----------------------------------------------------------------------------#
  722. class LaunchApp(ObjectKeyword):
  723. """
  724. LaunchApp 'package.Activity'
  725. """
  726. def __init__(self):
  727. super(LaunchApp,self).__init__()
  728. pattern = re.compile('\'((?P<class>(?P<package>[^:]*)(::(?P<activityOtherPackage>.+)|(?P<activitySamePackage>\.[^.]+)))|(?P<launchplace>(recent|appmenu):)?(?P<appname>[^\.]*))\'')
  729. #pattern = re.compile("'(?P<name>.*)'")
  730. self.attributePattern = pattern
  731. self.delay = 5
  732. def execute(self):
  733. matcher = self.attributePattern.match(self.attributes)
  734. config = ConfigParser.ConfigParser()
  735. #If the application has a specified launchup name, use that instead.
  736. try:
  737. config.read("appconfig.ini")
  738. launchname = config.get("Applications", matcher.group(1))
  739. if launchname:
  740. self.attributes = "'" + launchname + "'"
  741. except ConfigParser.Error:
  742. self.log("Application name not found from config, using the name directly")
  743. matcher = self.attributePattern.match(self.attributes)
  744. self.log('Launching activity: ' + matcher.group(0))
  745. #Launching application process directly
  746. if matcher.group("class"):
  747. try:
  748. #activity in the same package with the process
  749. activity = matcher.group('activitySamePackage')
  750. #Activity in a other package than the process
  751. if not activity:
  752. activity = matcher.group('activityOtherPackage')
  753. retcode = subprocess.call("adb -s " + self._target.name + " shell am start -n " + matcher.group('package') + "/" + activity, shell=True)
  754. except (OSError, ValueError):
  755. return False
  756. if retcode != 0:
  757. self.log("Launching application failed, check that android sdk tools are in the path variable")
  758. return False
  759. return True
  760. #Launching application through the GUI
  761. else:
  762. appname = matcher.group("appname")
  763. #Try launching from recent applications window
  764. if not matcher.group("launchplace") == "appmenu:":
  765. kw = LongPressKey()
  766. kw.initialize('home', self._target)
  767. if not kw.execute():
  768. return False
  769. time.sleep(1)
  770. kw = TapObject()
  771. kw.initialize("'" + appname +"'", self._target)
  772. if kw.execute():
  773. return True
  774. else:
  775. self._target.getMonkeyDriver().sendPress('back')
  776. #Try launching from the application menu
  777. if not matcher.group("launchplace") == "recent:":
  778. if not self._target.getMonkeyDriver().sendPress('home'):
  779. return False
  780. #TODO: Better solution?
  781. time.sleep(1)
  782. #TODO: Platform version dependant, Yuck!
  783. appsButton = 'id/all_apps'
  784. appsGrid = 'id/content'
  785. if self._target.getMonkeyDriver().getPlatformVersion() == "2.2":
  786. appsButton = 'id/all_apps_button'
  787. appsGrid = 'id/all_apps_2d_grid'
  788. kw = TapObject()
  789. kw.initialize(appsButton,self._target)
  790. if not kw.execute():
  791. return False
  792. kw = TapObject()
  793. kw.initialize(appsGrid + '::\'' + appname + '\'',self._target)
  794. if not kw.execute():
  795. return False
  796. return True
  797. return False
  798. #-----------------------------------------------------------------------------#
  799. class ObjectVisible(ObjectKeyword):
  800. def __init__(self):
  801. super(ObjectVisible,self).__init__()
  802. pattern = re.compile('(?P<component>' + self.componentPattern+ ')')
  803. self.attributePattern = pattern
  804. def execute(self):
  805. matcher = self.attributePattern.match(self.attributes)
  806. component = self.findComponentReference(matcher.group("component"))
  807. if component == None:
  808. return False
  809. if component.getProperties().has_key('getVisibility()') and component.getProperties()['getVisibility()'] == 'VISIBLE':
  810. return True
  811. return False
  812. #-----------------------------------------------------------------------------#
  813. class EmulatorKeyword(Keyword):
  814. def sendCommand(self, command):
  815. print command
  816. try:
  817. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  818. sock.connect( ('localhost', int(self._target.name[self._target.name.find("-") + 1:])) )
  819. data = sock.recv(4096)
  820. sock.send(command +"\n")
  821. data = sock.recv(4096)
  822. if not data.strip().endswith("OK"):
  823. return False
  824. sock.close()
  825. except socket.error,msg:
  826. self.log(msg)
  827. return False
  828. return True
  829. #-----------------------------------------------------------------------------#
  830. class SetNetworkDelay(EmulatorKeyword):
  831. def __init__(self):
  832. super(SetNetworkDelay,self).__init__()
  833. pattern = re.compile('gprs|edge|umts|none')
  834. self.attributePattern = pattern
  835. self.shouldLog = False
  836. def execute(self):
  837. matcher = self.attributePattern.match(self.attributes)
  838. return self.sendCommand("network delay " + matcher.group(0))
  839. #-----------------------------------------------------------------------------#
  840. class SetNetworkSpeed(EmulatorKeyword):
  841. def __init__(self):
  842. super(SetNetworkSpeed,self).__init__()
  843. pattern = re.compile('gsm|hscsd|gprs|edge|umts|hsdpa|full')
  844. self.attributePattern = pattern
  845. self.shouldLog = False
  846. def execute(self):
  847. matcher = self.attributePattern.match(self.attributes)
  848. return self.sendCommand("network speed " + matcher.group(0))
  849. #-----------------------------------------------------------------------------#
  850. class SendSMS(EmulatorKeyword):
  851. def __init__(self):
  852. super(SendSMS,self).__init__()
  853. pattern = re.compile("(\d+)\s*,\s*'(.*)'")
  854. self.attributePattern = pattern
  855. self.shouldLog = True
  856. def execute(self):
  857. matcher = self.attributePattern.match(self.attributes)
  858. return self.sendCommand("sms send " + matcher.group(1) + " " + matcher.group(2))
  859. #-----------------------------------------------------------------------------#